]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.interop.update/src/org/simantics/interop/update/editor/ModelUpdateEditor.java
PropertyChange class (instead of Pair)
[simantics/interop.git] / org.simantics.interop.update / src / org / simantics / interop / update / editor / ModelUpdateEditor.java
1 package org.simantics.interop.update.editor;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashSet;
6 import java.util.List;
7 import java.util.Stack;
8
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;
66
67
68 /**
69  * Editor for updating models.
70  * 
71  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
72  *
73  */
74 public abstract class ModelUpdateEditor extends Composite implements WarningListener{
75
76         private Composite errorComposite;
77         
78         private CheckboxTreeViewer changeBrowser;
79         private TableViewer changeViewer;
80         
81         private Button updateAllButton;
82         private Button updateSelectedButton;
83         
84         private LocalResourceManager manager = new LocalResourceManager(JFaceResources.getResources());
85         
86         private Image checked;
87         private Image unchecked;
88         private Image warning;
89         
90         private Color containsColor;
91         private Color deletedColor;
92         private Color addedColor;
93
94         private ModelUpdate update;
95         
96         
97         private HashSet<UpdateNode> selectedStructure = new HashSet<UpdateNode>();
98         
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"));
104
105                 
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                 
110                 this.setLayout(new GridLayout(1,false));
111                 
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));
120                 
121                 errorComposite.setVisible(false);
122
123 //              IEditorInput input = getEditorInput();
124 //              if (!(input instanceof UpdateEditorInput)) {
125 //                      Label label = new Label(composite, SWT.NONE);
126 //                      label.setText("Unknown input.");
127 //                      return;
128 //              }
129                 
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));
138
139                 {
140                         changeBrowser = new CheckboxTreeViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION  );
141                         
142                         changeBrowser.setContentProvider(new UpdateTreeContentProvider());
143                         
144                         changeBrowser.getTree().setHeaderVisible(true);
145                         
146                         ColumnViewerToolTipSupport.enableFor(changeBrowser);
147
148                         
149                         TreeViewerColumn dataColumn = TableUtils.addColumn(changeBrowser, "Data", true, 600);
150
151                         dataColumn.setLabelProvider(new UpdateNodeLabelProvider());
152                         
153                         changeBrowser.addCheckStateListener(new ICheckStateListener() {
154                                 
155                                 @Override
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()));
160                                                 
161                                         }
162                                         refreshChecked();
163                                         
164                                 }
165                         });
166                         changeBrowser.addTreeListener(new ITreeViewerListener() {
167                                 
168                                 @Override
169                                 public void treeExpanded(TreeExpansionEvent event) {
170                                         event.getTreeViewer().getControl().getDisplay().asyncExec(new Runnable() {
171                                                 
172                                                 @Override
173                                                 public void run() {
174                                                         // TreeViewer uses lazy load, checked states must be updated when the tree is expanded. 
175                                                         refreshChecked();
176                                                 }
177                                         });
178                                         
179                                 }
180                                 
181                                 @Override
182                                 public void treeCollapsed(TreeExpansionEvent event) {
183                                         
184                                 }
185                         });
186                         changeBrowser.setUseHashlookup(true);
187                         
188                 }
189                 {
190                         changeViewer = new TableViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION);
191                         
192                         changeViewer.getTable().setHeaderVisible(true);
193                         changeViewer.getTable().setLinesVisible(true);
194                         
195                         changeViewer.setContentProvider(new ModificationListContentProvider());
196                         
197                         changeViewer.setUseHashlookup(true);
198                         
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);
205                         
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));
211                         
212                         selection.setLabelProvider(new SelectionLabelProvider());
213                         selection.getColumn().addSelectionListener(new SelectionAdapter() {
214                                 @Override
215                                 public void widgetSelected(SelectionEvent e) {
216                                         if (update.getUpdateList().getChanges().size() > 0) {
217                                                 if (update.getUpdateList().getSelected().size() > 0) {
218                                                         update.getUpdateList().clearSelected();
219                                                 } else {
220                                                         for (PropertyChange nr : update.getUpdateList().getChanges())
221                                                                 nr.select(true);
222                                                 }
223                                                 changeViewer.refresh();
224                                         }
225                                 }
226                         });
227                         selection.setEditingSupport(new SelectionEditingSupport(changeViewer));
228                 
229                 }
230                 Composite buttonComposite = new Composite(this, SWT.NONE);
231                 
232                 data = new GridData();
233                 data.grabExcessHorizontalSpace = true;
234                 data.grabExcessVerticalSpace = false;
235                 data.horizontalAlignment = SWT.FILL;
236                 data.verticalAlignment = SWT.BOTTOM;
237                 
238                 buttonComposite.setLayoutData(data);
239                 
240                 buttonComposite.setLayout(new GridLayout(3, false));
241                 
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);
249                 
250                 updateAllButton = new Button(buttonComposite, SWT.PUSH);
251                 updateAllButton.setText("Update All");
252                 updateAllButton.addSelectionListener(new SelectionAdapter() {
253                         @Override
254                         public void widgetSelected(SelectionEvent e) {
255                                 applyAll();
256                         }
257                 });
258                 updateSelectedButton = new Button(buttonComposite, SWT.PUSH);
259                 updateSelectedButton.setText("Update Selected");
260                 updateSelectedButton.addSelectionListener(new SelectionAdapter() {
261                         @Override
262                         public void widgetSelected(SelectionEvent e) {
263                                 applySelected();
264                         }
265                 });
266         }
267         
268         protected Session getSession() {
269                 return SimanticsUI.getSession();
270         }
271         
272         protected String getColumntTitle(int i) {
273                 switch (i) {
274                 case 0:
275                         return "!";
276                 case 1:
277                         return "Diagram";
278                 case 2:
279                         return "Symbol";
280                 case 3:
281                         return "Property";
282                 case 4:
283                         return "Old Value";
284                 case 5:
285                         return "New Value";
286                 default:
287                         throw new RuntimeException("Unknown column index" + i);
288                         
289                 }
290         }
291         
292         protected abstract ColumnLabelProvider getLabelProvider(int i);
293         
294         public GraphChanges getChanges() {
295                 return update.getChanges();
296         }
297         
298         public UpdateTree getUpdateTree() {
299                 return update.getUpdateTree();
300         }
301         
302         public UpdateList getUpdateList() {
303                 return update.getUpdateList();
304         }
305         
306         public CheckboxTreeViewer getChangeBrowser() {
307                 return changeBrowser;
308         }
309         
310         public TableViewer getChangeViewer() {
311                 return changeViewer;
312         }
313         
314         public void showWarning(ModelUpdate update, String text) {
315                 errorComposite.setVisible(true);
316                 
317                 Label label = new Label(errorComposite, SWT.NONE);
318                 label.setImage(warning);
319                 label = new Label(errorComposite, SWT.NONE);
320                 label.setText(text);
321                 //this.setStatusMessage("Update contains structural changes (new or deleted symbols), please create a new model.");
322                 this.layout(true);
323         }
324         
325         
326         private List<ICheckStateListener> checkStateListeners = new ArrayList<>();
327         
328         
329         public void addCheckStateListener(ICheckStateListener listener) {
330                 checkStateListeners.add(listener);
331         }
332         
333         public void removeCheckStateListener(ICheckStateListener listener) {
334                 checkStateListeners.remove(listener);
335         }
336         
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);
347                                 } else {
348                                         boolean applied = op.applied();
349                                         if (applied) {
350                                                 changeBrowser.setChecked(n, true);
351                                                 changeBrowser.setGrayed(n, true);
352                                                 selectedStructure.remove(n);
353                                         } else {
354                                                 boolean sel = op.selected();
355                                                 if (sel) {
356                                                         selectedStructure.add(n);
357                                                         
358                                                 } else {
359                                                         selectedStructure.remove(n);
360                                                 }
361                                                 changeBrowser.setChecked(n, sel);
362                                                 changeBrowser.setGrayed(n, false);
363                                         }
364                                 }
365                         } else {
366                                 changeBrowser.setGrayed(n, true);
367                                 changeBrowser.setChecked(n, true);
368                         }
369                         for (UpdateNode c : n.getChildren()) {
370                                 nodeStack.add((UpdateNode)c);
371                         }
372                 }
373                 
374                 changeBrowser.refresh();
375                 for (ICheckStateListener l : checkStateListeners) {
376                         l.checkStateChanged(new CheckStateChangedEvent(changeBrowser, null, false));
377                 }
378                 changeViewer.refresh();
379         }
380         
381         protected abstract ModelUpdate createUpdate();
382         
383         
384         
385         public void load(UpdateEditorInput uei) {
386
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();
391                 try {
392                         if (update != null)
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());
400                         e.printStackTrace();
401                         return;
402                 }
403         
404                 setInputs();
405                 
406                 refreshChecked();
407         }
408         
409         protected void setInputs() {
410                 changeViewer.setInput(update.getUpdateList().getChanges());
411                 changeBrowser.setInput(update.getUpdateTree());
412         }
413         
414         private void applyAll() {
415                 updateAllButton.setEnabled(false);
416                 updateSelectedButton.setEnabled(false);
417                 getSession().asyncRequest(new WriteRequest(){
418                         @Override
419                         public void perform(WriteGraph graph) throws DatabaseException {
420                                 update.applyAll(graph);
421                                 
422                                 Display.getDefault().asyncExec(new Runnable() {
423                                         
424                                         @Override
425                                         public void run() {
426                                                 
427                                                 updateAllButton.setEnabled(true);
428                                                 updateSelectedButton.setEnabled(true);
429                                                 refreshChecked();
430                                                 changeViewer.refresh();
431                                         }
432                                 });
433                         }
434                         
435                         
436                 }, new Callback<DatabaseException>() {
437                         @Override
438                         public void run(DatabaseException parameter) {
439                                 if (parameter != null)
440                                         ExceptionUtils.logAndShowError("Cannot update model", parameter);
441                         }
442                 });
443         }
444         
445         private void applySelected() {
446                 updateAllButton.setEnabled(false);
447                 updateSelectedButton.setEnabled(false);
448                 getSession().asyncRequest(new WriteRequest(){
449                         @Override
450                         public void perform(WriteGraph graph) throws DatabaseException {
451                                 update.applySelected(graph);
452                                 
453                                 Display.getDefault().asyncExec(new Runnable() {
454                                         
455                                         @Override
456                                         public void run() {
457                                                 changeViewer.refresh();
458                                                 updateAllButton.setEnabled(true);
459                                                 updateSelectedButton.setEnabled(true);
460                                                 refreshChecked();
461                                         }
462                                 });
463                         }
464                 });
465         }       
466         
467         private class ModificationListContentProvider implements IStructuredContentProvider {
468                 
469                 @SuppressWarnings("unchecked")
470                 @Override
471                 public Object[] getElements(Object inputElement) {
472                         if (inputElement == null)
473                                 return null;
474                         Collection<Pair<Statement, Statement>> coll = (Collection<Pair<Statement, Statement>>)inputElement;
475                         return coll.toArray();
476                 }
477                 
478                 @Override
479                 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
480                         
481                 }
482                 
483                 @Override
484                 public void dispose() {
485                         
486                 }
487         }
488         
489         private class UpdateTreeContentProvider implements ITreeContentProvider {
490                 @Override
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();
497                         }
498                         return new Object[0];
499                 }
500                 
501                 @Override
502                 public Object getParent(Object element) {
503                         return null;
504                 }
505                 
506                 @Override
507                 public Object[] getChildren(Object parentElement) {
508                         UpdateNode node = (UpdateNode)parentElement;
509                         return node.getChildren().toArray();
510                 }
511                 
512                 @Override
513                 public boolean hasChildren(Object element) {
514                         UpdateNode node = (UpdateNode)element;
515                         return node.getChildren().size() > 0;
516                 }
517                 
518                 @Override
519                 public void dispose() {
520                         
521                 }
522                 
523                 @Override
524                 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
525                         
526                 }
527         }
528         
529         private class SelectionLabelProvider extends ColumnLabelProvider {
530                 
531                 public SelectionLabelProvider() {
532                         
533                 }
534                 @Override
535                 public String getText(Object element) {
536                         return "";
537                 }
538                 
539                 @Override
540                 public Image getImage(Object element) {
541                         if (update == null || !update.isInit())
542                                 return null;
543                         PropertyChange pc = (PropertyChange)element;
544                         if (pc.selected())
545                                 return checked;
546                         else
547                                 return unchecked;
548                 }
549         }
550         
551         private class UpdateNodeLabelProvider extends ColumnLabelProvider {
552                 
553                 @Override
554                 public String getText(Object element) {
555                         final UpdateNode node = (UpdateNode)element;
556                         return node.getLabel();
557                 }
558                 
559                 @Override
560                 public Image getImage(Object element) {
561                         final UpdateNode node = (UpdateNode)element;
562                         try  {
563                                 ImageDescriptor id = getSession().syncRequest(new Read<ImageDescriptor>() {
564                                         @Override
565                                         public ImageDescriptor perform(ReadGraph graph) throws DatabaseException {
566                                                 return node.getImage(graph);
567                                         }
568                                 });
569                                 return manager.createImage(id);
570                         } catch (Exception e) {
571                                 return null;
572                         }
573                 }
574                 
575                 @Override
576                 public String getToolTipText(Object element) {
577                         final UpdateNode node = (UpdateNode)element;
578                         if (node.getOp() != null) {
579                                 return node.getOp().toString();
580                         } else {
581                                 return null;
582                         }
583                 }
584                 
585                 @Override
586                 public int getToolTipDisplayDelayTime(Object object) {
587                         return 1000;
588                 }
589                 
590                 @Override
591                 public int getToolTipTimeDisplayed(Object object) {
592                         return 10000;
593                 }
594
595                 @Override
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)
602                                 return deletedColor;
603                         if (status == UpdateStatus.NEW)
604                                 return addedColor;
605                         return null;            
606                 }
607         }
608         
609         private class SelectionEditingSupport extends EditingSupport {
610                 
611                 
612                 @SuppressWarnings("rawtypes")
613                 public SelectionEditingSupport(ColumnViewer viewer) {
614                         super(viewer);
615                         
616                 }
617
618                 @Override
619                 protected boolean canEdit(Object element) {
620                         return true;
621                 }
622                 
623                 @Override
624                 protected CellEditor getCellEditor(Object element) {
625                         return new CheckboxCellEditor(null, SWT.CHECK);
626                 }
627                 
628                 @Override
629                 protected Object getValue(Object element) {
630                         if (update == null || !update.isInit())
631                                 return false;
632                         PropertyChange pc = (PropertyChange)element;
633                         return pc.selected();
634                 }
635                 
636                 @SuppressWarnings("unchecked")
637                 @Override
638                 protected void setValue(Object element, Object value) {
639                         if (update == null || !update.isInit())
640                                 return;
641                         PropertyChange pc = (PropertyChange)element;
642                         if (Boolean.TRUE.equals(value))
643                                 pc.select(true);
644                         else
645                                 pc.select(false);
646                         
647                         getViewer().refresh(element);
648                 }
649                 
650                 
651         }
652
653
654 }