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 unchecked = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/cross.png"));
104 warning = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/error.png"));
107 containsColor = new Color(parent.getDisplay(), new RGB(255,255,220));
108 deletedColor = new Color(parent.getDisplay(), new RGB(255,220,220));
109 addedColor = new Color(parent.getDisplay(), new RGB(220,255,220));
110 disabledColor = new Color(parent.getDisplay(), new RGB(128,128,128));
112 this.setLayout(new GridLayout(1,false));
114 errorComposite = new Composite(this, SWT.BORDER);
115 GridData data = new GridData();
116 data.grabExcessHorizontalSpace = true;
117 data.grabExcessVerticalSpace = false;
118 data.horizontalAlignment = SWT.FILL;
119 data.verticalAlignment = SWT.TOP;
120 errorComposite.setLayoutData(data);
121 errorComposite.setLayout(new GridLayout(2, false));
123 errorComposite.setVisible(false);
125 // IEditorInput input = getEditorInput();
126 // if (!(input instanceof UpdateEditorInput)) {
127 // Label label = new Label(composite, SWT.NONE);
128 // label.setText("Unknown input.");
132 Composite fillComposite = new Composite(this, SWT.NONE);
133 data = new GridData();
134 data.grabExcessHorizontalSpace = true;
135 data.grabExcessVerticalSpace = true;
136 data.horizontalAlignment = SWT.FILL;
137 data.verticalAlignment = SWT.FILL;
138 fillComposite.setLayoutData(data);
139 fillComposite.setLayout(new FillLayout(SWT.VERTICAL));
142 changeBrowser = new CheckboxTreeViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION );
144 changeBrowser.setContentProvider(new UpdateTreeContentProvider());
146 changeBrowser.getTree().setHeaderVisible(true);
148 ColumnViewerToolTipSupport.enableFor(changeBrowser);
151 TreeViewerColumn dataColumn = TableUtils.addColumn(changeBrowser, "Data", true, 600);
153 dataColumn.setLabelProvider(new UpdateNodeLabelProvider());
155 changeBrowser.addCheckStateListener(new ICheckStateListener() {
158 public void checkStateChanged(CheckStateChangedEvent event) {
159 UpdateNode node = (UpdateNode) event.getElement();
160 if (node.getOp() != null) {
161 node.getOp().select(Boolean.TRUE.equals(event.getChecked()));
168 changeBrowser.addTreeListener(new ITreeViewerListener() {
171 public void treeExpanded(TreeExpansionEvent event) {
172 event.getTreeViewer().getControl().getDisplay().asyncExec(new Runnable() {
176 // TreeViewer uses lazy load, checked states must be updated when the tree is expanded.
184 public void treeCollapsed(TreeExpansionEvent event) {
188 changeBrowser.setUseHashlookup(true);
192 changeViewer = new TableViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION);
194 changeViewer.getTable().setHeaderVisible(true);
195 changeViewer.getTable().setLinesVisible(true);
197 changeViewer.setContentProvider(new ModificationListContentProvider());
199 changeViewer.setUseHashlookup(true);
201 TableViewerColumn cols[] = new TableViewerColumn[getChangeListColumnCount()];
202 TableViewerColumn selection = TableUtils.addColumn(changeViewer, getColumntTitle(0), false, false, getChangeListColumnWidth(0));
204 for (int i = 1 ; i < getChangeListColumnCount(); i++) {
205 TableViewerColumn column = TableUtils.addColumn(changeViewer, getColumntTitle(i), true, getChangeListColumnSortable(i), getChangeListColumnWidth(i));
207 column.setLabelProvider(getLabelProvider(i));
208 configureChangeListColumn(i, column);
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 int getChangeListColumnCount() {
271 protected int getChangeListColumnWidth(int col) {
277 protected boolean getChangeListColumnSortable(int col) {
283 protected void configureChangeListColumn(int col, TableViewerColumn column) {
287 protected Session getSession() {
288 return Simantics.getSession();
291 protected String getColumntTitle(int i) {
306 throw new RuntimeException("Unknown column index" + i);
311 protected abstract ColumnLabelProvider getLabelProvider(int i);
313 public GraphChanges getChanges() {
314 return update.getChanges();
317 public UpdateTree getUpdateTree() {
318 return update.getUpdateTree();
321 public UpdateList getUpdateList() {
322 return update.getUpdateList();
325 public CheckboxTreeViewer getChangeBrowser() {
326 return changeBrowser;
329 public TableViewer getChangeViewer() {
333 public void showWarning(ModelUpdate update, String text) {
334 errorComposite.setVisible(true);
336 Label label = new Label(errorComposite, SWT.NONE);
337 label.setImage(warning);
338 label = new Label(errorComposite, SWT.NONE);
340 //this.setStatusMessage("Update contains structural changes (new or deleted symbols), please create a new model.");
345 private List<ICheckStateListener> checkStateListeners = new ArrayList<>();
348 public void addCheckStateListener(ICheckStateListener listener) {
349 checkStateListeners.add(listener);
352 public void removeCheckStateListener(ICheckStateListener listener) {
353 checkStateListeners.remove(listener);
356 public void refreshChecked() {
357 Stack<UpdateNode> nodeStack = new Stack<UpdateNode>();
358 nodeStack.push((UpdateNode)update.getUpdateTree().getRootNode());
359 while (!nodeStack.isEmpty()) {
360 UpdateNode n = nodeStack.pop();
361 if (n.getOp() != null) {
362 UpdateOp op = n.getOp();
363 if (!op.isChange()) {
364 changeBrowser.setGrayed(n, true);
365 changeBrowser.setChecked(n, true);
367 boolean applied = op.applied();
369 changeBrowser.setChecked(n, true);
370 changeBrowser.setGrayed(n, true);
371 selectedStructure.remove(n);
373 boolean sel = op.selected();
375 selectedStructure.add(n);
378 selectedStructure.remove(n);
380 changeBrowser.setChecked(n, sel);
381 changeBrowser.setGrayed(n, !op.enabled());
385 changeBrowser.setGrayed(n, true);
386 changeBrowser.setChecked(n, true);
388 for (UpdateNode c : n.getChildren()) {
389 nodeStack.add((UpdateNode)c);
393 changeBrowser.refresh();
394 for (ICheckStateListener l : checkStateListeners) {
395 l.checkStateChanged(new CheckStateChangedEvent(changeBrowser, null, false));
397 changeViewer.refresh();
400 protected abstract ModelUpdate createUpdate();
404 public void load(UpdateEditorInput uei) {
406 Resource oldModel = uei.getR1(); // old model that is being updated, contains user made changes
407 Resource newModel = uei.getR2(); // new model,
408 Resource originalModel = uei.getR3(); // original old model without user made changes
409 boolean newDistinct = uei.isNewDistinct();
412 update.removeListener(this);
413 update = createUpdate();
414 update.addListener(this);
415 update.setInput(oldModel, newModel, originalModel, newDistinct);
416 } catch (DatabaseException e) {
417 Text text = new Text(this, SWT.MULTI);
418 text.setText(e.getMessage());
428 protected void setInputs() {
429 changeViewer.setInput(update.getUpdateList().getChanges());
430 changeBrowser.setInput(update.getUpdateTree());
431 updateAllButton.setEnabled(true);
432 updateSelectedButton.setEnabled(true);
435 private void applyAll() {
436 updateAllButton.setEnabled(false);
437 updateSelectedButton.setEnabled(false);
438 getSession().asyncRequest(new WriteRequest(){
440 public void perform(WriteGraph graph) throws DatabaseException {
441 update.applyAll(graph);
443 Display.getDefault().asyncExec(new Runnable() {
448 updateAllButton.setEnabled(true);
449 updateSelectedButton.setEnabled(true);
451 changeViewer.refresh();
459 ExceptionUtils.logAndShowError("Cannot update model", e);
463 private void applySelected() {
464 updateAllButton.setEnabled(false);
465 updateSelectedButton.setEnabled(false);
466 getSession().asyncRequest(new WriteRequest(){
468 public void perform(WriteGraph graph) throws DatabaseException {
469 update.applySelected(graph);
471 Display.getDefault().asyncExec(new Runnable() {
475 changeViewer.refresh();
476 updateAllButton.setEnabled(true);
477 updateSelectedButton.setEnabled(true);
485 private class ModificationListContentProvider implements IStructuredContentProvider {
487 @SuppressWarnings("unchecked")
489 public Object[] getElements(Object inputElement) {
490 if (inputElement == null)
492 Collection<Pair<Statement, Statement>> coll = (Collection<Pair<Statement, Statement>>)inputElement;
493 return coll.toArray();
497 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
502 public void dispose() {
507 private class UpdateTreeContentProvider implements ITreeContentProvider {
509 public Object[] getElements(Object inputElement) {
510 if (inputElement instanceof UpdateTree)
511 return new Object[]{((UpdateTree)inputElement).getRootNode()};
512 if (inputElement instanceof UpdateNode) {
513 UpdateNode node = (UpdateNode)inputElement;
514 return node.getChildren().toArray();
516 return new Object[0];
520 public Object getParent(Object element) {
525 public Object[] getChildren(Object parentElement) {
526 UpdateNode node = (UpdateNode)parentElement;
527 return node.getChildren().toArray();
531 public boolean hasChildren(Object element) {
532 UpdateNode node = (UpdateNode)element;
533 return node.getChildren().size() > 0;
537 public void dispose() {
542 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
547 private class SelectionLabelProvider extends ColumnLabelProvider {
549 public SelectionLabelProvider() {
553 public String getText(Object element) {
558 public Image getImage(Object element) {
559 if (update == null || !update.isInit())
561 PropertyChange pc = (PropertyChange)element;
571 public Color getForeground(Object element) {
572 PropertyChange pc = (PropertyChange)element;
574 return disabledColor;
579 protected abstract class PropertyChangeLabelProvider extends ColumnLabelProvider {
581 public PropertyChangeLabelProvider() {
586 public Color getForeground(Object element) {
587 PropertyChange pc = (PropertyChange)element;
589 return disabledColor;
594 private class UpdateNodeLabelProvider extends ColumnLabelProvider {
597 public String getText(Object element) {
598 final UpdateNode node = (UpdateNode)element;
599 return node.getLabel();
603 public Image getImage(Object element) {
604 final UpdateNode node = (UpdateNode)element;
606 ImageDescriptor id = getSession().syncRequest(new Read<ImageDescriptor>() {
608 public ImageDescriptor perform(ReadGraph graph) throws DatabaseException {
609 return node.getImage(graph);
612 return manager.createImage(id);
613 } catch (Exception e) {
619 public String getToolTipText(Object element) {
620 final UpdateNode node = (UpdateNode)element;
621 if (node.getOp() != null) {
622 return node.getOp().toString();
629 public int getToolTipDisplayDelayTime(Object object) {
634 public int getToolTipTimeDisplayed(Object object) {
639 public Color getBackground(Object element) {
640 final UpdateNode node = (UpdateNode)element;
641 UpdateStatus status = node.getStatus();
642 if (status == UpdateStatus.CONTAINS)
643 return containsColor;
644 if (status == UpdateStatus.DELETED)
646 if (status == UpdateStatus.NEW)
652 public Color getForeground(Object element) {
653 final UpdateNode node = (UpdateNode)element;
654 if (node.getOp() != null && !node.getOp().enabled())
655 return disabledColor;
660 private class SelectionEditingSupport extends EditingSupport {
663 public SelectionEditingSupport(ColumnViewer viewer) {
668 protected boolean canEdit(Object element) {
673 protected CellEditor getCellEditor(Object element) {
674 return new CheckboxCellEditor(null, SWT.CHECK);
678 protected Object getValue(Object element) {
679 if (update == null || !update.isInit())
681 PropertyChange pc = (PropertyChange)element;
682 return pc.selected();
686 protected void setValue(Object element, Object value) {
687 if (update == null || !update.isInit())
689 PropertyChange pc = (PropertyChange)element;
690 if (Boolean.TRUE.equals(value))
695 getViewer().refresh(element);