--- /dev/null
+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();
+ }
+ }
+ }
+
+}