From: luukkainen Date: Fri, 5 Nov 2010 14:32:30 +0000 (+0000) Subject: Issues implementation X-Git-Tag: v1.31.0~131 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=f8c634455297c89de2932ee815dfb5cbba427646;p=simantics%2Finterop.git Issues implementation git-svn-id: https://www.simantics.org/svn/simantics/interoperability/trunk@18587 ac1ea38d-2e2b-0410-8846-a27921b304fc --- diff --git a/org.simantics.interop/META-INF/MANIFEST.MF b/org.simantics.interop/META-INF/MANIFEST.MF index 6171d9e..ca01362 100644 --- a/org.simantics.interop/META-INF/MANIFEST.MF +++ b/org.simantics.interop/META-INF/MANIFEST.MF @@ -18,3 +18,4 @@ Require-Bundle: org.eclipse.ui, org.simantics.layer0;bundle-version="1.0.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy +Export-Package: org.simantics.interop.issues diff --git a/org.simantics.interop/plugin.xml b/org.simantics.interop/plugin.xml index 0a51d3d..e558611 100644 --- a/org.simantics.interop/plugin.xml +++ b/org.simantics.interop/plugin.xml @@ -34,6 +34,12 @@ name="Comparator" restorable="true"> + + diff --git a/org.simantics.interop/src/org/simantics/interop/issues/AbstractIssue.java b/org.simantics.interop/src/org/simantics/interop/issues/AbstractIssue.java new file mode 100644 index 0000000..ae14eed --- /dev/null +++ b/org.simantics.interop/src/org/simantics/interop/issues/AbstractIssue.java @@ -0,0 +1,62 @@ +package org.simantics.interop.issues; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.widgets.Display; + +public abstract class AbstractIssue implements Issue{ + + private String description; + private List listeners = new ArrayList(); + + @Override + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + fireUpdated(); + } + + protected void fireUpdated() { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + for (IssueListener l : listeners) { + l.updated(AbstractIssue.this); + } + } + }); + } + + protected void fireDisposed() { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + List list = new ArrayList(); + list.addAll(listeners); + for (IssueListener l : list) { + l.disposed(AbstractIssue.this); + } + } + }); + } + + @Override + public void addListener(IssueListener listener) { + listeners.add(listener); + } + + @Override + public void removeListener(IssueListener listener) { + listeners.remove(listener); + } + + @Override + public void dispose() { + fireDisposed(); + } + +} diff --git a/org.simantics.interop/src/org/simantics/interop/issues/AndRead.java b/org.simantics.interop/src/org/simantics/interop/issues/AndRead.java new file mode 100644 index 0000000..e8a28c0 --- /dev/null +++ b/org.simantics.interop/src/org/simantics/interop/issues/AndRead.java @@ -0,0 +1,30 @@ +package org.simantics.interop.issues; + +import org.simantics.db.ReadGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.request.Read; + +/** + * AndRead can be used to combine multiple requests into single one. If all reads return true or null, this returns true. + * @author Marko Luukkainen + * + */ +public class AndRead implements Read{ + + private Read reads[]; + + public AndRead(Read... reads) { + this.reads = reads; + } + + @Override + public Boolean perform(ReadGraph graph) throws DatabaseException { + Boolean b = null; + for (Read r : reads) { + b = r.perform(graph); + if(b != null && !b) + return false; + } + return true; + } +} diff --git a/org.simantics.interop/src/org/simantics/interop/issues/BasicIssue.java b/org.simantics.interop/src/org/simantics/interop/issues/BasicIssue.java new file mode 100644 index 0000000..12020ab --- /dev/null +++ b/org.simantics.interop/src/org/simantics/interop/issues/BasicIssue.java @@ -0,0 +1,26 @@ +package org.simantics.interop.issues; + +/** + * Basic, static issue. + * @author Marko Luukkainen + * + */ +public class BasicIssue extends AbstractIssue { + + + public BasicIssue(String description) { + setDescription(description); + } + + @Override + public void showInEditor() { + + } + + @Override + public boolean supportsEditor() { + return false; + } + + +} diff --git a/org.simantics.interop/src/org/simantics/interop/issues/GraphIssue.java b/org.simantics.interop/src/org/simantics/interop/issues/GraphIssue.java new file mode 100644 index 0000000..2a37603 --- /dev/null +++ b/org.simantics.interop/src/org/simantics/interop/issues/GraphIssue.java @@ -0,0 +1,76 @@ +package org.simantics.interop.issues; + +import org.simantics.db.AsyncReadGraph; +import org.simantics.db.ReadGraph; +import org.simantics.db.procedure.AsyncListener; +import org.simantics.db.request.Read; +import org.simantics.utils.ui.ErrorLogger; + +/** + * An issue whose state can be updated with an query + * @author Marko Luukkainen + * + */ +public class GraphIssue extends AbstractIssue { + + private boolean disposed = false; + + /** + * Creates an new Graph Issue + * @param g access to graph + * @param request Request that returns true if issue is still valid. If the request returns false, the issue is disposed. + * @param description + */ + public GraphIssue(ReadGraph g, Read request, String description) { + setDescription(description); + IssueReporter.getInstance().addIssue(this); + setRequest(g, request); + } + + public GraphIssue(String description) { + setDescription(description); + IssueReporter.getInstance().addIssue(this); + } + + public void setRequest(ReadGraph g, Read request) { + g.asyncRequest(request,new AsyncListener() { + @Override + public void execute(AsyncReadGraph graph, Boolean result) { + if (result == null) + return; + + if (!result) { + dispose(); + } + } + + @Override + public void exception(AsyncReadGraph graph, Throwable throwable) { + ErrorLogger.defaultLogError("Error in GraphIssue handling, disposing issue \"" + getDescription()+"\"", throwable); + dispose(); + } + + @Override + public boolean isDisposed() { + return disposed; + } + }); + } + + @Override + public void showInEditor() { + + } + + @Override + public boolean supportsEditor() { + return false; + } + + @Override + public void dispose() { + this.disposed = true; + super.dispose(); + } + +} diff --git a/org.simantics.interop/src/org/simantics/interop/issues/Issue.java b/org.simantics.interop/src/org/simantics/interop/issues/Issue.java new file mode 100644 index 0000000..8d7a072 --- /dev/null +++ b/org.simantics.interop/src/org/simantics/interop/issues/Issue.java @@ -0,0 +1,38 @@ +package org.simantics.interop.issues; + +/** + * Interface for an issue + * + * TODO: grouping, severity? + * + * @author Marko Luukkainen + * + */ +public interface Issue { + + /** + * Prints description + * @return + */ + public String getDescription(); + + /** + * Returns true if this issue can be highlighted in an editor + * @return + */ + public boolean supportsEditor(); + + /** + * Opens and highlights the reason of the issue in an editor + */ + public void showInEditor(); + + /** + * Disposes the issue. + */ + public void dispose(); + + public void addListener(IssueListener listenr); + public void removeListener(IssueListener listener); + +} diff --git a/org.simantics.interop/src/org/simantics/interop/issues/IssueListener.java b/org.simantics.interop/src/org/simantics/interop/issues/IssueListener.java new file mode 100644 index 0000000..0750afd --- /dev/null +++ b/org.simantics.interop/src/org/simantics/interop/issues/IssueListener.java @@ -0,0 +1,22 @@ +package org.simantics.interop.issues; + +/** + * Interface for listening changes in issues. + * @author Marko Luukkainen + * + */ +public interface IssueListener { + + /** + * Issues is updated + * @param issue + */ + public void updated(Issue issue); + + /** + * Issue is disposed (not valid anymore); + * @param issue + */ + public void disposed(Issue issue); + +} diff --git a/org.simantics.interop/src/org/simantics/interop/issues/IssueReporter.java b/org.simantics.interop/src/org/simantics/interop/issues/IssueReporter.java new file mode 100644 index 0000000..f1ab4a7 --- /dev/null +++ b/org.simantics.interop/src/org/simantics/interop/issues/IssueReporter.java @@ -0,0 +1,107 @@ +package org.simantics.interop.issues; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.swt.widgets.Display; + +/** + * IssueReporter is singleton class that handles collecting issues. + * + * TODO: how to store issues when the application is closed? Memento-based? + * + * @author Marko Luukkainen + * + */ +public class IssueReporter implements IssueListener{ + + private static IssueReporter INSTANCE; + + private List issues = new ArrayList(); + private List listeners = new ArrayList(); + + + private IssueReporter() { + + } + + public static IssueReporter getInstance() { + if (INSTANCE == null) + INSTANCE = new IssueReporter(); + return INSTANCE; + } + + /** + * Retuns list of issues. + * @return + */ + public List getIssues() { + return Collections.unmodifiableList(issues); + } + + public void addIssue(Issue issue) { + issues.add(issue); + issue.addListener(this); + fireAdded(issue); + } + + public void removeIssue(Issue issue) { + issue.removeListener(this); + issues.remove(issue); + fireRemoved(issue); + } + + @Override + public void updated(Issue issue) { + fireUpdated(issue); + } + + @Override + public void disposed(Issue issue) { + issue.removeListener(this); + issues.remove(issue); + fireRemoved(issue); + } + + + public void addListener(IssueReporterListener listener) { + listeners.add(listener); + } + + public void removeListener(IssueReporterListener listener) { + listeners.remove(listener); + } + + protected void fireAdded(final Issue issue) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + for (IssueReporterListener l : listeners) + l.added(issue); + } + }); + } + + protected void fireRemoved(final Issue issue) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + for (IssueReporterListener l : listeners) + l.removed(issue); + } + }); + } + + protected void fireUpdated(final Issue issue) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + for (IssueReporterListener l : listeners) + l.updated(issue); + } + }); + } + + +} diff --git a/org.simantics.interop/src/org/simantics/interop/issues/IssueReporterListener.java b/org.simantics.interop/src/org/simantics/interop/issues/IssueReporterListener.java new file mode 100644 index 0000000..8b15040 --- /dev/null +++ b/org.simantics.interop/src/org/simantics/interop/issues/IssueReporterListener.java @@ -0,0 +1,9 @@ +package org.simantics.interop.issues; + +public interface IssueReporterListener { + + public void added(Issue issue); + public void removed(Issue issue); + public void updated(Issue issue); + +} diff --git a/org.simantics.interop/src/org/simantics/interop/ui/IssuesViewPart.java b/org.simantics.interop/src/org/simantics/interop/ui/IssuesViewPart.java new file mode 100644 index 0000000..d9e7b6d --- /dev/null +++ b/org.simantics.interop/src/org/simantics/interop/ui/IssuesViewPart.java @@ -0,0 +1,165 @@ +package org.simantics.interop.ui; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.part.ViewPart; +import org.simantics.interop.issues.Issue; +import org.simantics.interop.issues.IssueReporter; +import org.simantics.interop.issues.IssueReporterListener; + +public class IssuesViewPart extends ViewPart { + + private Composite parent; + private TableViewer viewer; + + + public IssuesViewPart() { + // TODO Auto-generated constructor stub + } + + @Override + public void createPartControl(Composite parent) { + this.parent = parent; + this.parent.setLayout(new GridLayout(1,false)); + viewer = new TableViewer(parent); + viewer.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + viewer.setContentProvider(new IssueContentProvider()); + viewer.setLabelProvider(new IssueLabelProvider()); + + viewer.setInput(IssueReporter.getInstance().getIssues()); + + Composite buttonComposite = new Composite(parent, SWT.BORDER); + buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); + Button clearButton = new Button(buttonComposite, SWT.PUSH); + clearButton.setText("Clear all"); + clearButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + Collection issues = IssueReporter.getInstance().getIssues(); + for (Issue i : issues) + i.dispose(); + } + }); + + Button showButton = new Button(buttonComposite, SWT.PUSH); + showButton.setText("Show in editor"); + showButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + IStructuredSelection sel = (IStructuredSelection)viewer.getSelection(); + if (sel.isEmpty()) + return; + Issue i = (Issue)sel.getFirstElement(); + if (i.supportsEditor()) + i.showInEditor(); + } + }); + + + } + + @Override + public void setFocus() { + parent.setFocus(); + } + + + private class IssueContentProvider implements IStructuredContentProvider { + private IssueReporterListener listener; + private Viewer viewer; + + public IssueContentProvider() { + listener = new IssueReporterListener() { + + @Override + public void updated(Issue issue) { + viewer.refresh(); + } + + @Override + public void removed(Issue issue) { + viewer.setInput(IssueReporter.getInstance().getIssues()); + } + + @Override + public void added(Issue issue) { + viewer.setInput(IssueReporter.getInstance().getIssues()); + } + }; + IssueReporter.getInstance().addListener(listener); + } + + + @Override + public Object[] getElements(Object inputElement) { + Collection issues = (Collection)inputElement; + return issues.toArray(); + } + + @Override + public void dispose() { + IssueReporter.getInstance().removeListener(listener); + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + this.viewer = viewer; + } + } + + private class IssueLabelProvider implements ITableLabelProvider { + + private List listeners = new ArrayList(); + + @Override + public Image getColumnImage(Object element, int columnIndex) { + return null; + } + + @Override + public String getColumnText(Object element, int columnIndex) { + Issue issue = (Issue)element; + if (columnIndex == 0) + return issue.getDescription(); + return null; + } + + @Override + public boolean isLabelProperty(Object element, String property) { + return true; + } + + @Override + public void addListener(ILabelProviderListener listener) { + listeners.add(listener); + } + + @Override + public void removeListener(ILabelProviderListener listener) { + listeners.remove(listener); + } + + @Override + public void dispose() { + + } + } + +}