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;
92 private Color disabledColor;
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));
109 disabledColor = new Color(parent.getDisplay(), new RGB(128,128,128));
111 this.setLayout(new GridLayout(1,false));
113 errorComposite = new Composite(this, SWT.BORDER);
114 GridData data = new GridData();
115 data.grabExcessHorizontalSpace = true;
116 data.grabExcessVerticalSpace = false;
117 data.horizontalAlignment = SWT.FILL;
118 data.verticalAlignment = SWT.TOP;
119 errorComposite.setLayoutData(data);
120 errorComposite.setLayout(new GridLayout(2, false));
122 errorComposite.setVisible(false);
124 // IEditorInput input = getEditorInput();
125 // if (!(input instanceof UpdateEditorInput)) {
126 // Label label = new Label(composite, SWT.NONE);
127 // label.setText("Unknown input.");
131 Composite fillComposite = new Composite(this, SWT.NONE);
132 data = new GridData();
133 data.grabExcessHorizontalSpace = true;
134 data.grabExcessVerticalSpace = true;
135 data.horizontalAlignment = SWT.FILL;
136 data.verticalAlignment = SWT.FILL;
137 fillComposite.setLayoutData(data);
138 fillComposite.setLayout(new FillLayout(SWT.VERTICAL));
141 changeBrowser = new CheckboxTreeViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION );
143 changeBrowser.setContentProvider(new UpdateTreeContentProvider());
145 changeBrowser.getTree().setHeaderVisible(true);
147 ColumnViewerToolTipSupport.enableFor(changeBrowser);
150 TreeViewerColumn dataColumn = TableUtils.addColumn(changeBrowser, "Data", true, 600);
152 dataColumn.setLabelProvider(new UpdateNodeLabelProvider());
154 changeBrowser.addCheckStateListener(new ICheckStateListener() {
157 public void checkStateChanged(CheckStateChangedEvent event) {
158 UpdateNode node = (UpdateNode) event.getElement();
159 if (node.getOp() != null) {
160 node.getOp().select(Boolean.TRUE.equals(event.getChecked()));
167 changeBrowser.addTreeListener(new ITreeViewerListener() {
170 public void treeExpanded(TreeExpansionEvent event) {
171 event.getTreeViewer().getControl().getDisplay().asyncExec(new Runnable() {
175 // TreeViewer uses lazy load, checked states must be updated when the tree is expanded.
183 public void treeCollapsed(TreeExpansionEvent event) {
187 changeBrowser.setUseHashlookup(true);
191 changeViewer = new TableViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION);
193 changeViewer.getTable().setHeaderVisible(true);
194 changeViewer.getTable().setLinesVisible(true);
196 changeViewer.setContentProvider(new ModificationListContentProvider());
198 changeViewer.setUseHashlookup(true);
200 TableViewerColumn cols[] = new TableViewerColumn[getChangeListColumnCount()];
201 TableViewerColumn selection = TableUtils.addColumn(changeViewer, getColumntTitle(0), false, false, getChangeListColumnWidth(0));
203 for (int i = 1 ; i < getChangeListColumnCount(); i++) {
204 TableViewerColumn column = TableUtils.addColumn(changeViewer, getColumntTitle(i), true, getChangeListColumnSortable(i), getChangeListColumnWidth(i));
206 column.setLabelProvider(getLabelProvider(i));
207 configureChangeListColumn(i, column);
210 selection.setLabelProvider(new SelectionLabelProvider());
211 selection.getColumn().addSelectionListener(new SelectionAdapter() {
213 public void widgetSelected(SelectionEvent e) {
214 if (update.getUpdateList().getChanges().size() > 0) {
215 if (update.getUpdateList().getSelected().size() > 0) {
216 update.getUpdateList().clearSelected();
218 for (PropertyChange nr : update.getUpdateList().getChanges())
221 changeViewer.refresh();
225 selection.setEditingSupport(new SelectionEditingSupport(changeViewer));
228 Composite buttonComposite = new Composite(this, SWT.NONE);
230 data = new GridData();
231 data.grabExcessHorizontalSpace = true;
232 data.grabExcessVerticalSpace = false;
233 data.horizontalAlignment = SWT.FILL;
234 data.verticalAlignment = SWT.BOTTOM;
236 buttonComposite.setLayoutData(data);
238 buttonComposite.setLayout(new GridLayout(3, false));
240 Label label = new Label(buttonComposite, SWT.NONE);
241 data = new GridData();
242 data.grabExcessHorizontalSpace = true;
243 data.grabExcessVerticalSpace = false;
244 data.horizontalAlignment = SWT.FILL;
245 data.verticalAlignment = SWT.CENTER;
246 label.setLayoutData(data);
248 updateAllButton = new Button(buttonComposite, SWT.PUSH);
249 updateAllButton.setText("Update All");
250 updateAllButton.addSelectionListener(new SelectionAdapter() {
252 public void widgetSelected(SelectionEvent e) {
256 updateSelectedButton = new Button(buttonComposite, SWT.PUSH);
257 updateSelectedButton.setText("Update Selected");
258 updateSelectedButton.addSelectionListener(new SelectionAdapter() {
260 public void widgetSelected(SelectionEvent e) {
266 protected int getChangeListColumnCount() {
270 protected int getChangeListColumnWidth(int col) {
276 protected boolean getChangeListColumnSortable(int col) {
282 protected void configureChangeListColumn(int col, TableViewerColumn column) {
286 protected Session getSession() {
287 return Simantics.getSession();
290 protected String getColumntTitle(int i) {
305 throw new RuntimeException("Unknown column index" + i);
310 protected abstract ColumnLabelProvider getLabelProvider(int i);
312 public GraphChanges getChanges() {
313 return update.getChanges();
316 public UpdateTree getUpdateTree() {
317 return update.getUpdateTree();
320 public UpdateList getUpdateList() {
321 return update.getUpdateList();
324 public CheckboxTreeViewer getChangeBrowser() {
325 return changeBrowser;
328 public TableViewer getChangeViewer() {
332 public void showWarning(ModelUpdate update, String text) {
333 errorComposite.setVisible(true);
335 Label label = new Label(errorComposite, SWT.NONE);
336 label.setImage(warning);
337 label = new Label(errorComposite, SWT.NONE);
339 //this.setStatusMessage("Update contains structural changes (new or deleted symbols), please create a new model.");
344 private List<ICheckStateListener> checkStateListeners = new ArrayList<>();
347 public void addCheckStateListener(ICheckStateListener listener) {
348 checkStateListeners.add(listener);
351 public void removeCheckStateListener(ICheckStateListener listener) {
352 checkStateListeners.remove(listener);
355 public void refreshChecked() {
356 Stack<UpdateNode> nodeStack = new Stack<UpdateNode>();
357 nodeStack.push((UpdateNode)update.getUpdateTree().getRootNode());
358 while (!nodeStack.isEmpty()) {
359 UpdateNode n = nodeStack.pop();
360 if (n.getOp() != null) {
361 UpdateOp op = n.getOp();
362 if (!op.isChange()) {
363 changeBrowser.setGrayed(n, true);
364 changeBrowser.setChecked(n, true);
366 boolean applied = op.applied();
368 changeBrowser.setChecked(n, true);
369 changeBrowser.setGrayed(n, true);
370 selectedStructure.remove(n);
372 boolean sel = op.selected();
374 selectedStructure.add(n);
377 selectedStructure.remove(n);
379 changeBrowser.setChecked(n, sel);
380 changeBrowser.setGrayed(n, !op.enabled());
384 changeBrowser.setGrayed(n, true);
385 changeBrowser.setChecked(n, true);
387 for (UpdateNode c : n.getChildren()) {
388 nodeStack.add((UpdateNode)c);
392 changeBrowser.refresh();
393 for (ICheckStateListener l : checkStateListeners) {
394 l.checkStateChanged(new CheckStateChangedEvent(changeBrowser, null, false));
396 changeViewer.refresh();
399 protected abstract ModelUpdate createUpdate();
403 public void load(UpdateEditorInput uei) {
405 Resource oldModel = uei.getR1(); // old model that is being updated, contains user made changes
406 Resource newModel = uei.getR2(); // new model,
407 Resource originalModel = uei.getR3(); // original old model without user made changes
408 boolean newDistinct = uei.isNewDistinct();
411 update.removeListener(this);
412 update = createUpdate();
413 update.addListener(this);
414 update.setInput(oldModel, newModel, originalModel, newDistinct);
415 } catch (DatabaseException e) {
416 Text text = new Text(this, SWT.MULTI);
417 text.setText(e.getMessage());
427 protected void setInputs() {
428 changeViewer.setInput(update.getUpdateList().getChanges());
429 changeBrowser.setInput(update.getUpdateTree());
432 private void applyAll() {
433 updateAllButton.setEnabled(false);
434 updateSelectedButton.setEnabled(false);
435 getSession().asyncRequest(new WriteRequest(){
437 public void perform(WriteGraph graph) throws DatabaseException {
438 update.applyAll(graph);
440 Display.getDefault().asyncExec(new Runnable() {
445 updateAllButton.setEnabled(true);
446 updateSelectedButton.setEnabled(true);
448 changeViewer.refresh();
456 ExceptionUtils.logAndShowError("Cannot update model", e);
460 private void applySelected() {
461 updateAllButton.setEnabled(false);
462 updateSelectedButton.setEnabled(false);
463 getSession().asyncRequest(new WriteRequest(){
465 public void perform(WriteGraph graph) throws DatabaseException {
466 update.applySelected(graph);
468 Display.getDefault().asyncExec(new Runnable() {
472 changeViewer.refresh();
473 updateAllButton.setEnabled(true);
474 updateSelectedButton.setEnabled(true);
482 private class ModificationListContentProvider implements IStructuredContentProvider {
484 @SuppressWarnings("unchecked")
486 public Object[] getElements(Object inputElement) {
487 if (inputElement == null)
489 Collection<Pair<Statement, Statement>> coll = (Collection<Pair<Statement, Statement>>)inputElement;
490 return coll.toArray();
494 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
499 public void dispose() {
504 private class UpdateTreeContentProvider implements ITreeContentProvider {
506 public Object[] getElements(Object inputElement) {
507 if (inputElement instanceof UpdateTree)
508 return new Object[]{((UpdateTree)inputElement).getRootNode()};
509 if (inputElement instanceof UpdateNode) {
510 UpdateNode node = (UpdateNode)inputElement;
511 return node.getChildren().toArray();
513 return new Object[0];
517 public Object getParent(Object element) {
522 public Object[] getChildren(Object parentElement) {
523 UpdateNode node = (UpdateNode)parentElement;
524 return node.getChildren().toArray();
528 public boolean hasChildren(Object element) {
529 UpdateNode node = (UpdateNode)element;
530 return node.getChildren().size() > 0;
534 public void dispose() {
539 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
544 private class SelectionLabelProvider extends ColumnLabelProvider {
546 public SelectionLabelProvider() {
550 public String getText(Object element) {
555 public Image getImage(Object element) {
556 if (update == null || !update.isInit())
558 PropertyChange pc = (PropertyChange)element;
566 public Color getForeground(Object element) {
567 PropertyChange pc = (PropertyChange)element;
569 return disabledColor;
574 protected abstract class PropertyChangeLabelProvider extends ColumnLabelProvider {
576 public PropertyChangeLabelProvider() {
581 public Color getForeground(Object element) {
582 PropertyChange pc = (PropertyChange)element;
584 return disabledColor;
589 private class UpdateNodeLabelProvider extends ColumnLabelProvider {
592 public String getText(Object element) {
593 final UpdateNode node = (UpdateNode)element;
594 return node.getLabel();
598 public Image getImage(Object element) {
599 final UpdateNode node = (UpdateNode)element;
601 ImageDescriptor id = getSession().syncRequest(new Read<ImageDescriptor>() {
603 public ImageDescriptor perform(ReadGraph graph) throws DatabaseException {
604 return node.getImage(graph);
607 return manager.createImage(id);
608 } catch (Exception e) {
614 public String getToolTipText(Object element) {
615 final UpdateNode node = (UpdateNode)element;
616 if (node.getOp() != null) {
617 return node.getOp().toString();
624 public int getToolTipDisplayDelayTime(Object object) {
629 public int getToolTipTimeDisplayed(Object object) {
634 public Color getBackground(Object element) {
635 final UpdateNode node = (UpdateNode)element;
636 UpdateStatus status = node.getStatus();
637 if (status == UpdateStatus.CONTAINS)
638 return containsColor;
639 if (status == UpdateStatus.DELETED)
641 if (status == UpdateStatus.NEW)
647 public Color getForeground(Object element) {
648 final UpdateNode node = (UpdateNode)element;
649 if (node.getOp() != null && !node.getOp().enabled())
650 return disabledColor;
655 private class SelectionEditingSupport extends EditingSupport {
658 public SelectionEditingSupport(ColumnViewer viewer) {
663 protected boolean canEdit(Object element) {
668 protected CellEditor getCellEditor(Object element) {
669 return new CheckboxCellEditor(null, SWT.CHECK);
673 protected Object getValue(Object element) {
674 if (update == null || !update.isInit())
676 PropertyChange pc = (PropertyChange)element;
677 return pc.selected();
681 protected void setValue(Object element, Object value) {
682 if (update == null || !update.isInit())
684 PropertyChange pc = (PropertyChange)element;
685 if (Boolean.TRUE.equals(value))
690 getViewer().refresh(element);