SCL expressions to SCL Issues view 43/1143/11
authorjsimomaa <jani.simomaa@gmail.com>
Thu, 26 Oct 2017 08:51:22 +0000 (11:51 +0300)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Mon, 30 Oct 2017 10:10:50 +0000 (13:10 +0300)
refs #7575

Change-Id: Ic962c2e77a02dec079e6e0b3d5225a62ad734cee

19 files changed:
bundles/org.simantics.document.server/.project
bundles/org.simantics.document.server/build.properties
bundles/org.simantics.layer0/graph/Layer0Values.pgraph
bundles/org.simantics.modeling/META-INF/MANIFEST.MF
bundles/org.simantics.modeling/OSGI-INF/sclExpressionIssueProvider.xml [new file with mode: 0644]
bundles/org.simantics.modeling/build.properties
bundles/org.simantics.modeling/src/org/simantics/modeling/scl/issue/SCLExpressionIssueProvider.java [new file with mode: 0644]
bundles/org.simantics.scl.osgi/META-INF/MANIFEST.MF
bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/internal/Activator.java
bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/issues/SCLIssueFactoryProvider.java [new file with mode: 0644]
bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/issues/SCLIssueProviderFactory.java [new file with mode: 0644]
bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/issues/SCLIssuesTableEntry.java [moved from bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/issues/SCLIssuesTableEntry.java with 83% similarity]
bundles/org.simantics.scl.ui/META-INF/MANIFEST.MF
bundles/org.simantics.scl.ui/OSGI-INF/sclModuleIssueProvider.xml [new file with mode: 0644]
bundles/org.simantics.scl.ui/build.properties
bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/Activator.java
bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/issues/SCLIssuesContentProvider.java
bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/issues/SCLIssuesView.java
bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/issues/SCLModuleIssueProvider.java [new file with mode: 0644]

index ea6fdd9e83f371ddb705fdc1514a3a7874f880ab..5372c4d3fb256ea299679a6d7d80df7ba831df0e 100644 (file)
                        <arguments>
                        </arguments>
                </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ds.core.builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
        </buildSpec>
        <natures>
                <nature>org.eclipse.pde.PluginNature</nature>
index 132fd41430622e73a43da83b40bb4fce1f673d5a..1635b2b1f4001122f4aa145cc1ee1f9d0bb41310 100644 (file)
@@ -1,4 +1,3 @@
-source.. = src/
 output.. = bin/
 bin.includes = META-INF/,\
                .,\
@@ -6,4 +5,4 @@ bin.includes = META-INF/,\
                webdefault.xml,\
                scl/
 src.includes = scl/
-
+source.. = src/
index 18fd6d25c955eb8d9899d0a8dce42eadabd9fea6..c36cf60e56cffc6faf7d53cc1e7c10d2d0a3bd40 100644 (file)
@@ -16,7 +16,7 @@ L0.RequiresValueType <R L0.HasProperty : L0.FunctionalRelation
     <-- L0.Relation
     --> L0.String
 
-L0.HasDefaultLiteralType <R L0.DependsOn : L0.FunctionalRelation    
+L0.HasDefaultLiteralType <R L0.DependsOn : L0.FunctionalRelation
     <-- L0.Relation
     --> L0.Type
     
@@ -24,12 +24,15 @@ L0.HasSubliteralPredicate <R L0.DependsOn
 
 L0.RVIContext <T L0.Entity
 
-L0.SCLValue <T L0.Value
+L0.SCLValue <T L0.Value : L0.SCLValueType
     @L0.tag L0.Abstract
     >-- L0.SCLValue.expression --> L0.String <R L0.HasProperty : L0.TotalFunction
     >-- L0.SCLValue.environment --> L0.SCLValue.Environment <R L0.IsRelatedTo : L0.TotalFunction
     @L0.assert L0.ConvertsToValueWith L0.Functions.computeExpression
 
