]> gerrit.simantics Code Review - simantics/interop.git/commitdiff
Generinc UpdateEditor
authorMarko Luukkainen <marko.luukkainen@vtt.fi>
Thu, 23 Feb 2017 10:21:37 +0000 (12:21 +0200)
committerMarko Luukkainen <marko.luukkainen@vtt.fi>
Thu, 23 Feb 2017 10:21:37 +0000 (12:21 +0200)
refs #7045

Change-Id: Idad586011de488d6d188949b3817e10ac2633632

org.simantics.interop.update/META-INF/MANIFEST.MF
org.simantics.interop.update/src/org/simantics/interop/update/editor/ModelUpdateEditor.java [new file with mode: 0644]
org.simantics.interop.update/src/org/simantics/interop/update/editor/UpdateEditorInput.java [new file with mode: 0644]
org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateNode.java
org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateOperations.java
org.simantics.interop.update/src/org/simantics/interop/update/model/UpdateTree.java

index 83657dea45553098d554042fc884369dc060618f..d0a0ca7f5e95ea0c83b152cf7f33da15404adc57 100644 (file)
@@ -12,7 +12,10 @@ Require-Bundle: org.eclipse.ui,
  org.simantics.db.common;bundle-version="1.1.0",
  org.simantics.layer0;bundle-version="1.1.0",
  org.simantics.issues;bundle-version="1.1.0",
