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.Simantics;
44 import org.simantics.db.ReadGraph;
45 import org.simantics.db.Resource;
46 import org.simantics.db.Session;
47 import org.simantics.db.Statement;
48 import org.simantics.db.WriteGraph;
49 import org.simantics.db.common.request.WriteRequest;
50 import org.simantics.db.exception.DatabaseException;
51 import org.simantics.db.request.Read;
52 import org.simantics.interop.test.GraphChanges;
53 import org.simantics.interop.update.Activator;
54 import org.simantics.interop.update.model.ModelUpdate;
55 import org.simantics.interop.update.model.ModelUpdate.WarningListener;
56 import org.simantics.interop.update.model.PropertyChange;
57 import org.simantics.interop.update.model.UpdateList;
58 import org.simantics.interop.update.model.UpdateNode;
59 import org.simantics.interop.update.model.UpdateOp;
60 import org.simantics.interop.update.model.UpdateStatus;
61 import org.simantics.interop.update.model.UpdateTree;
62 import org.simantics.interop.utils.TableUtils;
63 import org.simantics.utils.datastructures.Pair;
64 import org.simantics.utils.ui.ExceptionUtils;
68 * Editor for updating models.
70 * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
73 public abstract class ModelUpdateEditor extends Composite implements WarningListener{
75 private Composite errorComposite;
77 private CheckboxTreeViewer changeBrowser;
78 private TableViewer changeViewer;
80 private Button updateAllButton;
81 private Button updateSelectedButton;
83 private LocalResourceManager manager = new LocalResourceManager(JFaceResources.getResources());
85 private Image checked;
86 private Image unchecked;
87 private Image warning;
89 private Color containsColor;
90 private Color deletedColor;
91 private Color addedColor;
93 private ModelUpdate update;
96 private HashSet<UpdateNode> selectedStructure = new HashSet<UpdateNode>();
98 public ModelUpdateEditor(Composite parent) {
99 super(parent,SWT.NONE);
100 checked = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/tick.png"));
101 unchecked = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/cross.png"));
102 warning = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/error.png"));
105 containsColor = new Color(parent.getDisplay(), new RGB(255,255,220));
106 deletedColor = new Color(parent.getDisplay(), new RGB(255,220,220));
107 addedColor = new Color(parent.getDisplay(), new RGB(220,255,220));
109 this.setLayout(new GridLayout(1,false));
111 errorComposite = new Composite(this, SWT.BORDER);
112 GridData data = new GridData();
113 data.grabExcessHorizontalSpace = true;
114 data.grabExcessVerticalSpace = false;
115 data.horizontalAlignment = SWT.FILL;
116 data.verticalAlignment = SWT.TOP;
117 errorComposite.setLayoutData(data);
118 errorComposite.setLayout(new GridLayout(2, false));
120 errorComposite.setVisible(false);
122 // IEditorInput input = getEditorInput();
123 // if (!(input instanceof UpdateEditorInput)) {
124 // Label label = new Label(composite, SWT.NONE);
125 // label.setText("Unknown input.");
129 Composite fillComposite = new Composite(this, SWT.NONE);
130 data = new GridData();
131 data.grabExcessHorizontalSpace = true;
132 data.grabExcessVerticalSpace = true;
133 data.horizontalAlignment = SWT.FILL;
134 data.verticalAlignment = SWT.FILL;
135 fillComposite.setLayoutData(data);
136 fillComposite.setLayout(new FillLayout(SWT.VERTICAL));
139 changeBrowser = new CheckboxTreeViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION );
141 changeBrowser.setContentProvider(new UpdateTreeContentProvider());
143 changeBrowser.getTree().setHeaderVisible(true);
145 ColumnViewerToolTipSupport.enableFor(changeBrowser);
148 TreeViewerColumn dataColumn = TableUtils.addColumn(changeBrowser, "Data", true, 600);
150 dataColumn.setLabelProvider(new UpdateNodeLabelProvider());
152 changeBrowser.addCheckStateListener(new ICheckStateListener() {
155 public void checkStateChanged(CheckStateChangedEvent event) {
156 UpdateNode node = (UpdateNode) event.getElement();
157 if (node.getOp() != null) {
158 node.getOp().select(Boolean.TRUE.equals(event.getChecked()));
165 changeBrowser.addTreeListener(new ITreeViewerListener() {
168 public void treeExpanded(TreeExpansionEvent event) {
169 event.getTreeViewer().getControl().getDisplay().asyncExec(new Runnable() {
173 // TreeViewer uses lazy load, checked states must be updated when the tree is expanded.
181 public void treeCollapsed(TreeExpansionEvent event) {
185 changeBrowser.setUseHashlookup(true);
189 changeViewer = new TableViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION);
191 changeViewer.getTable().setHeaderVisible(true);
192 changeViewer.getTable().setLinesVisible(true);
194 changeViewer.setContentProvider(new ModificationListContentProvider());
196 changeViewer.setUseHashlookup(true);
198 TableViewerColumn selection = TableUtils.addColumn(changeViewer, getColumntTitle(0), false, false, 20);
199 TableViewerColumn diagram = TableUtils.addColumn(changeViewer, getColumntTitle(1), true, true, 100);
200 TableViewerColumn symbol = TableUtils.addColumn(changeViewer, getColumntTitle(2), true, true, 100);
201 TableViewerColumn property = TableUtils.addColumn(changeViewer, getColumntTitle(3), true, true, 100);
202 TableViewerColumn oldValue = TableUtils.addColumn(changeViewer, getColumntTitle(4), true, true, 100);
203 TableViewerColumn newValue = TableUtils.addColumn(changeViewer, getColumntTitle(5), true, true, 100);
205 diagram.setLabelProvider(getLabelProvider(1));
206 symbol.setLabelProvider(getLabelProvider(2));
207 property.setLabelProvider(getLabelProvider(3));
208 oldValue.setLabelProvider(getLabelProvider(4));
209 newValue.setLabelProvider(getLabelProvider(5));
211 selection.setLabelProvider(new SelectionLabelProvider());
212 selection.getColumn().addSelectionListener(new SelectionAdapter() {
214 public void widgetSelected(SelectionEvent e) {
215 if (update.getUpdateList().getChanges().size() > 0) {
216 if (update.getUpdateList().getSelected().size() > 0) {
217 update.getUpdateList().clearSelected();
219 for (PropertyChange nr : update.getUpdateList().getChanges())
222 changeViewer.refresh();
226 selection.setEditingSupport(new SelectionEditingSupport(changeViewer));
229 Composite buttonComposite = new Composite(this, SWT.NONE);
231 data = new GridData();
232 data.grabExcessHorizontalSpace = true;
233 data.grabExcessVerticalSpace = false;
234 data.horizontalAlignment = SWT.FILL;
235 data.verticalAlignment = SWT.BOTTOM;
237 buttonComposite.setLayoutData(data);
239 buttonComposite.setLayout(new GridLayout(3, false));
241 Label label = new Label(buttonComposite, SWT.NONE);
242 data = new GridData();
243 data.grabExcessHorizontalSpace = true;
244 data.grabExcessVerticalSpace = false;
245 data.horizontalAlignment = SWT.FILL;
246 data.verticalAlignment = SWT.CENTER;
247 label.setLayoutData(data);
249 updateAllButton = new Button(buttonComposite, SWT.PUSH);
250 updateAllButton.setText("Update All");
251 updateAllButton.addSelectionListener(new SelectionAdapter() {
253 public void widgetSelected(SelectionEvent e) {
257 updateSelectedButton = new Button(buttonComposite, SWT.PUSH);
258 updateSelectedButton.setText("Update Selected");
259 updateSelectedButton.addSelectionListener(new SelectionAdapter() {
261 public void widgetSelected(SelectionEvent e) {
267 protected Session getSession() {
268 return Simantics.getSession();
271 protected String getColumntTitle(int i) {
286 throw new RuntimeException("Unknown column index" + i);
291 protected abstract ColumnLabelProvider getLabelProvider(int i);
293 public GraphChanges getChanges() {
294 return update.getChanges();
297 public UpdateTree getUpdateTree() {
298 return update.getUpdateTree();
301 public UpdateList getUpdateList() {
302 return update.getUpdateList();
305 public CheckboxTreeViewer getChangeBrowser() {
306 return changeBrowser;
309 public TableViewer getChangeViewer() {
313 public void showWarning(ModelUpdate update, String text) {
314 errorComposite.setVisible(true);
316 Label label = new Label(errorComposite, SWT.NONE);
317 label.setImage(warning);
318 label = new Label(errorComposite, SWT.NONE);
320 //this.setStatusMessage("Update contains structural changes (new or deleted symbols), please create a new model.");
325 private List<ICheckStateListener> checkStateListeners = new ArrayList<>();
328 public void addCheckStateListener(ICheckStateListener listener) {
329 checkStateListeners.add(listener);
332 public void removeCheckStateListener(ICheckStateListener listener) {
333 checkStateListeners.remove(listener);
336 public void refreshChecked() {
337 Stack<UpdateNode> nodeStack = new Stack<UpdateNode>();
338 nodeStack.push((UpdateNode)update.getUpdateTree().getRootNode());
339 while (!nodeStack.isEmpty()) {
340 UpdateNode n = nodeStack.pop();
341 if (n.getOp() != null) {
342 UpdateOp op = n.getOp();
343 if (!op.isChange()) {
344 changeBrowser.setGrayed(n, true);
345 changeBrowser.setChecked(n, true);
347 boolean applied = op.applied();
349 changeBrowser.setChecked(n, true);
350 changeBrowser.setGrayed(n, true);
351 selectedStructure.remove(n);
353 boolean sel = op.selected();
355 selectedStructure.add(n);
358 selectedStructure.remove(n);
360 changeBrowser.setChecked(n, sel);
361 changeBrowser.setGrayed(n, false);
365 changeBrowser.setGrayed(n, true);
366 changeBrowser.setChecked(n, true);
368 for (UpdateNode c : n.getChildren()) {
369 nodeStack.add((UpdateNode)c);
373 changeBrowser.refresh();
374 for (ICheckStateListener l : checkStateListeners) {
375 l.checkStateChanged(new CheckStateChangedEvent(changeBrowser, null, false));
377 changeViewer.refresh();
380 protected abstract ModelUpdate createUpdate();
384 public void load(UpdateEditorInput uei) {
386 Resource oldModel = uei.getR1(); // old model that is being updated, contains user made changes
387 Resource newModel = uei.getR2(); // new model,
388 Resource originalModel = uei.getR3(); // original old model without user made changes
389 boolean newDistinct = uei.isNewDistinct();
392 update.removeListener(this);
393 update = createUpdate();
394 update.addListener(this);
395 update.setInput(oldModel, newModel, originalModel, newDistinct);
396 } catch (DatabaseException e) {
397 Text text = new Text(this, SWT.MULTI);
398 text.setText(e.getMessage());
408 protected void setInputs() {
409 changeViewer.setInput(update.getUpdateList().getChanges());
410 changeBrowser.setInput(update.getUpdateTree());
413 private void applyAll() {
414 updateAllButton.setEnabled(false);
415 updateSelectedButton.setEnabled(false);
416 getSession().asyncRequest(new WriteRequest(){
418 public void perform(WriteGraph graph) throws DatabaseException {
419 update.applyAll(graph);
421 Display.getDefault().asyncExec(new Runnable() {
426 updateAllButton.setEnabled(true);
427 updateSelectedButton.setEnabled(true);
429 changeViewer.refresh();
437 ExceptionUtils.logAndShowError("Cannot update model", e);
441 private void applySelected() {
442 updateAllButton.setEnabled(false);
443 updateSelectedButton.setEnabled(false);
444 getSession().asyncRequest(new WriteRequest(){
446 public void perform(WriteGraph graph) throws DatabaseException {
447 update.applySelected(graph);
449 Display.getDefault().asyncExec(new Runnable() {
453 changeViewer.refresh();
454 updateAllButton.setEnabled(true);
455 updateSelectedButton.setEnabled(true);
463 private class ModificationListContentProvider implements IStructuredContentProvider {
465 @SuppressWarnings("unchecked")
467 public Object[] getElements(Object inputElement) {
468 if (inputElement == null)
470 Collection<Pair<Statement, Statement>> coll = (Collection<Pair<Statement, Statement>>)inputElement;
471 return coll.toArray();
475 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
480 public void dispose() {
485 private class UpdateTreeContentProvider implements ITreeContentProvider {
487 public Object[] getElements(Object inputElement) {
488 if (inputElement instanceof UpdateTree)
489 return new Object[]{((UpdateTree)inputElement).getRootNode()};
490 if (inputElement instanceof UpdateNode) {
491 UpdateNode node = (UpdateNode)inputElement;
492 return node.getChildren().toArray();
494 return new Object[0];
498 public Object getParent(Object element) {
503 public Object[] getChildren(Object parentElement) {
504 UpdateNode node = (UpdateNode)parentElement;
505 return node.getChildren().toArray();
509 public boolean hasChildren(Object element) {
510 UpdateNode node = (UpdateNode)element;
511 return node.getChildren().size() > 0;
515 public void dispose() {
520 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
525 private class SelectionLabelProvider extends ColumnLabelProvider {
527 public SelectionLabelProvider() {
531 public String getText(Object element) {
536 public Image getImage(Object element) {
537 if (update == null || !update.isInit())
539 PropertyChange pc = (PropertyChange)element;
547 private class UpdateNodeLabelProvider extends ColumnLabelProvider {
550 public String getText(Object element) {
551 final UpdateNode node = (UpdateNode)element;
552 return node.getLabel();
556 public Image getImage(Object element) {
557 final UpdateNode node = (UpdateNode)element;
559 ImageDescriptor id = getSession().syncRequest(new Read<ImageDescriptor>() {
561 public ImageDescriptor perform(ReadGraph graph) throws DatabaseException {
562 return node.getImage(graph);
565 return manager.createImage(id);
566 } catch (Exception e) {
572 public String getToolTipText(Object element) {
573 final UpdateNode node = (UpdateNode)element;
574 if (node.getOp() != null) {
575 return node.getOp().toString();
582 public int getToolTipDisplayDelayTime(Object object) {
587 public int getToolTipTimeDisplayed(Object object) {
592 public Color getBackground(Object element) {
593 final UpdateNode node = (UpdateNode)element;
594 UpdateStatus status = node.getStatus();
595 if (status == UpdateStatus.CONTAINS)
596 return containsColor;
597 if (status == UpdateStatus.DELETED)
599 if (status == UpdateStatus.NEW)
605 private class SelectionEditingSupport extends EditingSupport {
608 public SelectionEditingSupport(ColumnViewer viewer) {
613 protected boolean canEdit(Object element) {
618 protected CellEditor getCellEditor(Object element) {
619 return new CheckboxCellEditor(null, SWT.CHECK);
623 protected Object getValue(Object element) {
624 if (update == null || !update.isInit())
626 PropertyChange pc = (PropertyChange)element;
627 return pc.selected();
631 protected void setValue(Object element, Object value) {
632 if (update == null || !update.isInit())
634 PropertyChange pc = (PropertyChange)element;
635 if (Boolean.TRUE.equals(value))
640 getViewer().refresh(element);