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 cols[] = new TableViewerColumn[getChangeListColumnCount()];
199 TableViewerColumn selection = TableUtils.addColumn(changeViewer, getColumntTitle(0), false, false, getChangeListColumnWidth(0));
201 for (int i = 1 ; i < getChangeListColumnCount(); i++) {
202 TableViewerColumn column = TableUtils.addColumn(changeViewer, getColumntTitle(i), true, getChangeListColumnSortable(i), getChangeListColumnWidth(i));
204 column.setLabelProvider(getLabelProvider(i));
205 configureChangeListColumn(i, column);
208 selection.setLabelProvider(new SelectionLabelProvider());
209 selection.getColumn().addSelectionListener(new SelectionAdapter() {
211 public void widgetSelected(SelectionEvent e) {
212 if (update.getUpdateList().getChanges().size() > 0) {
213 if (update.getUpdateList().getSelected().size() > 0) {
214 update.getUpdateList().clearSelected();
216 for (PropertyChange nr : update.getUpdateList().getChanges())
219 changeViewer.refresh();
223 selection.setEditingSupport(new SelectionEditingSupport(changeViewer));
226 Composite buttonComposite = new Composite(this, SWT.NONE);
228 data = new GridData();
229 data.grabExcessHorizontalSpace = true;
230 data.grabExcessVerticalSpace = false;
231 data.horizontalAlignment = SWT.FILL;
232 data.verticalAlignment = SWT.BOTTOM;
234 buttonComposite.setLayoutData(data);
236 buttonComposite.setLayout(new GridLayout(3, false));
238 Label label = new Label(buttonComposite, SWT.NONE);
239 data = new GridData();
240 data.grabExcessHorizontalSpace = true;
241 data.grabExcessVerticalSpace = false;
242 data.horizontalAlignment = SWT.FILL;
243 data.verticalAlignment = SWT.CENTER;
244 label.setLayoutData(data);
246 updateAllButton = new Button(buttonComposite, SWT.PUSH);
247 updateAllButton.setText("Update All");
248 updateAllButton.addSelectionListener(new SelectionAdapter() {
250 public void widgetSelected(SelectionEvent e) {
254 updateSelectedButton = new Button(buttonComposite, SWT.PUSH);
255 updateSelectedButton.setText("Update Selected");
256 updateSelectedButton.addSelectionListener(new SelectionAdapter() {
258 public void widgetSelected(SelectionEvent e) {
264 protected int getChangeListColumnCount() {
268 protected int getChangeListColumnWidth(int col) {
274 protected boolean getChangeListColumnSortable(int col) {
280 protected void configureChangeListColumn(int col, TableViewerColumn column) {
284 protected Session getSession() {
285 return Simantics.getSession();
288 protected String getColumntTitle(int i) {
303 throw new RuntimeException("Unknown column index" + i);
308 protected abstract ColumnLabelProvider getLabelProvider(int i);
310 public GraphChanges getChanges() {
311 return update.getChanges();
314 public UpdateTree getUpdateTree() {
315 return update.getUpdateTree();
318 public UpdateList getUpdateList() {
319 return update.getUpdateList();
322 public CheckboxTreeViewer getChangeBrowser() {
323 return changeBrowser;
326 public TableViewer getChangeViewer() {
330 public void showWarning(ModelUpdate update, String text) {
331 errorComposite.setVisible(true);
333 Label label = new Label(errorComposite, SWT.NONE);
334 label.setImage(warning);
335 label = new Label(errorComposite, SWT.NONE);
337 //this.setStatusMessage("Update contains structural changes (new or deleted symbols), please create a new model.");
342 private List<ICheckStateListener> checkStateListeners = new ArrayList<>();
345 public void addCheckStateListener(ICheckStateListener listener) {
346 checkStateListeners.add(listener);
349 public void removeCheckStateListener(ICheckStateListener listener) {
350 checkStateListeners.remove(listener);
353 public void refreshChecked() {
354 Stack<UpdateNode> nodeStack = new Stack<UpdateNode>();
355 nodeStack.push((UpdateNode)update.getUpdateTree().getRootNode());
356 while (!nodeStack.isEmpty()) {
357 UpdateNode n = nodeStack.pop();
358 if (n.getOp() != null) {
359 UpdateOp op = n.getOp();
360 if (!op.isChange()) {
361 changeBrowser.setGrayed(n, true);
362 changeBrowser.setChecked(n, true);
364 boolean applied = op.applied();
366 changeBrowser.setChecked(n, true);
367 changeBrowser.setGrayed(n, true);
368 selectedStructure.remove(n);
370 boolean sel = op.selected();
372 selectedStructure.add(n);
375 selectedStructure.remove(n);
377 changeBrowser.setChecked(n, sel);
378 changeBrowser.setGrayed(n, false);
382 changeBrowser.setGrayed(n, true);
383 changeBrowser.setChecked(n, true);
385 for (UpdateNode c : n.getChildren()) {
386 nodeStack.add((UpdateNode)c);
390 changeBrowser.refresh();
391 for (ICheckStateListener l : checkStateListeners) {
392 l.checkStateChanged(new CheckStateChangedEvent(changeBrowser, null, false));
394 changeViewer.refresh();
397 protected abstract ModelUpdate createUpdate();
401 public void load(UpdateEditorInput uei) {
403 Resource oldModel = uei.getR1(); // old model that is being updated, contains user made changes
404 Resource newModel = uei.getR2(); // new model,
405 Resource originalModel = uei.getR3(); // original old model without user made changes
406 boolean newDistinct = uei.isNewDistinct();
409 update.removeListener(this);
410 update = createUpdate();
411 update.addListener(this);
412 update.setInput(oldModel, newModel, originalModel, newDistinct);
413 } catch (DatabaseException e) {
414 Text text = new Text(this, SWT.MULTI);
415 text.setText(e.getMessage());
425 protected void setInputs() {
426 changeViewer.setInput(update.getUpdateList().getChanges());
427 changeBrowser.setInput(update.getUpdateTree());
430 private void applyAll() {
431 updateAllButton.setEnabled(false);
432 updateSelectedButton.setEnabled(false);
433 getSession().asyncRequest(new WriteRequest(){
435 public void perform(WriteGraph graph) throws DatabaseException {
436 update.applyAll(graph);
438 Display.getDefault().asyncExec(new Runnable() {
443 updateAllButton.setEnabled(true);
444 updateSelectedButton.setEnabled(true);
446 changeViewer.refresh();
454 ExceptionUtils.logAndShowError("Cannot update model", e);
458 private void applySelected() {
459 updateAllButton.setEnabled(false);
460 updateSelectedButton.setEnabled(false);
461 getSession().asyncRequest(new WriteRequest(){
463 public void perform(WriteGraph graph) throws DatabaseException {
464 update.applySelected(graph);
466 Display.getDefault().asyncExec(new Runnable() {
470 changeViewer.refresh();
471 updateAllButton.setEnabled(true);
472 updateSelectedButton.setEnabled(true);
480 private class ModificationListContentProvider implements IStructuredContentProvider {
482 @SuppressWarnings("unchecked")
484 public Object[] getElements(Object inputElement) {
485 if (inputElement == null)
487 Collection<Pair<Statement, Statement>> coll = (Collection<Pair<Statement, Statement>>)inputElement;
488 return coll.toArray();
492 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
497 public void dispose() {
502 private class UpdateTreeContentProvider implements ITreeContentProvider {
504 public Object[] getElements(Object inputElement) {
505 if (inputElement instanceof UpdateTree)
506 return new Object[]{((UpdateTree)inputElement).getRootNode()};
507 if (inputElement instanceof UpdateNode) {
508 UpdateNode node = (UpdateNode)inputElement;
509 return node.getChildren().toArray();
511 return new Object[0];
515 public Object getParent(Object element) {
520 public Object[] getChildren(Object parentElement) {
521 UpdateNode node = (UpdateNode)parentElement;
522 return node.getChildren().toArray();
526 public boolean hasChildren(Object element) {
527 UpdateNode node = (UpdateNode)element;
528 return node.getChildren().size() > 0;
532 public void dispose() {
537 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
542 private class SelectionLabelProvider extends ColumnLabelProvider {
544 public SelectionLabelProvider() {
548 public String getText(Object element) {
553 public Image getImage(Object element) {
554 if (update == null || !update.isInit())
556 PropertyChange pc = (PropertyChange)element;
564 private class UpdateNodeLabelProvider extends ColumnLabelProvider {
567 public String getText(Object element) {
568 final UpdateNode node = (UpdateNode)element;
569 return node.getLabel();
573 public Image getImage(Object element) {
574 final UpdateNode node = (UpdateNode)element;
576 ImageDescriptor id = getSession().syncRequest(new Read<ImageDescriptor>() {
578 public ImageDescriptor perform(ReadGraph graph) throws DatabaseException {
579 return node.getImage(graph);
582 return manager.createImage(id);
583 } catch (Exception e) {
589 public String getToolTipText(Object element) {
590 final UpdateNode node = (UpdateNode)element;
591 if (node.getOp() != null) {
592 return node.getOp().toString();
599 public int getToolTipDisplayDelayTime(Object object) {
604 public int getToolTipTimeDisplayed(Object object) {
609 public Color getBackground(Object element) {
610 final UpdateNode node = (UpdateNode)element;
611 UpdateStatus status = node.getStatus();
612 if (status == UpdateStatus.CONTAINS)
613 return containsColor;
614 if (status == UpdateStatus.DELETED)
616 if (status == UpdateStatus.NEW)
622 private class SelectionEditingSupport extends EditingSupport {
625 public SelectionEditingSupport(ColumnViewer viewer) {
630 protected boolean canEdit(Object element) {
635 protected CellEditor getCellEditor(Object element) {
636 return new CheckboxCellEditor(null, SWT.CHECK);
640 protected Object getValue(Object element) {
641 if (update == null || !update.isInit())
643 PropertyChange pc = (PropertyChange)element;
644 return pc.selected();
648 protected void setValue(Object element, Object value) {
649 if (update == null || !update.isInit())
651 PropertyChange pc = (PropertyChange)element;
652 if (Boolean.TRUE.equals(value))
657 getViewer().refresh(element);