- org.simantics.issues.common;bundle-version="1.1.0"
+ org.simantics.issues.common;bundle-version="1.1.0",
+ org.simantics.db.layer0;bundle-version="1.1.0",
+ org.simantics.ui;bundle-version="1.0.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-ActivationPolicy: lazy
-Export-Package: org.simantics.interop.update.model
+Export-Package: org.simantics.interop.update.editor,
+ org.simantics.interop.update.model
diff --git a/org.simantics.interop.update/src/org/simantics/interop/update/editor/ModelUpdateEditor.java b/org.simantics.interop.update/src/org/simantics/interop/update/editor/ModelUpdateEditor.java
new file mode 100644 (file)
index 0000000..a3b6033
--- /dev/null
@@ -0,0 +1,770 @@
+package org.simantics.interop.update.editor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Stack;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxCellEditor;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.ITreeViewerListener;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TreeExpansionEvent;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+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.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.RGB;
+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.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IEditorInput;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Statement;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.DoesNotContainValueException;
+import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
+import org.simantics.db.exception.NoSingleResultException;
+import org.simantics.db.exception.ServiceException;
+import org.simantics.db.request.Read;
+import org.simantics.interop.test.GraphChanges;
+import org.simantics.interop.test.GraphComparator;
+import org.simantics.interop.test.NameComparator;
+import org.simantics.interop.update.Activator;
+import org.simantics.interop.update.model.UpdateNode;
+import org.simantics.interop.update.model.UpdateNode.Status;
+import org.simantics.interop.update.model.UpdateTree;
+import org.simantics.interop.utils.TableUtils;
+import org.simantics.layer0.Layer0;
+import org.simantics.ui.workbench.ResourceEditorPart2;
+import org.simantics.utils.datastructures.BijectionMap;
+import org.simantics.utils.datastructures.Callback;
+import org.simantics.utils.datastructures.Pair;
+import org.simantics.utils.ui.ExceptionUtils;
+
+
+/**
+ * Editor for updating models.
+ * 
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public abstract class ModelUpdateEditor extends ResourceEditorPart2 {
+
+       
+       private Composite composite;
+       private Composite errorComposite;
+       
+       private CheckboxTreeViewer changeBrowser;
+       private TableViewer changeViewer;
+       
+       private GraphChanges changes;
+       private UpdateTree updateTree;
+       
+       private Button updateAllButton;
+       private Button updateSelectedButton;
+       
+       private LocalResourceManager manager = new LocalResourceManager(JFaceResources.getResources());
+       
+       private Image checked;
+       private Image unchecked;
+       private Image warning;
+       
+       private Color containsColor;
+       private Color deletedColor;
+       private Color addedColor;
+       
+       private HashSet<Pair<Statement, Statement>> selected = new HashSet<Pair<Statement,Statement>>();
+       
+       private HashSet<UpdateNode> selectedStructure = new HashSet<UpdateNode>();
+       
+       private List<ChangeFilter> filters = new ArrayList<ChangeFilter>();
+       
+       public ModelUpdateEditor() {
+               checked = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/tick.png"));
+               unchecked = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/cross.png"));
+               warning = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/error.png"));
+       }
+       
+       @Override
+       public void createPartControl(Composite parent) {
+               
+               containsColor = new Color(parent.getDisplay(), new RGB(255,255,220));
+               deletedColor = new Color(parent.getDisplay(), new RGB(255,220,220));
+               addedColor = new Color(parent.getDisplay(), new RGB(220,255,220));
+               
+               composite = new Composite(parent, SWT.NONE);
+               composite.setLayout(new GridLayout(1,false));
+               
+               errorComposite = new Composite(composite, SWT.BORDER);
+               GridData data = new GridData();
+               data.grabExcessHorizontalSpace = true;
+               data.grabExcessVerticalSpace = false;
+               data.horizontalAlignment = SWT.FILL;
+               data.verticalAlignment = SWT.TOP;
+               errorComposite.setLayoutData(data);
+               errorComposite.setLayout(new GridLayout(2, false));
+               
+               errorComposite.setVisible(false);
+
+               IEditorInput input = getEditorInput();
+               if (!(input instanceof UpdateEditorInput)) {
+                       Label label = new Label(composite, SWT.NONE);
+                       label.setText("Unknown input.");
+                       return;
+               }
+               
+               Composite fillComposite = new Composite(composite, SWT.NONE);
+               data = new GridData();
+               data.grabExcessHorizontalSpace = true;
+               data.grabExcessVerticalSpace = true;
+               data.horizontalAlignment = SWT.FILL;
+               data.verticalAlignment = SWT.FILL;
+               fillComposite.setLayoutData(data);
+               fillComposite.setLayout(new FillLayout(SWT.VERTICAL));
+
+               {
+                       changeBrowser = new CheckboxTreeViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION  );
+                       
+                       changeBrowser.setContentProvider(new UpdateTreeContentProvider());
+                       
+                       changeBrowser.getTree().setHeaderVisible(true);
+                       
+                       ColumnViewerToolTipSupport.enableFor(changeBrowser);
+
+                       
+                       TreeViewerColumn dataColumn = TableUtils.addColumn(changeBrowser, "Data", true, 600);
+
+                       dataColumn.setLabelProvider(new UpdateNodeLabelProvicer());
+                       
+                       changeBrowser.addCheckStateListener(new ICheckStateListener() {
+                               
+                               @Override
+                               public void checkStateChanged(CheckStateChangedEvent event) {
+                                       UpdateNode node = (UpdateNode) event.getElement();
+                                       if (node.getOp() != null) {
+                                               node.getOp().select(Boolean.TRUE.equals(event.getChecked()));
+                                               
+                                       }
+                                       updateSelection();
+                                       
+                               }
+                       });
+                       changeBrowser.addTreeListener(new ITreeViewerListener() {
+                               
+                               @Override
+                               public void treeExpanded(TreeExpansionEvent event) {
+                                       event.getTreeViewer().getControl().getDisplay().asyncExec(new Runnable() {
+                                               
+                                               @Override
+                                               public void run() {
+                                                       updateSelection();
+                                               }
+                                       });
+                                       
+                               }
+                               
+                               @Override
+                               public void treeCollapsed(TreeExpansionEvent event) {
+                                       
+                               }
+                       });
+                       changeBrowser.setUseHashlookup(true);
+                       
+               }
+               {
+                       changeViewer = new TableViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION);
+                       
+                       changeViewer.getTable().setHeaderVisible(true);
+                       changeViewer.getTable().setLinesVisible(true);
+                       
+                       changeViewer.setContentProvider(new ModificationListContentProvider());
+                       
+                       changeViewer.setUseHashlookup(true);
+                       
+                       TableViewerColumn selection = TableUtils.addColumn(changeViewer, getColumntTitle(0), false, false, 20);
+                       TableViewerColumn diagram = TableUtils.addColumn(changeViewer, getColumntTitle(1), true, true, 100);
+                       TableViewerColumn symbol = TableUtils.addColumn(changeViewer, getColumntTitle(2), true, true, 100);
+                       TableViewerColumn property = TableUtils.addColumn(changeViewer, getColumntTitle(3), true, true, 100);
+                       TableViewerColumn oldValue = TableUtils.addColumn(changeViewer, getColumntTitle(4), true, true, 100);
+                       TableViewerColumn newValue = TableUtils.addColumn(changeViewer, getColumntTitle(5), true, true, 100);
+                       
+                       diagram.setLabelProvider(getLabelProvider(1));
+                       symbol.setLabelProvider(getLabelProvider(2));
+                       property.setLabelProvider(getLabelProvider(3));
+                       oldValue.setLabelProvider(getLabelProvider(4));
+                       newValue.setLabelProvider(getLabelProvider(5));
+                       
+                       selection.setLabelProvider(new SelectionLabelProvider(selected));
+                       selection.getColumn().addSelectionListener(new SelectionAdapter() {
+                               @Override
+                               public void widgetSelected(SelectionEvent e) {
+                                       if (changes.getModifications().size() > 0) {
+                                               if (selected.contains(changes.getModifications().get(0))) {
+                                                       for (Pair<Statement, Statement> nr : changes.getModifications())
+                                                               selected.remove(nr);
+                                               } else {
+                                                       for (Pair<Statement, Statement> nr : changes.getModifications())
+                                                               selected.add(nr);
+                                               }
+                                               changeViewer.refresh();
+                                       }
+                               }
+                       });
+                       selection.setEditingSupport(new SelectionEditingSupport(changeViewer, selected));
+               
+               }
+               Composite buttonComposite = new Composite(composite, SWT.NONE);
+               
+               data = new GridData();
+               data.grabExcessHorizontalSpace = true;
+               data.grabExcessVerticalSpace = false;
+               data.horizontalAlignment = SWT.FILL;
+               data.verticalAlignment = SWT.BOTTOM;
+               
+               buttonComposite.setLayoutData(data);
+               
+               buttonComposite.setLayout(new GridLayout(3, false));
+               
+               Label label = new Label(buttonComposite, SWT.NONE);
+               data = new GridData();
+               data.grabExcessHorizontalSpace = true;
+               data.grabExcessVerticalSpace = false;
+               data.horizontalAlignment = SWT.FILL;
+               data.verticalAlignment = SWT.CENTER;
+               label.setLayoutData(data);
+               
+               updateAllButton = new Button(buttonComposite, SWT.PUSH);
+               updateAllButton.setText("Update All");
+               updateAllButton.addSelectionListener(new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               updateAll();
+                       }
+               });
+               updateSelectedButton = new Button(buttonComposite, SWT.PUSH);
+               updateSelectedButton.setText("Update Selected");
+               updateSelectedButton.addSelectionListener(new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               updateSelected();
+                       }
+               });
+
+               load();
+               
+       }
+       
+       protected String getColumntTitle(int i) {
+               switch (i) {
+               case 0:
+                       return "!";
+               case 1:
+                       return "Diagram";
+               case 2:
+                       return "Symbol";
+               case 3:
+                       return "Property";
+               case 4:
+                       return "Old Value";
+               case 5:
+                       return "New Value";
+               default:
+                       throw new RuntimeException("Unknown column index" + i);
+                       
+               }
+       }
+       
+       protected abstract ColumnLabelProvider getLabelProvider(int i);
+       protected abstract Pair<GraphComparator,Boolean> getChanges(Resource r1, Resource r2)  throws DatabaseException;
+       protected abstract UpdateTree getUpdateTree(GraphChanges changes) throws DatabaseException;
+       
+       protected void addFilters(List<ChangeFilter> filters) {
+               
+       }
+       
+       public GraphChanges getChanges() {
+               return changes;
+       }
+       
+       private void showWarning(String text) {
+               errorComposite.setVisible(true);
+               
+               Label label = new Label(errorComposite, SWT.NONE);
+               label.setImage(warning);
+               label = new Label(errorComposite, SWT.NONE);
+               label.setText(text);
+               //this.setStatusMessage("Update contains structural changes (new or deleted symbols), please create a new model.");
+               composite.layout(true);
+       
+       }
+       
+       private void updateSelection() {
+               Stack<UpdateNode> nodeStack = new Stack<UpdateNode>();
+               nodeStack.push((UpdateNode)updateTree.getRootNode());
+               while (!nodeStack.isEmpty()) {
+                       UpdateNode n = nodeStack.pop();
+                       if (n.getOp() != null) {
+                               boolean applied = n.getOp().applied();
+                               if (applied) {
+                                       changeBrowser.setChecked(n, true);
+                                       changeBrowser.setGrayed(n, true);
+                                       selectedStructure.remove(n);
+                               } else {
+                                       boolean sel = n.getOp().selected();
+                                       if (sel) {
+                                               selectedStructure.add(n);
+                                               
+                                       } else {
+                                               selectedStructure.remove(n);
+                                       }
+                                       changeBrowser.setChecked(n, sel);
+                                       changeBrowser.setGrayed(n, false);
+                               }
+                       } else {
+                               changeBrowser.setGrayed(n, true);
+                               changeBrowser.setChecked(n, true);
+                       }
+                       for (UpdateNode c : n.getChildren()) {
+                               nodeStack.add((UpdateNode)c);
+                       }
+               }
+               
+               changeBrowser.refresh();
+       }
+       
+       
+       
+       private void load() {
+               
+               addFilters(filters);
+
+               UpdateEditorInput uei = (UpdateEditorInput)getEditorInput();
+               Resource r1 = uei.getR1();
+               Resource r2 = uei.getR2();
+               
+
+               try {
+                       
+                       Pair<GraphComparator,Boolean> result = getChanges(r1,r2);
+                       GraphComparator comparator  = result.first;
+                       if (result.second)
+                               showWarning("Structural symbols have been changed. Model update is not able to update these, please create a new model.");
+                       comparator.test(getSession());
+                       changes = comparator.getChanges();
+                       changes = getSession().syncRequest(new FilterChangesRead(changes));
+                       updateTree = getUpdateTree(changes);
+               } catch (DatabaseException e) {
+                       Text text = new Text(composite, SWT.MULTI);
+                       text.setText(e.getMessage());
+                       e.printStackTrace();
+                       return;
+               }
+       
+
+
+               changeViewer.setInput(changes.getModifications());
+               changeBrowser.setInput(updateTree);
+               updateSelection();
+       }
+       
+       
+       
+       private void updateAll() {
+               updateAllButton.setEnabled(false);
+               updateSelectedButton.setEnabled(false);
+               getSession().asyncRequest(new WriteRequest(){
+                       @Override
+                       public void perform(WriteGraph graph) throws DatabaseException {
+                               for (Pair<Statement, Statement> mod : changes.getModifications()) {
+                                       applyLiteralChange(graph, mod);
+                               }
+                               selected.clear();
+                               changes.getModifications().clear();
+                               
+                               updateTree.getUpdateOps().applyAll(graph);
+                               
+                               Display.getDefault().asyncExec(new Runnable() {
+                                       
+                                       @Override
+                                       public void run() {
+                                               
+                                               updateAllButton.setEnabled(true);
+                                               updateSelectedButton.setEnabled(true);
+                                               updateSelection();
+                                               changeViewer.refresh();
+                                       }
+                               });
+                       }
+                       
+                       
+               }, new Callback<DatabaseException>() {
+                       @Override
+                       public void run(DatabaseException parameter) {
+                               if (parameter != null)
+                                       ExceptionUtils.logAndShowError("Cannot update model", parameter);
+                       }
+               });
+       }
+       
+       private void applyLiteralChange(WriteGraph graph, Pair<Statement, Statement> mod) throws DoesNotContainValueException, ServiceException, ManyObjectsForFunctionalRelationException {
+               
+               Resource s = changes.getComparable().getLeft(mod.second.getSubject());
+               Resource pred = mod.first.getPredicate();
+               if (graph.hasValue(mod.second.getObject())) {
+                       Object value = graph.getValue(mod.second.getObject());
+                       graph.claimLiteral(s, pred, value);
+               } else {
+                       graph.deny(s,pred);
+               }
+               
+               
+       }
+       
+       private void updateSelected() {
+               updateAllButton.setEnabled(false);
+               updateSelectedButton.setEnabled(false);
+               getSession().asyncRequest(new WriteRequest(){
+                       @Override
+                       public void perform(WriteGraph graph) throws DatabaseException {
+                               for (Pair<Statement, Statement> mod : selected) {
+                                       changes.getModifications().remove(mod);
+                                       applyLiteralChange(graph, mod);
+                               }
+                               selected.clear();
+                               
+                               updateTree.getUpdateOps().applySelected(graph);
+                               
+                               Display.getDefault().asyncExec(new Runnable() {
+                                       
+                                       @Override
+                                       public void run() {
+                                               changeViewer.refresh();
+                                               updateAllButton.setEnabled(true);
+                                               updateSelectedButton.setEnabled(true);
+                                               updateSelection();
+                                       }
+                               });
+                       }
+               });
+       }
+
+       @Override
+       public void setFocus() {
+               composite.setFocus();
+
+       }
+       
+       /**
+        * Filters changes:
+        * 1. Changes that are not essential for model update (changes that can be found when the models are axcatly the same)
+        * 2. Runs custom filters for value changes. 
+        * 
+        * @param g
+        * @param changes
+        * @return
+        * @throws DatabaseException
+        */
+       protected GraphChanges filterChanges(ReadGraph g, GraphChanges changes) throws DatabaseException 
+    {
+               
+               List<Pair<Statement,Statement>> modifications = new ArrayList<Pair<Statement,Statement>>();
+               
+       for (Pair<Statement, Statement> mod : changes.getModifications()) {
+               
+               boolean accept = true;
+               for (ChangeFilter filter : filters) {
+                       if (!filter.accept(g, mod)) {
+                               accept = false;
+                               break;
+                       }       
+               }
+               if (accept)
+                       modifications.add(mod);
+       }
+       GraphChanges newChanges =  new GraphChanges(changes.getResource1(),changes.getResource2(),changes.getDeletions(), changes.getAdditions(), modifications, changes.getComparable());
+       return newChanges;
+    }
+       
+       public interface ChangeFilter {
+               public boolean accept(ReadGraph g, Pair<Statement, Statement> change) throws DatabaseException;
+       }
+       
+       
+       
+       
+       /**
+        * 
+        * Filters floating point value changes (default filter is set filter when the change is less than 1%)  
+        *
+        */
+       protected class FPValueFilter implements ChangeFilter  {
+               
+               private double percentage = 0.01;
+               
+               public FPValueFilter() {
+                       
+               }
+               
+               public FPValueFilter(double percentage) {
+                       if (percentage < 0.0 || percentage > 1.0)
+                               throw new IllegalArgumentException("Percentage must be between 0.0 and 1.0.");
+                       this.percentage = percentage;
+               }
+               
+               @Override
+               public boolean accept(ReadGraph g, Pair<Statement, Statement> change) throws DatabaseException {
+                       //filter floating point values that have less than 1% difference.
+                       if (!g.hasValue(change.first.getObject()) || !g.hasValue(change.second.getObject()))
+                               return true;
+               Object v1 = g.getValue(change.first.getObject());
+               Object v2 = g.getValue(change.second.getObject());
+               
+               if (v1 instanceof Double && v2 instanceof Double) {
+                       double d1 = (Double)v1;
+                       double d2 = (Double)v2;
+                       if (Math.abs(d1-d2) / Math.max(Math.abs(d1), Math.abs(d2)) < percentage)
+                               return false;
+               } else if (v1 instanceof Float && v2 instanceof Float) {
+                       float d1 = (Float)v1;
+                       float d2 = (Float)v2;
+                       if (Math.abs(d1-d2) / Math.max(Math.abs(d1), Math.abs(d2)) < percentage)
+                               return false;
+               }
+
+               return true;
+               }
+       }
+
+       
+       private class FilterChangesRead implements Read<GraphChanges> {
+               private GraphChanges changes;
+               public FilterChangesRead(GraphChanges changes) {
+                       this.changes = changes;
+               }
+               
+               @Override
+               public GraphChanges perform(ReadGraph graph) throws DatabaseException {
+                       return filterChanges(graph, changes);
+               }
+       }
+       
+       
+       private class ModificationListContentProvider implements IStructuredContentProvider {
+               
+               @SuppressWarnings("unchecked")
+               @Override
+               public Object[] getElements(Object inputElement) {
+                       if (inputElement == null)
+                               return null;
+                       Collection<Pair<Statement, Statement>> coll = (Collection<Pair<Statement, Statement>>)inputElement;
+                       return coll.toArray();
+               }
+               
+               @Override
+               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+                       
+               }
+               
+               @Override
+               public void dispose() {
+                       
+               }
+       }
+       
+       private class UpdateTreeContentProvider implements ITreeContentProvider {
+               @Override
+               public Object[] getElements(Object inputElement) {
+                       if (inputElement instanceof UpdateTree)
+                               return new Object[]{((UpdateTree)inputElement).getRootNode()};
+                       if (inputElement instanceof UpdateNode) {
+                               UpdateNode node = (UpdateNode)inputElement;
+                               return node.getChildren().toArray();
+                       }
+                       return new Object[0];
+               }
+               
+               @Override
+               public Object getParent(Object element) {
+                       return null;
+               }
+               
+               @Override
+               public Object[] getChildren(Object parentElement) {
+                       UpdateNode node = (UpdateNode)parentElement;
+                       return node.getChildren().toArray();
+               }
+               
+               @Override
+               public boolean hasChildren(Object element) {
+                       UpdateNode node = (UpdateNode)element;
+                       return node.getChildren().size() > 0;
+               }
+               
+               @Override
+               public void dispose() {
+                       
+               }
+               
+               @Override
+               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+                       
+               }
+       }
+       
+       private class SelectionLabelProvider extends ColumnLabelProvider {
+               
+               Collection<?>  selected;
+               public SelectionLabelProvider(Collection<?>  selected) {
+                       this.selected = selected;
+               }
+               @Override
+               public String getText(Object element) {
+                       return "";
+               }
+               
+               @Override
+               public Image getImage(Object element) {
+                       if (selected.contains(element))
+                               return checked;
+                       else
+                               return unchecked;
+               }
+       }
+       
+       private class UpdateNodeLabelProvicer extends ColumnLabelProvider {
+               
+               @Override
+               public String getText(Object element) {
+                       final UpdateNode node = (UpdateNode)element;
+                       try  {
+                               return getSession().syncRequest(new Read<String>() {
+                                       @Override
+                                       public String perform(ReadGraph graph) throws DatabaseException {
+                                               return node.getLabel(graph);
+                                       }
+                               });
+                       } catch (Exception e) {
+                               return e.getMessage();
+                       }
+               }
+               
+               @Override
+               public Image getImage(Object element) {
+                       final UpdateNode node = (UpdateNode)element;
+                       try  {
+                               ImageDescriptor id = getSession().syncRequest(new Read<ImageDescriptor>() {
+                                       @Override
+                                       public ImageDescriptor perform(ReadGraph graph) throws DatabaseException {
+                                               return node.getImage(graph);
+                                       }
+                               });
+                               return manager.createImage(id);
+                       } catch (Exception e) {
+                               return null;
+                       }
+               }
+               
+               @Override
+               public String getToolTipText(Object element) {
+                       final UpdateNode node = (UpdateNode)element;
+                       if (node.getOp() != null) {
+                               return node.getOp().toString();
+                       } else {
+                               return null;
+                       }
+               }
+               
+               @Override
+               public int getToolTipDisplayDelayTime(Object object) {
+                       return 1000;
+               }
+               
+               @Override
+               public int getToolTipTimeDisplayed(Object object) {
+                       return 10000;
+               }
+
+               @Override
+               public Color getBackground(Object element) {
+                       final UpdateNode node = (UpdateNode)element;
+                       Status status = node.getStatus();
+                       if (status == Status.CONTAINS)
+                               return containsColor;
+                       if (status == Status.DELETED)
+                               return deletedColor;
+                       if (status == Status.NEW)
+                               return addedColor;
+                       return null;            
+               }
+       }
+       
+       private class SelectionEditingSupport extends EditingSupport {
+               
+               @SuppressWarnings("rawtypes")
+               Collection selected;
+
+               
+               @SuppressWarnings("rawtypes")
+               public SelectionEditingSupport(ColumnViewer viewer, Collection selected) {
+                       super(viewer);
+                       this.selected = selected;
+                       
+               }
+
+               @Override
+               protected boolean canEdit(Object element) {
+                       return true;
+               }
+               
+               @Override
+               protected CellEditor getCellEditor(Object element) {
+                       return new CheckboxCellEditor(null, SWT.CHECK);
+               }
+               
+               @Override
+               protected Object getValue(Object element) {
+                       return selected.contains(element);
+               }
+               
+               @SuppressWarnings("unchecked")
+               @Override
+               protected void setValue(Object element, Object value) {
+                       if (Boolean.TRUE.equals(value))
+                               selected.add(element);
+                       else
+                               selected.remove(element);
+                       
+                       getViewer().refresh(element);
+               }
+               
+               
+       }
+
+
+}
diff --git a/org.simantics.interop.update/src/org/simantics/interop/update/editor/UpdateEditorInput.java b/org.simantics.interop.update/src/org/simantics/interop/update/editor/UpdateEditorInput.java
new file mode 100644 (file)
index 0000000..f91f659
--- /dev/null
@@ -0,0 +1,33 @@
+package org.simantics.interop.update.editor;
+
+import org.simantics.db.Resource;
+import org.simantics.db.layer0.variable.RVI;
+import org.simantics.ui.workbench.ResourceEditorInput2;
+
+/**
+ * Editor input for ModelUpdateEditor
+ * 
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public class UpdateEditorInput extends ResourceEditorInput2{
+
+       private Resource r1;
+       private Resource r2;
+       
+       public UpdateEditorInput(String editorID, Resource r1, Resource r2, Resource model, RVI rvi) {
+               super(editorID, r1, model, rvi);
+               this.r1 = r1;
+               this.r2 = r2;
+       }
+
+       public Resource getR1() {
+               return r1;
+       }
+       
+       public Resource getR2() {
+               return r2;
+       }
+       
+       
+}
index e1312bfac3fb1d38d0caa869599290fc9a8a0319..da78b9016638aceb359281f304cdcf2a8844c0ee 100644 (file)
@@ -13,7 +13,7 @@ import org.simantics.db.exception.ServiceException;
 import org.simantics.db.exception.ValidationException;
 import org.simantics.layer0.Layer0;
 
-public abstract class UpdateNode {
+public class UpdateNode {
 
        public enum Status {EXIST,DELETED,NEW,CONTAINS};
        
@@ -69,7 +69,9 @@ public abstract class UpdateNode {
                children.add(node);
        }
 
-       public abstract ImageDescriptor getImage(ReadGraph graph) throws DatabaseException;
+       public ImageDescriptor getImage(ReadGraph graph) throws DatabaseException {
+               return null;
+       }
 
        public String getLabel(ReadGraph graph) throws DatabaseException {
                return getLabel(graph,r);
index 74acf180cb455c952a14f1a7dcd21a866bed5ea6..9c929c59cc4f267d14d1cc5f867d05fce23c00d6 100644 (file)
@@ -92,7 +92,7 @@ public abstract  class UpdateOperations {
        protected void replaceOp(Resource r, UpdateOp op) {
                UpdateOp oldOp = opMap.remove(r);
                if (oldOp != null) {
-                       operations.remove(op);
+                       operations.remove(oldOp);
                }
                opMap.put(r, op);
                operations.add(op);
index b7a2c4be6c27ed90e58fb5eeb2c54781f63d6acd..d06d70637b539618aff056b30fb08c8954c667bc 100644 (file)
@@ -10,7 +10,7 @@ import org.simantics.interop.test.GraphChanges;
 import org.simantics.interop.update.model.UpdateNode.Status;
 
 
-public abstract class UpdateTree {
+public class UpdateTree {
        
        private UpdateNode rootNode;
        private Map<Resource,UpdateNode> nodes;
@@ -37,8 +37,13 @@ public abstract class UpdateTree {
                return rootNode;
        }
        
-       protected abstract UpdateNode createNode(Status status, Resource r);
-       protected abstract UpdateNode createNode(Status status, UpdateOp op);
+       protected UpdateNode createNode(Status status, Resource r) {
+               return new UpdateNode(status, r);
+       }
+       
+       protected UpdateNode createNode(Status status, UpdateOp op) {
+               return new UpdateNode(status, op);
+       }
        
        private UpdateNode createNode(Resource r1, Resource r2) {
                UpdateNode node = null;
@@ -95,7 +100,9 @@ public abstract class UpdateTree {
                }
        }
        
-       protected abstract boolean handleCustom(ReadGraph g, UpdateOp op) throws DatabaseException;
+       protected boolean handleCustom(ReadGraph g, UpdateOp op) throws DatabaseException {
+               return false;
+       }
        
        private void populate(ReadGraph g) throws DatabaseException{