+package org.simantics.scl.ui.issues;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Collections;\r
+import java.util.concurrent.atomic.AtomicBoolean;\r
+\r
+import org.eclipse.jface.viewers.IStructuredContentProvider;\r
+import org.eclipse.jface.viewers.Viewer;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.simantics.scl.compiler.errors.CompilationError;\r
+import org.simantics.scl.compiler.errors.Failable;\r
+import org.simantics.scl.compiler.errors.Failure;\r
+import org.simantics.scl.compiler.module.Module;\r
+import org.simantics.scl.compiler.module.repository.ModuleRepository;\r
+import org.simantics.scl.compiler.module.repository.UpdateListener;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.procedure.TObjectProcedure;\r
+\r
+public class SCLIssuesContentProvider implements IStructuredContentProvider {\r
+\r
+ public static final int MAX_ISSUE_COUNT = 1000;\r
+ \r
+ Viewer viewer;\r
+ ModuleRepository repository;\r
+ boolean disposed = false;\r
+ AtomicBoolean refreshInProgress = new AtomicBoolean(false);\r
+ \r
+ THashMap<String, Failure> currentFailures = new THashMap<String, Failure>();\r
+ THashMap<String, UpdateListener> updateListeners = new THashMap<String, UpdateListener>(); \r
+ \r
+ @Override\r
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
+ this.viewer = viewer;\r
+ this.repository = (ModuleRepository)newInput;\r
+ if(newInput != null)\r
+ listenIssues();\r
+ }\r
+ \r
+ private UpdateListener getUpdateListener(String moduleName) {\r
+ UpdateListener listener = updateListeners.get(moduleName);\r
+ if(listener == null) {\r
+ listener = new UpdateListener() {\r
+ @Override\r
+ public void notifyAboutUpdate() {\r
+ if(!disposed)\r
+ listenModule(moduleName);\r
+ }\r
+ };\r
+ updateListeners.put(moduleName, listener);\r
+ }\r
+ return listener;\r
+ }\r
+ \r
+ private void listenModule(String moduleName) {\r
+ if(repository == null)\r
+ return;\r
+ Failable<Module> result = repository.getModule(moduleName, getUpdateListener(moduleName));\r
+ synchronized(currentFailures) {\r
+ if(result instanceof Failure) {\r
+ Failure failure = (Failure)result;\r
+ currentFailures.put(moduleName, failure);\r
+ }\r
+ else\r
+ if(currentFailures.remove(moduleName) == null)\r
+ return;\r
+ }\r
+ refresh();\r
+ }\r
+ \r
+ private void refresh() {\r
+ if(!refreshInProgress.compareAndSet(false, true))\r
+ return;\r
+ if(viewer == null)\r
+ return;\r
+ Control control = viewer.getControl();\r
+ if(control.isDisposed() || disposed)\r
+ return;\r
+ control.getDisplay().asyncExec(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ if(control.isDisposed() || disposed)\r
+ return;\r
+ refreshInProgress.set(false);\r
+ viewer.refresh();\r
+ }\r
+ });\r
+ }\r
+\r
+ private void listenIssues() {\r
+ new Thread() {\r
+ public void run() {\r
+ if(repository == null)\r
+ return;\r
+ repository.getSourceRepository().forAllModules(new TObjectProcedure<String>() {\r
+ @Override\r
+ public boolean execute(String moduleName) {\r
+ listenModule(moduleName);\r
+ return true;\r
+ }\r
+ });\r
+ }\r
+ }.start();\r
+ }\r
+\r
+ @Override\r
+ public void dispose() {\r
+ this.disposed = true;\r
+ }\r
+\r
+ @Override\r
+ public Object[] getElements(Object inputElement) {\r
+ ArrayList<SCLIssuesTableEntry> result = new ArrayList<SCLIssuesTableEntry>();\r
+ synchronized(currentFailures) {\r
+ String[] moduleNames = currentFailures.keySet().toArray(new String[currentFailures.size()]);\r
+ Arrays.sort(moduleNames);\r
+ for(String moduleName : moduleNames) {\r
+ Failure failure = currentFailures.get(moduleName);\r
+ for(CompilationError error : failure.errors)\r
+ result.add(new SCLIssuesTableEntry(moduleName, error));\r
+ if(result.size() >= MAX_ISSUE_COUNT)\r
+ break;\r
+ }\r
+ }\r
+ Collections.sort(result);\r
+ return result.toArray();\r
+ }\r
+\r
+}\r