1 package org.simantics.interop.update.editor;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashSet;
7 import java.util.Stack;
9 import org.eclipse.jface.resource.ImageDescriptor;
10 import org.eclipse.jface.resource.JFaceResources;
11 import org.eclipse.jface.resource.LocalResourceManager;
12 import org.eclipse.jface.viewers.CellEditor;
13 import org.eclipse.jface.viewers.CheckStateChangedEvent;
14 import org.eclipse.jface.viewers.CheckboxCellEditor;
15 import org.eclipse.jface.viewers.CheckboxTreeViewer;
16 import org.eclipse.jface.viewers.ColumnLabelProvider;
17 import org.eclipse.jface.viewers.ColumnViewer;
18 import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
19 import org.eclipse.jface.viewers.EditingSupport;
20 import org.eclipse.jface.viewers.ICheckStateListener;
21 import org.eclipse.jface.viewers.IStructuredContentProvider;
22 import org.eclipse.jface.viewers.ITreeContentProvider;
23 import org.eclipse.jface.viewers.ITreeViewerListener;
24 import org.eclipse.jface.viewers.TableViewer;
25 import org.eclipse.jface.viewers.TableViewerColumn;
26 import org.eclipse.jface.viewers.TreeExpansionEvent;
27 import org.eclipse.jface.viewers.TreeViewerColumn;
28 import org.eclipse.jface.viewers.Viewer;
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.events.SelectionAdapter;
31 import org.eclipse.swt.events.SelectionEvent;
32 import org.eclipse.swt.graphics.Color;
33 import org.eclipse.swt.graphics.Image;
34 import org.eclipse.swt.graphics.RGB;
35 import org.eclipse.swt.layout.FillLayout;
36 import org.eclipse.swt.layout.GridData;
37 import org.eclipse.swt.layout.GridLayout;
38 import org.eclipse.swt.widgets.Button;
39 import org.eclipse.swt.widgets.Composite;
40 import org.eclipse.swt.widgets.Display;
41 import org.eclipse.swt.widgets.Label;
42 import org.eclipse.swt.widgets.Text;
43 import org.simantics.db.ReadGraph;
44 import org.simantics.db.Resource;
45 import org.simantics.db.Session;
46 import org.simantics.db.Statement;
47 import org.simantics.db.WriteGraph;
48 import org.simantics.db.common.request.WriteRequest;
49 import org.simantics.db.exception.DatabaseException;
50 import org.simantics.db.request.Read;
51 import org.simantics.interop.test.GraphChanges;
52 import org.simantics.interop.update.Activator;
53 import org.simantics.interop.update.model.ModelUpdate;
54 import org.simantics.interop.update.model.PropertyChange;
55 import org.simantics.interop.update.model.ModelUpdate.WarningListener;
56 import org.simantics.interop.update.model.UpdateList;
57 import org.simantics.interop.update.model.UpdateNode;
58 import org.simantics.interop.update.model.UpdateOp;
59 import org.simantics.interop.update.model.UpdateStatus;
60 import org.simantics.interop.update.model.UpdateTree;
61 import org.simantics.interop.utils.TableUtils;
62 import org.simantics.ui.SimanticsUI;
63 import org.simantics.utils.datastructures.Callback;
64 import org.simantics.utils.datastructures.Pair;
65 import org.simantics.utils.ui.ExceptionUtils;
69 * Editor for updating models.
71 * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
74 public abstract class ModelUpdateEditor extends Composite implements WarningListener{
76 private Composite errorComposite;
78 private CheckboxTreeViewer changeBrowser;
79 private TableViewer changeViewer;
81 private Button updateAllButton;
82 private Button updateSelectedButton;
84 private LocalResourceManager manager = new LocalResourceManager(JFaceResources.getResources());
86 private Image checked;
87 private Image unchecked;
88 private Image warning;
90 private Color containsColor;
91 private Color deletedColor;
92 private Color addedColor;
94 private ModelUpdate update;
97 private HashSet<UpdateNode> selectedStructure = new HashSet<UpdateNode>();
99 public ModelUpdateEditor(Composite parent) {
100 super(parent,SWT.NONE);
101 checked = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/tick.png"));
102 unchecked = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/cross.png"));
103 warning = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/error.png"));
106 containsColor = new Color(parent.getDisplay(), new RGB(255,255,220));
107 deletedColor = new Color(parent.getDisplay(), new RGB(255,220,220));
108 addedColor = new Color(parent.getDisplay(), new RGB(220,255,220));
110 this.setLayout(new GridLayout(1,false));
112 errorComposite = new Composite(this, SWT.BORDER);
113 GridData data = new GridData();
114 data.grabExcessHorizontalSpace = true;
115 data.grabExcessVerticalSpace = false;
116 data.horizontalAlignment = SWT.FILL;
117 data.verticalAlignment = SWT.TOP;
118 errorComposite.setLayoutData(data);
119 errorComposite.setLayout(new GridLayout(2, false));
121 errorComposite.setVisible(false);
123 // IEditorInput input = getEditorInput();
124 // if (!(input instanceof UpdateEditorInput)) {
125 // Label label = new Label(composite, SWT.NONE);
126 // label.setText("Unknown input.");
130 Composite fillComposite = new Composite(this, SWT.NONE);
131 data = new GridData();
132 data.grabExcessHorizontalSpace = true;
133 data.grabExcessVerticalSpace = true;
134 data.horizontalAlignment = SWT.FILL;
135 data.verticalAlignment = SWT.FILL;
136 fillComposite.setLayoutData(data);
137 fillComposite.setLayout(new FillLayout(SWT.VERTICAL));
140 changeBrowser = new CheckboxTreeViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION );
142 changeBrowser.setContentProvider(new UpdateTreeContentProvider());
144 changeBrowser.getTree().setHeaderVisible(true);
146 ColumnViewerToolTipSupport.enableFor(changeBrowser);
149 TreeViewerColumn dataColumn = TableUtils.addColumn(changeBrowser, "Data", true, 600);
151 dataColumn.setLabelProvider(new UpdateNodeLabelProvider());
153 changeBrowser.addCheckStateListener(new ICheckStateListener() {
156 public void checkStateChanged(CheckStateChangedEvent event) {
157 UpdateNode node = (UpdateNode) event.getElement();
158 if (node.getOp() != null) {
159 node.getOp().select(Boolean.TRUE.equals(event.getChecked()));
166 changeBrowser.addTreeListener(new ITreeViewerListener() {
169 public void treeExpanded(TreeExpansionEvent event) {
170 event.getTreeViewer().getControl().getDisplay().asyncExec(new Runnable() {
174 // TreeViewer uses lazy load, checked states must be updated when the tree is expanded.
182 public void treeCollapsed(TreeExpansionEvent event) {
186 changeBrowser.setUseHashlookup(true);
190 changeViewer = new TableViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION);
192 changeViewer.getTable().setHeaderVisible(true);
193 changeViewer.getTable().setLinesVisible(true);
195 changeViewer.setContentProvider(new ModificationListContentProvider());
197 changeViewer.setUseHashlookup(true);
199 TableViewerColumn selection = TableUtils.addColumn(changeViewer, getColumntTitle(0), false, false, 20);
200 TableViewerColumn diagram = TableUtils.addColumn(changeViewer, getColumntTitle(1), true, true, 100);
201 TableViewerColumn symbol = TableUtils.addColumn(changeViewer, getColumntTitle(2), true, true, 100);
202 TableViewerColumn property = TableUtils.addColumn(changeViewer, getColumntTitle(3), true, true, 100);
203 TableViewerColumn oldValue = TableUtils.addColumn(changeViewer, getColumntTitle(4), true, true, 100);
204 TableViewerColumn newValue = TableUtils.addColumn(changeViewer, getColumntTitle(5), true, true, 100);
206 diagram.setLabelProvider(getLabelProvider(1));
207 symbol.setLabelProvider(getLabelProvider(2));
208 property.setLabelProvider(getLabelProvider(3));
209 oldValue.setLabelProvider(getLabelProvider(4));
210 newValue.setLabelProvider(getLabelProvider(5));
212 selection.setLabelProvider(new SelectionLabelProvider());
213 selection.getColumn().addSelectionListener(new SelectionAdapter() {
215 public void widgetSelected(SelectionEvent e) {
216 if (update.getUpdateList().getChanges().size() > 0) {
217 if (update.getUpdateList().getSelected().size() > 0) {
218 update.getUpdateList().clearSelected();
220 for (PropertyChange nr : update.getUpdateList().getChanges())
223 changeViewer.refresh();
227 selection.setEditingSupport(new SelectionEditingSupport(changeViewer));
230 Composite buttonComposite = new Composite(this, SWT.NONE);
232 data = new GridData();
233 data.grabExcessHorizontalSpace = true;
234 data.grabExcessVerticalSpace = false;
235 data.horizontalAlignment = SWT.FILL;
236 data.verticalAlignment = SWT.BOTTOM;
238 buttonComposite.setLayoutData(data);
240 buttonComposite.setLayout(new GridLayout(3, false));
242 Label label = new Label(buttonComposite, SWT.NONE);
243 data = new GridData();
244 data.grabExcessHorizontalSpace = true;
245 data.grabExcessVerticalSpace = false;
246 data.horizontalAlignment = SWT.FILL;
247 data.verticalAlignment = SWT.CENTER;
248 label.setLayoutData(data);
250 updateAllButton = new Button(buttonComposite, SWT.PUSH);
251 updateAllButton.setText("Update All");
252 updateAllButton.addSelectionListener(new SelectionAdapter() {
254 public void widgetSelected(SelectionEvent e) {
258 updateSelectedButton = new Button(buttonComposite, SWT.PUSH);
259 updateSelectedButton.setText("Update Selected");
260 updateSelectedButton.addSelectionListener(new SelectionAdapter() {
262 public void widgetSelected(SelectionEvent e) {
268 protected Session getSession() {
269 return SimanticsUI.getSession();
272 protected String getColumntTitle(int i) {
287 throw new RuntimeException("Unknown column index" + i);
292 protected abstract ColumnLabelProvider getLabelProvider(int i);
294 public GraphChanges getChanges() {
295 return update.getChanges();
298 public UpdateTree getUpdateTree() {
299 return update.getUpdateTree();
302 public UpdateList getUpdateList() {
303 return update.getUpdateList();
306 public CheckboxTreeViewer getChangeBrowser() {
307 return changeBrowser;
310 public TableViewer getChangeViewer() {
314 public void showWarning(ModelUpdate update, String text) {
315 errorComposite.setVisible(true);
317 Label label = new Label(errorComposite, SWT.NONE);
318 label.setImage(warning);
319 label = new Label(errorComposite, SWT.NONE);
321 //this.setStatusMessage("Update contains structural changes (new or deleted symbols), please create a new model.");
326 private List<ICheckStateListener> checkStateListeners = new ArrayList<>();
329 public void addCheckStateListener(ICheckStateListener listener) {
330 checkStateListeners.add(listener);
333 public void removeCheckStateListener(ICheckStateListener listener) {
334 checkStateListeners.remove(listener);
337 public void refreshChecked() {
338 Stack<UpdateNode> nodeStack = new Stack<UpdateNode>();
339 nodeStack.push((UpdateNode)update.getUpdateTree().getRootNode());
340 while (!nodeStack.isEmpty()) {
341 UpdateNode n = nodeStack.pop();
342 if (n.getOp() != null) {
343 UpdateOp op = n.getOp();
344 if (!op.isChange()) {
345 changeBrowser.setGrayed(n, true);
346 changeBrowser.setChecked(n, true);
348 boolean applied = op.applied();
350 changeBrowser.setChecked(n, true);
351 changeBrowser.setGrayed(n, true);
352 selectedStructure.remove(n);
354 boolean sel = op.selected();
356 selectedStructure.add(n);
359 selectedStructure.remove(n);
361 changeBrowser.setChecked(n, sel);
362 changeBrowser.setGrayed(n, false);
366 changeBrowser.setGrayed(n, true);
367 changeBrowser.setChecked(n, true);
369 for (UpdateNode c : n.getChildren()) {
370 nodeStack.add((UpdateNode)c);
374 changeBrowser.refresh();
375 for (ICheckStateListener l : checkStateListeners) {
376 l.checkStateChanged(new CheckStateChangedEvent(changeBrowser, null, false));
378 changeViewer.refresh();
381 protected abstract ModelUpdate createUpdate();
385 public void load(UpdateEditorInput uei) {
387 Resource oldModel = uei.getR1(); // old model that is being updated, contains user made changes
388 Resource newModel = uei.getR2(); // new model,
389 Resource originalModel = uei.getR3(); // original old model without user made changes
390 boolean newDistinct = uei.isNewDistinct();
393 update.removeListener(this);
394 update = createUpdate();
395 update.addListener(this);
396 update.setInput(oldModel, newModel, originalModel, newDistinct);
397 } catch (DatabaseException e) {
398 Text text = new Text(this, SWT.MULTI);
399 text.setText(e.getMessage());
409 protected void setInputs() {
410 changeViewer.setInput(update.getUpdateList().getChanges());
411 changeBrowser.setInput(update.getUpdateTree());
414 private void applyAll() {
415 updateAllButton.setEnabled(false);
416 updateSelectedButton.setEnabled(false);
417 getSession().asyncRequest(new WriteRequest(){
419 public void perform(WriteGraph graph) throws DatabaseException {
420 update.applyAll(graph);
422 Display.getDefault().asyncExec(new Runnable() {
427 updateAllButton.setEnabled(true);
428 updateSelectedButton.setEnabled(true);
430 changeViewer.refresh();
436 }, new Callback<DatabaseException>() {
438 public void run(DatabaseException parameter) {
439 if (parameter != null)
440 ExceptionUtils.logAndShowError("Cannot update model", parameter);
445 private void applySelected() {
446 updateAllButton.setEnabled(false);
447 updateSelectedButton.setEnabled(false);
448 getSession().asyncRequest(new WriteRequest(){
450 public void perform(WriteGraph graph) throws DatabaseException {
451 update.applySelected(graph);
453 Display.getDefault().asyncExec(new Runnable() {
457 changeViewer.refresh();
458 updateAllButton.setEnabled(true);
459 updateSelectedButton.setEnabled(true);
467 private class ModificationListContentProvider implements IStructuredContentProvider {
469 @SuppressWarnings("unchecked")
471 public Object[] getElements(Object inputElement) {
472 if (inputElement == null)
474 Collection<Pair<Statement, Statement>> coll = (Collection<Pair<Statement, Statement>>)inputElement;
475 return coll.toArray();
479 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
484 public void dispose() {
489 private class UpdateTreeContentProvider implements ITreeContentProvider {
491 public Object[] getElements(Object inputElement) {
492 if (inputElement instanceof UpdateTree)
493 return new Object[]{((UpdateTree)inputElement).getRootNode()};
494 if (inputElement instanceof UpdateNode) {
495 UpdateNode node = (UpdateNode)inputElement;
496 return node.getChildren().toArray();
498 return new Object[0];
502 public Object getParent(Object element) {
507 public Object[] getChildren(Object parentElement) {
508 UpdateNode node = (UpdateNode)parentElement;
509 return node.getChildren().toArray();
513 public boolean hasChildren(Object element) {
514 UpdateNode node = (UpdateNode)element;
515 return node.getChildren().size() > 0;
519 public void dispose() {
524 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
529 private class SelectionLabelProvider extends ColumnLabelProvider {
531 public SelectionLabelProvider() {
535 public String getText(Object element) {
540 public Image getImage(Object element) {
541 if (update == null || !update.isInit())
543 PropertyChange pc = (PropertyChange)element;
551 private class UpdateNodeLabelProvider extends ColumnLabelProvider {
554 public String getText(Object element) {
555 final UpdateNode node = (UpdateNode)element;
556 return node.getLabel();
560 public Image getImage(Object element) {
561 final UpdateNode node = (UpdateNode)element;
563 ImageDescriptor id = getSession().syncRequest(new Read<ImageDescriptor>() {
565 public ImageDescriptor perform(ReadGraph graph) throws DatabaseException {
566 return node.getImage(graph);
569 return manager.createImage(id);
570 } catch (Exception e) {
576 public String getToolTipText(Object element) {
577 final UpdateNode node = (UpdateNode)element;
578 if (node.getOp() != null) {
579 return node.getOp().toString();
586 public int getToolTipDisplayDelayTime(Object object) {
591 public int getToolTipTimeDisplayed(Object object) {
596 public Color getBackground(Object element) {
597 final UpdateNode node = (UpdateNode)element;
598 UpdateStatus status = node.getStatus();
599 if (status == UpdateStatus.CONTAINS)
600 return containsColor;
601 if (status == UpdateStatus.DELETED)
603 if (status == UpdateStatus.NEW)
609 private class SelectionEditingSupport extends EditingSupport {
612 @SuppressWarnings("rawtypes")
613 public SelectionEditingSupport(ColumnViewer viewer) {
619 protected boolean canEdit(Object element) {
624 protected CellEditor getCellEditor(Object element) {
625 return new CheckboxCellEditor(null, SWT.CHECK);
629 protected Object getValue(Object element) {
630 if (update == null || !update.isInit())
632 PropertyChange pc = (PropertyChange)element;
633 return pc.selected();
636 @SuppressWarnings("unchecked")
638 protected void setValue(Object element, Object value) {
639 if (update == null || !update.isInit())
641 PropertyChange pc = (PropertyChange)element;
642 if (Boolean.TRUE.equals(value))
647 getViewer().refresh(element);