org.simantics.layer0;bundle-version="1.0.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
+Export-Package: org.simantics.interop.issues
name="Comparator"\r
restorable="true">\r
</view>\r
+ <view\r
+ class="org.simantics.interop.ui.IssuesViewPart"\r
+ id="org.simantics.interop.issues"\r
+ name="Issues"\r
+ restorable="true">\r
+ </view>\r
</extension>\r
<extension\r
point="org.eclipse.ui.importWizards">\r
--- /dev/null
+package org.simantics.interop.issues;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.eclipse.swt.widgets.Display;\r
+\r
+public abstract class AbstractIssue implements Issue{\r
+ \r
+ private String description;\r
+ private List<IssueListener> listeners = new ArrayList<IssueListener>();\r
+ \r
+ @Override\r
+ public String getDescription() {\r
+ return description;\r
+ }\r
+ \r
+ public void setDescription(String description) {\r
+ this.description = description;\r
+ fireUpdated();\r
+ }\r
+ \r
+ protected void fireUpdated() {\r
+ Display.getDefault().asyncExec(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ for (IssueListener l : listeners) {\r
+ l.updated(AbstractIssue.this);\r
+ }\r
+ }\r
+ });\r
+ }\r
+ \r
+ protected void fireDisposed() {\r
+ Display.getDefault().asyncExec(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ List<IssueListener> list = new ArrayList<IssueListener>();\r
+ list.addAll(listeners);\r
+ for (IssueListener l : list) {\r
+ l.disposed(AbstractIssue.this);\r
+ }\r
+ }\r
+ });\r
+ }\r
+ \r
+ @Override\r
+ public void addListener(IssueListener listener) {\r
+ listeners.add(listener);\r
+ }\r
+ \r
+ @Override\r
+ public void removeListener(IssueListener listener) {\r
+ listeners.remove(listener);\r
+ }\r
+ \r
+ @Override\r
+ public void dispose() {\r
+ fireDisposed();\r
+ }\r
+\r
+}\r
--- /dev/null
+package org.simantics.interop.issues;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.request.Read;\r
+\r
+/**\r
+ * AndRead can be used to combine multiple requests into single one. If all reads return true or null, this returns true.\r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class AndRead implements Read<Boolean>{\r
+\r
+ private Read<Boolean> reads[];\r
+ \r
+ public AndRead(Read<Boolean>... reads) {\r
+ this.reads = reads;\r
+ }\r
+ \r
+ @Override\r
+ public Boolean perform(ReadGraph graph) throws DatabaseException {\r
+ Boolean b = null;\r
+ for (Read<Boolean> r : reads) {\r
+ b = r.perform(graph);\r
+ if(b != null && !b)\r
+ return false;\r
+ }\r
+ return true;\r
+ }\r
+}\r
--- /dev/null
+package org.simantics.interop.issues;\r
+\r
+/**\r
+ * Basic, static issue.\r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class BasicIssue extends AbstractIssue {\r
+\r
+ \r
+ public BasicIssue(String description) {\r
+ setDescription(description);\r
+ }\r
+ \r
+ @Override\r
+ public void showInEditor() {\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public boolean supportsEditor() {\r
+ return false;\r
+ }\r
+ \r
+ \r
+}\r
--- /dev/null
+package org.simantics.interop.issues;\r
+\r
+import org.simantics.db.AsyncReadGraph;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.procedure.AsyncListener;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.utils.ui.ErrorLogger;\r
+\r
+/**\r
+ * An issue whose state can be updated with an query\r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class GraphIssue extends AbstractIssue {\r
+ \r
+ private boolean disposed = false;\r
+ \r
+ /**\r
+ * Creates an new Graph Issue\r
+ * @param g access to graph\r
+ * @param request Request that returns true if issue is still valid. If the request returns false, the issue is disposed.\r
+ * @param description\r
+ */\r
+ public GraphIssue(ReadGraph g, Read<Boolean> request, String description) {\r
+ setDescription(description);\r
+ IssueReporter.getInstance().addIssue(this);\r
+ setRequest(g, request);\r
+ }\r
+ \r
+ public GraphIssue(String description) {\r
+ setDescription(description);\r
+ IssueReporter.getInstance().addIssue(this);\r
+ }\r
+ \r
+ public void setRequest(ReadGraph g, Read<Boolean> request) {\r
+ g.asyncRequest(request,new AsyncListener<Boolean>() {\r
+ @Override\r
+ public void execute(AsyncReadGraph graph, Boolean result) {\r
+ if (result == null)\r
+ return;\r
+ \r
+ if (!result) {\r
+ dispose();\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void exception(AsyncReadGraph graph, Throwable throwable) {\r
+ ErrorLogger.defaultLogError("Error in GraphIssue handling, disposing issue \"" + getDescription()+"\"", throwable);\r
+ dispose(); \r
+ }\r
+ \r
+ @Override\r
+ public boolean isDisposed() {\r
+ return disposed;\r
+ }\r
+ });\r
+ }\r
+ \r
+ @Override\r
+ public void showInEditor() {\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public boolean supportsEditor() {\r
+ return false;\r
+ }\r
+ \r
+ @Override\r
+ public void dispose() {\r
+ this.disposed = true;\r
+ super.dispose();\r
+ }\r
+\r
+}\r
--- /dev/null
+package org.simantics.interop.issues;\r
+\r
+/**\r
+ * Interface for an issue\r
+ * \r
+ * TODO: grouping, severity?\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public interface Issue {\r
+ \r
+ /**\r
+ * Prints description\r
+ * @return\r
+ */\r
+ public String getDescription();\r
+ \r
+ /**\r
+ * Returns true if this issue can be highlighted in an editor\r
+ * @return\r
+ */\r
+ public boolean supportsEditor();\r
+ \r
+ /**\r
+ * Opens and highlights the reason of the issue in an editor\r
+ */\r
+ public void showInEditor();\r
+ \r
+ /**\r
+ * Disposes the issue.\r
+ */\r
+ public void dispose();\r
+ \r
+ public void addListener(IssueListener listenr);\r
+ public void removeListener(IssueListener listener);\r
+\r
+}\r
--- /dev/null
+package org.simantics.interop.issues;\r
+\r
+/**\r
+ * Interface for listening changes in issues.\r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public interface IssueListener {\r
+ \r
+ /**\r
+ * Issues is updated\r
+ * @param issue\r
+ */\r
+ public void updated(Issue issue);\r
+ \r
+ /**\r
+ * Issue is disposed (not valid anymore);\r
+ * @param issue\r
+ */\r
+ public void disposed(Issue issue);\r
+\r
+}\r
--- /dev/null
+package org.simantics.interop.issues;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.eclipse.swt.widgets.Display;\r
+\r
+/**\r
+ * IssueReporter is singleton class that handles collecting issues.\r
+ * \r
+ * TODO: how to store issues when the application is closed? Memento-based?\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class IssueReporter implements IssueListener{\r
+ \r
+ private static IssueReporter INSTANCE;\r
+ \r
+ private List<Issue> issues = new ArrayList<Issue>();\r
+ private List<IssueReporterListener> listeners = new ArrayList<IssueReporterListener>();\r
+ \r
+ \r
+ private IssueReporter() {\r
+ \r
+ }\r
+ \r
+ public static IssueReporter getInstance() {\r
+ if (INSTANCE == null)\r
+ INSTANCE = new IssueReporter();\r
+ return INSTANCE;\r
+ }\r
+ \r
+ /**\r
+ * Retuns list of issues.\r
+ * @return\r
+ */\r
+ public List<Issue> getIssues() {\r
+ return Collections.unmodifiableList(issues);\r
+ }\r
+ \r
+ public void addIssue(Issue issue) {\r
+ issues.add(issue);\r
+ issue.addListener(this);\r
+ fireAdded(issue);\r
+ }\r
+ \r
+ public void removeIssue(Issue issue) {\r
+ issue.removeListener(this);\r
+ issues.remove(issue);\r
+ fireRemoved(issue);\r
+ }\r
+ \r
+ @Override\r
+ public void updated(Issue issue) {\r
+ fireUpdated(issue);\r
+ }\r
+ \r
+ @Override\r
+ public void disposed(Issue issue) {\r
+ issue.removeListener(this);\r
+ issues.remove(issue);\r
+ fireRemoved(issue);\r
+ }\r
+ \r
+ \r
+ public void addListener(IssueReporterListener listener) {\r
+ listeners.add(listener);\r
+ }\r
+ \r
+ public void removeListener(IssueReporterListener listener) {\r
+ listeners.remove(listener);\r
+ }\r
+ \r
+ protected void fireAdded(final Issue issue) {\r
+ Display.getDefault().asyncExec(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ for (IssueReporterListener l : listeners)\r
+ l.added(issue);\r
+ }\r
+ });\r
+ }\r
+ \r
+ protected void fireRemoved(final Issue issue) {\r
+ Display.getDefault().asyncExec(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ for (IssueReporterListener l : listeners)\r
+ l.removed(issue);\r
+ }\r
+ });\r
+ }\r
+ \r
+ protected void fireUpdated(final Issue issue) {\r
+ Display.getDefault().asyncExec(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ for (IssueReporterListener l : listeners)\r
+ l.updated(issue);\r
+ }\r
+ });\r
+ }\r
+ \r
+\r
+}\r
--- /dev/null
+package org.simantics.interop.issues;\r
+\r
+public interface IssueReporterListener {\r
+ \r
+ public void added(Issue issue);\r
+ public void removed(Issue issue);\r
+ public void updated(Issue issue);\r
+\r
+}\r
--- /dev/null
+package org.simantics.interop.ui;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.eclipse.jface.viewers.ILabelProviderListener;\r
+import org.eclipse.jface.viewers.IStructuredContentProvider;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.jface.viewers.ITableLabelProvider;\r
+import org.eclipse.jface.viewers.TableViewer;\r
+import org.eclipse.jface.viewers.Viewer;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.graphics.Image;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.ui.part.ViewPart;\r
+import org.simantics.interop.issues.Issue;\r
+import org.simantics.interop.issues.IssueReporter;\r
+import org.simantics.interop.issues.IssueReporterListener;\r
+\r
+public class IssuesViewPart extends ViewPart {\r
+\r
+ private Composite parent;\r
+ private TableViewer viewer;\r
+ \r
+ \r
+ public IssuesViewPart() {\r
+ // TODO Auto-generated constructor stub\r
+ }\r
+\r
+ @Override\r
+ public void createPartControl(Composite parent) {\r
+ this.parent = parent;\r
+ this.parent.setLayout(new GridLayout(1,false));\r
+ viewer = new TableViewer(parent);\r
+ viewer.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));\r
+ viewer.setContentProvider(new IssueContentProvider());\r
+ viewer.setLabelProvider(new IssueLabelProvider());\r
+ \r
+ viewer.setInput(IssueReporter.getInstance().getIssues());\r
+ \r
+ Composite buttonComposite = new Composite(parent, SWT.BORDER);\r
+ buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL));\r
+ Button clearButton = new Button(buttonComposite, SWT.PUSH);\r
+ clearButton.setText("Clear all");\r
+ clearButton.addSelectionListener(new SelectionAdapter() {\r
+ @Override\r
+ public void widgetSelected(SelectionEvent e) {\r
+ Collection<Issue> issues = IssueReporter.getInstance().getIssues();\r
+ for (Issue i : issues)\r
+ i.dispose();\r
+ }\r
+ });\r
+ \r
+ Button showButton = new Button(buttonComposite, SWT.PUSH);\r
+ showButton.setText("Show in editor");\r
+ showButton.addSelectionListener(new SelectionAdapter() {\r
+ @Override\r
+ public void widgetSelected(SelectionEvent e) {\r
+ IStructuredSelection sel = (IStructuredSelection)viewer.getSelection();\r
+ if (sel.isEmpty())\r
+ return;\r
+ Issue i = (Issue)sel.getFirstElement();\r
+ if (i.supportsEditor())\r
+ i.showInEditor();\r
+ }\r
+ });\r
+ \r
+ \r
+ }\r
+\r
+ @Override\r
+ public void setFocus() {\r
+ parent.setFocus();\r
+ }\r
+ \r
+ \r
+ private class IssueContentProvider implements IStructuredContentProvider {\r
+ private IssueReporterListener listener;\r
+ private Viewer viewer;\r
+ \r
+ public IssueContentProvider() {\r
+ listener = new IssueReporterListener() {\r
+ \r
+ @Override\r
+ public void updated(Issue issue) {\r
+ viewer.refresh();\r
+ }\r
+ \r
+ @Override\r
+ public void removed(Issue issue) {\r
+ viewer.setInput(IssueReporter.getInstance().getIssues());\r
+ }\r
+ \r
+ @Override\r
+ public void added(Issue issue) {\r
+ viewer.setInput(IssueReporter.getInstance().getIssues());\r
+ }\r
+ };\r
+ IssueReporter.getInstance().addListener(listener);\r
+ }\r
+ \r
+ \r
+ @Override\r
+ public Object[] getElements(Object inputElement) {\r
+ Collection<Issue> issues = (Collection<Issue>)inputElement;\r
+ return issues.toArray();\r
+ }\r
+ \r
+ @Override\r
+ public void dispose() {\r
+ IssueReporter.getInstance().removeListener(listener);\r
+ }\r
+ \r
+ @Override\r
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
+ this.viewer = viewer;\r
+ }\r
+ }\r
+ \r
+ private class IssueLabelProvider implements ITableLabelProvider {\r
+ \r
+ private List<ILabelProviderListener> listeners = new ArrayList<ILabelProviderListener>();\r
+ \r
+ @Override\r
+ public Image getColumnImage(Object element, int columnIndex) {\r
+ return null;\r
+ }\r
+ \r
+ @Override\r
+ public String getColumnText(Object element, int columnIndex) {\r
+ Issue issue = (Issue)element;\r
+ if (columnIndex == 0)\r
+ return issue.getDescription();\r
+ return null;\r
+ }\r
+ \r
+ @Override\r
+ public boolean isLabelProperty(Object element, String property) {\r
+ return true;\r
+ }\r
+ \r
+ @Override\r
+ public void addListener(ILabelProviderListener listener) {\r
+ listeners.add(listener);\r
+ }\r
+ \r
+ @Override\r
+ public void removeListener(ILabelProviderListener listener) {\r
+ listeners.remove(listener);\r
+ }\r
+ \r
+ @Override\r
+ public void dispose() {\r
+ \r
+ }\r
+ }\r
+\r
+}\r