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 currentFailures = new THashMap<>(); THashMap 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 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() { @Override public boolean execute(String moduleName) { listenModule(moduleName, callback); return true; } }); } }.start(); } @Override public List getIssues() { ArrayList 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.scheduleOpenDefinition(moduleName, error.location); } }); } } } return result; } @Override public void dispose() { if (disposed) return; disposed = true; if(repository != null) { synchronized(updateListeners) { updateListeners.forEachEntry(new TObjectObjectProcedure() { @Override public boolean execute(String moduleName, UpdateListener listener) { listener.stopListening(); return true; } }); updateListeners.clear(); } } } }