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