+L0.SCLValueType <T L0.Entity
+    >-- L0.SCLValueType.validator ==> "Variable -> <ReadGraph> String" <R L0.HasProperty
+
 L0.scl : L0.Template
     @template %subject %property %expression %valueType
         %subject
@@ -47,5 +50,3 @@ L0.Property <T L0.Value
     @L0.tag L0.Abstract
     @L0.tag L0.Deprecated
     @L0.assert L0.ConvertsToValueWith L0.Functions.composedPropertyValue
-    
-    
\ No newline at end of file
index bcdf142191365b0176b90d0d110c872d69c426e1..2c0a7f14530892d7ff49d1b3633b7cd35a8fc528 100644 (file)
@@ -64,3 +64,4 @@ Export-Package: org.simantics.modeling,
 Bundle-Vendor: VTT Technical Research Centre of Finland
 Bundle-ActivationPolicy: lazy
 Bundle-Activator: org.simantics.modeling.internal.Activator
+Service-Component: OSGI-INF/sclExpressionIssueProvider.xml
diff --git a/bundles/org.simantics.modeling/OSGI-INF/sclExpressionIssueProvider.xml b/bundles/org.simantics.modeling/OSGI-INF/sclExpressionIssueProvider.xml
new file mode 100644 (file)
index 0000000..735c794
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.simantics.modeling.sclExpressionIssueProvider">
+   <implementation class="org.simantics.modeling.scl.issue.SCLExpressionIssueProvider$SCLExpressionIssueProviderFactory"/>
+   <service>
+      <provide interface="org.simantics.scl.osgi.issues.SCLIssueProviderFactory"/>
+   </service>
+</scr:component>
index e69c44b34f09698553528432d40a03605f7cb6d8..0937bf5e12662fb6f5e57889e46b4f1de45e2ae1 100644 (file)
@@ -15,5 +15,6 @@ bin.includes = META-INF/,\
                .,\
                adapters.xml,\
                plugin.xml,\
-               scl/
+               scl/,\
+               OSGI-INF/
 src.includes = scl/
diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/scl/issue/SCLExpressionIssueProvider.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/scl/issue/SCLExpressionIssueProvider.java
new file mode 100644 (file)
index 0000000..bbbd6b0
--- /dev/null
@@ -0,0 +1,165 @@
+package org.simantics.modeling.scl.issue;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.simantics.Simantics;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.procedure.adapter.SyncListenerAdapter;
+import org.simantics.db.common.request.UniqueRead;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.util.Layer0Utils;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.layer0.variable.Variables;
+import org.simantics.layer0.Layer0;
+import org.simantics.modeling.ModelingUtils;
+import org.simantics.scl.compiler.errors.CompilationError;
+import org.simantics.scl.compiler.errors.Locations;
+import org.simantics.scl.osgi.issues.SCLIssueProviderFactory;
+import org.simantics.scl.osgi.issues.SCLIssueProviderFactory.SCLIssueProvider;
+import org.simantics.scl.osgi.issues.SCLIssuesTableEntry;
+import org.simantics.scl.runtime.SCLContext;
+import org.simantics.scl.runtime.function.Function1;
+import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.ui.workbench.action.DefaultActions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SCLExpressionIssueProvider implements SCLIssueProvider {
+
+    public static class SCLExpressionIssueProviderFactory implements SCLIssueProviderFactory {
+
+        @Override
+        public SCLIssueProvider getSCLIssueProvider() {
+            return new SCLExpressionIssueProvider();
+        }
+
+    }
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(SCLExpressionIssueProvider.class);
+    private List<SCLIssuesTableEntry> currentIssues = new ArrayList<>();
+    private boolean disposed = false;
+
+    SCLExpressionIssueProvider() {
+    }
+
+    @Override
+    public void listenIssues(Runnable callback) {
+        Simantics.getSession().asyncRequest(new UniqueRead<List<SCLIssuesTableEntry>>() {
+
+            @Override
+            public List<SCLIssuesTableEntry> perform(ReadGraph graph) throws DatabaseException {
+                Layer0 L0 = Layer0.getInstance(graph);
+                Set<Resource> indexRoots = new TreeSet<Resource>();
+                for(Resource ontology : Layer0Utils.listOntologies(graph)) {
+                    if (graph.isInstanceOf(ontology, L0.SharedOntology)) {
+                        indexRoots.add(ontology);
+                    }
+                }
+
+                for(Resource child : graph.getObjects(Simantics.getProjectResource(), L0.ConsistsOf)) {
+                    if (graph.isInstanceOf(child, L0.IndexRoot)) {
+                        indexRoots.add(child);
+                    }
+                }
+
+                StructuralResource2 STR = StructuralResource2.getInstance(graph);
+
+                List<SCLIssuesTableEntry> results = new ArrayList<>();
+
+                for (Resource ontology : indexRoots) {
+                    List<Resource> components = ModelingUtils.searchByTypeShallow(graph, ontology, STR.Component);
+                    for (Resource component : components) {
+
+                        for (Resource predicate : graph.getPredicates(component)) {
+                            if (graph.isSubrelationOf(predicate, L0.HasProperty)) {
+                                for (Resource object : graph.getObjects(component, predicate)) {
+                                    if (graph.isInstanceOf(object, L0.SCLValue)) {
+                                        Resource type = graph.getPossibleType(object, L0.SCLValue);
+                                        Variable typeVariable = Variables.getVariable(graph, type);
+
+                                        Function1<Variable, String> func = typeVariable.getPossiblePropertyValue(graph, "validator");
+                                        if (func == null) {
+                                            // No validator available
+                                            if (LOGGER.isTraceEnabled())
+                                                LOGGER.trace("No validator available for " + typeVariable.getURI(graph));
+                                            continue;
+                                        }
+
+                                        Variable componentVariable = Variables.getVariable(graph, component);
+                                        Variable propertyVariable = componentVariable.getProperty(graph, predicate);
+
+                                        SCLContext sclContext = SCLContext.getCurrent();
+                                        Object oldGraph = sclContext.get("graph");
+                                        try {
+                                            sclContext.put("graph", graph);
+                                            String validatorValue = func.apply(propertyVariable);
+                                            if (validatorValue != null && !validatorValue.isEmpty()) {
+                                                results.add(new SCLIssuesTableEntry(propertyVariable.getURI(graph), new CompilationError(Locations.NO_LOCATION, validatorValue.replace("\n", " "))) {
+                                                    @Override
+                                                    public void openLocation() {
+                                                        openResource(Display.getCurrent().getActiveShell(), component);
+                                                    }
+                                                });
+                                            }
+                                        } catch (Throwable t) {
+                                            LOGGER.error("Failed to invoke type validator function " + func, t);
+                                        } finally {
+                                            sclContext.put("graph", oldGraph);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                return results;
+            }
+        }, new SyncListenerAdapter<List<SCLIssuesTableEntry>>() {
+
+            @Override
+            public void execute(ReadGraph graph, List<SCLIssuesTableEntry> result) {
+                synchronized (currentIssues) {
+                    currentIssues.clear();
+                    currentIssues.addAll(result);
+                }
+                if (callback != null)
+                    callback.run();
+            }
+
+            @Override
+            public void exception(ReadGraph graph, Throwable t) {
+                LOGGER.error("Could not get SCL issues", t);
+            }
+
+            @Override
+            public boolean isDisposed() {
+                return disposed;
+            }
+        });
+    }
+
+    @Override
+    public List<SCLIssuesTableEntry> getIssues() {
+        synchronized (currentIssues) {
+            List<SCLIssuesTableEntry> results = new ArrayList<>(currentIssues);
+            return results;
+        }
+    }
+
+    @Override
+    public void dispose() {
+        disposed = true;
+    }
+
+    private static void openResource(Shell shell, Resource resource) {
+        DefaultActions.performDefaultAction(shell, new StructuredSelection(resource));
+    }
+
+}
index a1033a4a4b710589241eda12510c2403fd6ea1a6..971c55338eab1ea6cbe1d1933bb712ab96bec5ae 100644 (file)
@@ -6,11 +6,13 @@ Bundle-Version: 1.0.4.qualifier
 Bundle-Activator: org.simantics.scl.osgi.internal.Activator
 Require-Bundle: org.eclipse.core.runtime,
  gnu.trove3;bundle-version="3.0.0",
- org.simantics.scl.compiler;bundle-version="0.6.0";visibility:=reexport
+ org.simantics.scl.compiler;bundle-version="0.6.0";visibility:=reexport,
+ org.slf4j.api
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Export-Package: org.simantics.scl.osgi,
- org.simantics.scl.osgi.internal
+ org.simantics.scl.osgi.internal,
+ org.simantics.scl.osgi.issues
 Service-Component: OSGI-INF/org.simantics.scl.osgi.internal.BundleModuleSourceRepository.xml,
  OSGI-INF/org.simantics.scl.osgi.internal.FileSystemModuleSourceRepository.xml,
  OSGI-INF/org.simantics.scl.osgi.internal.BundleTestScriptRepository.xml
index d7a9e9e7f771f2802a15ad0b8d13beeae9868cbf..b629e08d96817dc7d2935259ec8354af7c534edf 100644 (file)
@@ -13,6 +13,8 @@ import org.simantics.scl.osgi.SCLOsgi;
 
 public class Activator implements BundleActivator {
 
+    public static final String PLUGIN_ID = "org.simantics.scl.osgi";
+
     private static BundleContext context;
 
     public static BundleContext getContext() {
diff --git a/bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/issues/SCLIssueFactoryProvider.java b/bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/issues/SCLIssueFactoryProvider.java
new file mode 100644 (file)
index 0000000..c06dbe1
--- /dev/null
@@ -0,0 +1,35 @@
+package org.simantics.scl.osgi.issues;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.simantics.scl.osgi.internal.Activator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class SCLIssueFactoryProvider {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(SCLIssueFactoryProvider.class);
+
+    public static List<SCLIssueProviderFactory> getSCLIssueProviderFactories() {
+        ServiceReference<?>[] serviceReferences = new ServiceReference<?>[0];
+        try {
+            serviceReferences = Activator.getContext().getAllServiceReferences(SCLIssueProviderFactory.class.getName(), null);
+        } catch (InvalidSyntaxException e) {
+            LOGGER.error("Could not get service references for " + SCLIssueProviderFactory.class.getName(), e);
+        }
+        if (serviceReferences == null || serviceReferences.length == 0)
+            return Collections.emptyList();
+
+        List<SCLIssueProviderFactory> services = new ArrayList<>(serviceReferences.length);
+        for (ServiceReference<?> reference : serviceReferences) {
+            SCLIssueProviderFactory service = (SCLIssueProviderFactory) Activator.getContext().getService(reference);
+            services.add(service);
+        }
+        return services;
+    }
+
+}
diff --git a/bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/issues/SCLIssueProviderFactory.java b/bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/issues/SCLIssueProviderFactory.java
new file mode 100644 (file)
index 0000000..293e8a1
--- /dev/null
@@ -0,0 +1,18 @@
+package org.simantics.scl.osgi.issues;
+
+import java.util.List;
+
+public interface SCLIssueProviderFactory {
+    
+    SCLIssueProvider getSCLIssueProvider();
+    
+    public static interface SCLIssueProvider {
+        
+        void listenIssues(Runnable callback);
+
+        List<SCLIssuesTableEntry> getIssues();
+
+        void dispose();
+    }
+
+}
similarity index 83%
rename from bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/issues/SCLIssuesTableEntry.java
rename to bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/issues/SCLIssuesTableEntry.java
index 2b49dd125b993c01afed536a8dff510ac73af6ce..c9c21e8b3f516a561cba402df184745508ba171a 100644 (file)
@@ -1,9 +1,9 @@
-package org.simantics.scl.ui.issues;
+package org.simantics.scl.osgi.issues;
 
 import org.simantics.scl.compiler.errors.CompilationError;
 import org.simantics.scl.compiler.errors.Locations;
 
-public class SCLIssuesTableEntry implements Comparable<SCLIssuesTableEntry> {
+public abstract class SCLIssuesTableEntry implements Comparable<SCLIssuesTableEntry> {
     public final String moduleName;
     public final CompilationError error;
 
@@ -12,6 +12,8 @@ public class SCLIssuesTableEntry implements Comparable<SCLIssuesTableEntry> {
         this.error = error;
     }
 
+    public abstract void openLocation();
+
     @Override
     public int compareTo(SCLIssuesTableEntry o) {
         if(this == o)
index 061dad8522a0f7e7758588ab8fd3192238b4a835..60603619abb95d4ea3a20d3a7ff0182f0ddea244 100644 (file)
@@ -14,10 +14,12 @@ Require-Bundle: org.eclipse.ui.editors;bundle-version="3.6.0",
  org.simantics.scl.osgi;bundle-version="1.0.0",
  org.simantics.scl.compiler;bundle-version="0.6.0",
  org.junit;bundle-version="4.12.0";resolution:=optional,
- com.ibm.icu
+ com.ibm.icu,
+ org.slf4j.api
 Export-Package: org.simantics.scl.ui.console,
  org.simantics.scl.ui.editor,
  org.simantics.scl.ui.editor2,
  org.simantics.scl.ui.imports
 Bundle-Activator: org.simantics.scl.ui.Activator
 Bundle-ActivationPolicy: lazy
+Service-Component: OSGI-INF/sclModuleIssueProvider.xml
diff --git a/bundles/org.simantics.scl.ui/OSGI-INF/sclModuleIssueProvider.xml b/bundles/org.simantics.scl.ui/OSGI-INF/sclModuleIssueProvider.xml
new file mode 100644 (file)
index 0000000..81cd28c
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.simantics.scl.ui.sclModuleIssueProvider">
+   <implementation class="org.simantics.scl.ui.issues.SCLModuleIssueProvider$SCLModuleIssueProviderFactory"/>
+   <service>
+      <provide interface="org.simantics.scl.osgi.issues.SCLIssueProviderFactory"/>
+   </service>
+</scr:component>
index 6c480f39f1bf02b9d3cd69ecf5d747da230d11bf..4c8a5cea8e5ef7dbff19c95d24db8ebd62c9cf40 100644 (file)
@@ -1,6 +1,7 @@
-source.. = src/
 output.. = bin/
 bin.includes = META-INF/,\
                .,\
                plugin.xml,\
-               icons/
+               icons/,\
+               OSGI-INF/sclModuleIssueProvider.xml
+source.. = src/
index 768682fa3ef8a056f0b1fc73e7765a1e1390d034..f68f2876e83087c3a88dc30a5a456a7028909694 100644 (file)
@@ -12,6 +12,8 @@ import org.simantics.scl.ui.imports.internal.ManualImportModulesAction;
 
 public class Activator extends AbstractUIPlugin {
 
+    public static final String PLUGIN_ID = "org.simantics.scl.ui";
+
     private static Activator INSTANCE;
     
     @Override
index 4772ad5ba7996b89baa875c4cf24db9e70e940e4..4e386e685b3c168bfdec4c47189a9fae8bea100f 100644 (file)
@@ -1,90 +1,40 @@
 package org.simantics.scl.ui.issues;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
 
 import org.eclipse.jface.viewers.IStructuredContentProvider;
 import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.swt.widgets.Control;
-import org.simantics.scl.compiler.errors.CompilationError;
-import org.simantics.scl.compiler.errors.DoesNotExist;
-import org.simantics.scl.compiler.errors.Failable;
-import org.simantics.scl.compiler.errors.Failure;
-import org.simantics.scl.compiler.module.Module;
-import org.simantics.scl.compiler.module.repository.ModuleRepository;
-import org.simantics.scl.compiler.module.repository.UpdateListener;
-
-import gnu.trove.map.hash.THashMap;
-import gnu.trove.procedure.TObjectObjectProcedure;
-import gnu.trove.procedure.TObjectProcedure;
+import org.simantics.scl.osgi.issues.SCLIssueFactoryProvider;
+import org.simantics.scl.osgi.issues.SCLIssueProviderFactory.SCLIssueProvider;
+import org.simantics.scl.osgi.issues.SCLIssuesTableEntry;
 
 public class SCLIssuesContentProvider implements IStructuredContentProvider {
 
     public static final int MAX_ISSUE_COUNT = 1000;
-    
-    Viewer viewer;
-    ModuleRepository repository;
+
+    private Viewer viewer;
     boolean disposed = false;
-    AtomicBoolean refreshInProgress = new AtomicBoolean(false);
-    
-    THashMap<String, CompilationError[]> currentFailures = new THashMap<String, CompilationError[]>();
-    THashMap<String, UpdateListener> updateListeners = new THashMap<String, UpdateListener>(); 
-    
+    private AtomicBoolean refreshInProgress = new AtomicBoolean(false);
+    private List<SCLIssueProvider> issueProviders = new ArrayList<>();
+
     @Override
     public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
         this.viewer = viewer;
-        this.repository = (ModuleRepository)newInput;
-        if(newInput != null)
-            listenIssues();
-    }
-    
-    private UpdateListener getUpdateListener(String moduleName) {
-        UpdateListener listener;
-        synchronized(updateListeners) {
-            listener = updateListeners.get(moduleName);
-            if(listener == null) {
-                listener = new UpdateListener() {
-                    @Override
-                    public void notifyAboutUpdate() {
-                        if(!disposed)
-                            listenModule(moduleName);
-                    }
-                };
-                updateListeners.put(moduleName, listener);
-            }
+        if (!issueProviders.isEmpty()) {
+            issueProviders.forEach(p -> p.dispose());
+            issueProviders.clear();
         }
-        return listener;
-    }
-    
-    private void listenModule(String moduleName) {
-        if(repository == null)
-            return;
-        Failable<Module> result = repository.getModule(moduleName, getUpdateListener(moduleName));
-        synchronized(currentFailures) {
-            if(result instanceof Failure) {
-                Failure failure = (Failure)result;
-                currentFailures.put(moduleName, failure.errors);
-            }
-            else if(result == DoesNotExist.INSTANCE) {
-                if(currentFailures.remove(moduleName) == null)
-                    return;
-            }
-            else {
-                CompilationError[] warnings = result.getResult().getWarnings();
-                if(warnings.length == 0) {
-                    if(currentFailures.remove(moduleName) == null)
-                        return;
-                }
-                else {
-                    currentFailures.put(moduleName, warnings);
-                }
-            }
+        if(newInput != null) {
+            issueProviders = SCLIssueFactoryProvider.getSCLIssueProviderFactories().stream().map(f -> f.getSCLIssueProvider()).collect(Collectors.toList());
+            issueProviders.forEach(p -> p.listenIssues(() -> refresh()));
         }
-        refresh();
     }
-    
+
     private void refresh() {
         if(!refreshInProgress.compareAndSet(false, true))
             return;
@@ -104,54 +54,18 @@ public class SCLIssuesContentProvider implements IStructuredContentProvider {
         });
     }
 
-    private void listenIssues() {
-        new Thread() {
-            public void run() {
-                if(repository == null)
-                    return;
-                repository.getSourceRepository().forAllModules(new TObjectProcedure<String>() {
-                    @Override
-                    public boolean execute(String moduleName) {
-                        listenModule(moduleName);
-                        return true;
-                    }
-                });
-            }
-        }.start();
-    }
-
-    @Override
     public void dispose() {
         if(this.disposed)
             return;
+        issueProviders.forEach(p -> p.dispose());
+        issueProviders.clear();
         this.disposed = true;
-        if(repository != null)
-            synchronized(updateListeners) {
-                updateListeners.forEachEntry(new TObjectObjectProcedure<String, UpdateListener>() {
-                    @Override
-                    public boolean execute(String moduleName, UpdateListener listener) {
-                        listener.stopListening();
-                        return true;
-                    }
-                });
-                updateListeners.clear();
-            }
     }
 
     @Override
     public Object[] getElements(Object inputElement) {
-        ArrayList<SCLIssuesTableEntry> result = new ArrayList<SCLIssuesTableEntry>();
-        synchronized(currentFailures) {
-            String[] moduleNames = currentFailures.keySet().toArray(new String[currentFailures.size()]);
-            Arrays.sort(moduleNames);
-            for(String moduleName : moduleNames) {
-                CompilationError[] errors = currentFailures.get(moduleName);
-                for(CompilationError error : errors)
-                    result.add(new SCLIssuesTableEntry(moduleName, error));
-                if(result.size() >= MAX_ISSUE_COUNT)
-                    break;
-            }
-        }
+        ArrayList<SCLIssuesTableEntry> result = new ArrayList<>();
+        issueProviders.forEach(p -> result.addAll(p.getIssues()));
         Collections.sort(result);
         return result.toArray();
     }
index 3e0cc3120bd8c163c62158b4e5f0661ef8e0d74f..10e2288e1b3d81b0a8cd639444b28e6b270bfa2b 100644 (file)
@@ -26,8 +26,8 @@ import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.part.ViewPart;
 import org.simantics.scl.compiler.errors.ErrorSeverity;
 import org.simantics.scl.osgi.SCLOsgi;
+import org.simantics.scl.osgi.issues.SCLIssuesTableEntry;
 import org.simantics.scl.ui.Activator;
-import org.simantics.scl.ui.editor2.OpenSCLDefinition;
 
 public class SCLIssuesView extends ViewPart {
 
@@ -55,7 +55,8 @@ public class SCLIssuesView extends ViewPart {
         IAction action = new Action("Refresh") {
             @Override
             public void run() {
-                SCLOsgi.MODULE_REPOSITORY.getSourceRepository().checkUpdates();
+                tableViewer.setInput(SCLOsgi.MODULE_REPOSITORY);
+//                issuesContentProvider.refresh()
             }
         };
         action.setImageDescriptor(imageRegistry.getDescriptor("arrow_refresh"));
@@ -144,7 +145,7 @@ public class SCLIssuesView extends ViewPart {
             public void doubleClick(DoubleClickEvent event) {
                 IStructuredSelection selection = (IStructuredSelection)event.getSelection();
                 SCLIssuesTableEntry entry = (SCLIssuesTableEntry)selection.getFirstElement();
-                OpenSCLDefinition.openDefinition(entry.moduleName, entry.error.location);
+                entry.openLocation();
             }
         });
     }
diff --git a/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/issues/SCLModuleIssueProvider.java b/bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/issues/SCLModuleIssueProvider.java
new file mode 100644 (file)
index 0000000..20a89d4
--- /dev/null
@@ -0,0 +1,147 @@
+package org.simantics.scl.ui.issues;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.simantics.scl.compiler.errors.CompilationError;
+import org.simantics.scl.compiler.errors.DoesNotExist;
+import org.simantics.scl.compiler.errors.Failable;
+import org.simantics.scl.compiler.errors.Failure;
+import org.simantics.scl.compiler.module.Module;
+import org.simantics.scl.compiler.module.repository.ModuleRepository;
+import org.simantics.scl.compiler.module.repository.UpdateListener;
+import org.simantics.scl.osgi.SCLOsgi;
+import org.simantics.scl.osgi.issues.SCLIssueProviderFactory;
+import org.simantics.scl.osgi.issues.SCLIssueProviderFactory.SCLIssueProvider;
+import org.simantics.scl.osgi.issues.SCLIssuesTableEntry;
+import org.simantics.scl.ui.editor2.OpenSCLDefinition;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.procedure.TObjectObjectProcedure;
+import gnu.trove.procedure.TObjectProcedure;
+
+public class SCLModuleIssueProvider implements SCLIssueProvider {
+
+    public static class SCLModuleIssueProviderFactory implements SCLIssueProviderFactory {
+
+        @Override
+        public SCLIssueProvider getSCLIssueProvider() {
+            return new SCLModuleIssueProvider();
+        }
+        
+    }
+    
+    ModuleRepository repository = SCLOsgi.MODULE_REPOSITORY;
+
+    THashMap<String, CompilationError[]> currentFailures = new THashMap<>();
+    THashMap<String, UpdateListener> updateListeners = new THashMap<>();
+
+    private boolean disposed;
+    
+    SCLModuleIssueProvider() {
+    }
+
+    private UpdateListener getUpdateListener(String moduleName, Runnable callback) {
+        UpdateListener listener;
+        synchronized(updateListeners) {
+            listener = updateListeners.get(moduleName);
+            if(listener == null) {
+                listener = new UpdateListener() {
+                    @Override
+                    public void notifyAboutUpdate() {
+                        if(!disposed)
+                            listenModule(moduleName, callback);
+                    }
+                };
+                updateListeners.put(moduleName, listener);
+            }
+        }
+        return listener;
+    }
+
+    private void listenModule(String moduleName, Runnable callback) {
+        if(repository == null)
+            return;
+        Failable<Module> result = repository.getModule(moduleName, getUpdateListener(moduleName, callback));
+        synchronized(currentFailures) {
+            if(result instanceof Failure) {
+                Failure failure = (Failure)result;
+                currentFailures.put(moduleName, failure.errors);
+            }
+            else if(result == DoesNotExist.INSTANCE) {
+                if(currentFailures.remove(moduleName) == null)
+                    return;
+            }
+            else {
+                CompilationError[] warnings = result.getResult().getWarnings();
+                if(warnings.length == 0) {
+                    if(currentFailures.remove(moduleName) == null)
+                        return;
+                }
+                else {
+                    currentFailures.put(moduleName, warnings);
+                }
+            }
+        }
+        if (callback != null)
+            callback.run();
+    }
+
+    public void listenIssues(Runnable callback) {
+        new Thread() {
+            public void run() {
+                if(repository == null)
+                    return;
+                repository.getSourceRepository().forAllModules(new TObjectProcedure<String>() {
+                    @Override
+                    public boolean execute(String moduleName) {
+                        listenModule(moduleName, callback);
+                        return true;
+                    }
+                });
+            }
+        }.start();
+    }
+
+    @Override
+    public List<SCLIssuesTableEntry> getIssues() {
+        ArrayList<SCLIssuesTableEntry> result = new ArrayList<>();
+        synchronized(currentFailures) {
+            String[] moduleNames = currentFailures.keySet().toArray(new String[currentFailures.size()]);
+            Arrays.sort(moduleNames);
+            for(String moduleName : moduleNames) {
+                CompilationError[] errors = currentFailures.get(moduleName);
+                for(CompilationError error : errors) {
+                    result.add(new SCLIssuesTableEntry(moduleName, error) {
+                        @Override
+                        public void openLocation() {
+                            OpenSCLDefinition.openDefinition(moduleName, error.location);
+                        }
+                    });
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public void dispose() {
+        if (disposed)
+            return;
+        disposed = true;
+        if(repository != null) {
+            synchronized(updateListeners) {
+                updateListeners.forEachEntry(new TObjectObjectProcedure<String, UpdateListener>() {
+                    @Override
+                    public boolean execute(String moduleName, UpdateListener listener) {
+                        listener.stopListening();
+                        return true;
+                    }
+                });
+                updateListeners.clear();
+            }
+        }
+    }
+
+}