]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.interop.update/src/org/simantics/interop/update/editor/ModelUpdateEditor.java
dbfb0356251d33dea1c2a03f774ed2f52d81eb49
[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.exception.DoesNotContainValueException;
51 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
52 import org.simantics.db.exception.ServiceException;
53 import org.simantics.db.layer0.util.Layer0Utils;
54 import org.simantics.db.request.Read;
55 import org.simantics.interop.test.GraphChanges;
56 import org.simantics.interop.test.GraphComparator;
57 import org.simantics.interop.update.Activator;
58 import org.simantics.interop.update.model.UpdateNode;
59 import org.simantics.interop.update.model.UpdateNode.Status;
60 import org.simantics.interop.update.model.UpdateOp;
61 import org.simantics.interop.update.model.UpdateTree;
62 import org.simantics.interop.utils.TableUtils;
63 import org.simantics.ui.SimanticsUI;
64 import org.simantics.utils.datastructures.Callback;
65 import org.simantics.utils.datastructures.Pair;
66 import org.simantics.utils.ui.ExceptionUtils;
67
68
69 /**
70  * Editor for updating models.
71  * 
72  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
73  *
74  */
75 public abstract class ModelUpdateEditor extends Composite{
76
77         private Composite errorComposite;
78         
79         private CheckboxTreeViewer changeBrowser;
80         private TableViewer changeViewer;
81         
82         private GraphChanges changes;
83         private UpdateTree updateTree;
84         
85         private Button updateAllButton;
86         private Button updateSelectedButton;
87         
88         private LocalResourceManager manager = new LocalResourceManager(JFaceResources.getResources());
89         
90         private Image checked;
91         private Image unchecked;
92         private Image warning;
93         
94         private Color containsColor;
95         private Color deletedColor;
96         private Color addedColor;
97         
98         private HashSet<Pair<Statement, Statement>> selected = new HashSet<Pair<Statement,Statement>>();
99         
100         private HashSet<UpdateNode> selectedStructure = new HashSet<UpdateNode>();
101         
102         private List<ChangeFilter> filters = new ArrayList<ChangeFilter>();
103         
104         public ModelUpdateEditor(Composite parent) {
105                 super(parent,SWT.NONE);
106                 checked = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/tick.png"));
107                 unchecked = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/cross.png"));
108                 warning = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/error.png"));
109
110                 
111                 containsColor = new Color(parent.getDisplay(), new RGB(255,255,220));
112                 deletedColor = new Color(parent.getDisplay(), new RGB(255,220,220));
113                 addedColor = new Color(parent.getDisplay(), new RGB(220,255,220));
114                 
115                 this.setLayout(new GridLayout(1,false));
116                 
117                 errorComposite = new Composite(this, SWT.BORDER);
118                 GridData data = new GridData();
119                 data.grabExcessHorizontalSpace = true;
120                 data.grabExcessVerticalSpace = false;
121                 data.horizontalAlignment = SWT.FILL;
122                 data.verticalAlignment = SWT.TOP;
123                 errorComposite.setLayoutData(data);
124                 errorComposite.setLayout(new GridLayout(2, false));
125                 
126                 errorComposite.setVisible(false);
127
128 //              IEditorInput input = getEditorInput();
129 //              if (!(input instanceof UpdateEditorInput)) {
130 //                      Label label = new Label(composite, SWT.NONE);
131 //                      label.setText("Unknown input.");
132 //                      return;
133 //              }
134                 
135                 Composite fillComposite = new Composite(this, SWT.NONE);
136                 data = new GridData();
137                 data.grabExcessHorizontalSpace = true;
138                 data.grabExcessVerticalSpace = true;
139                 data.horizontalAlignment = SWT.FILL;
140                 data.verticalAlignment = SWT.FILL;
141                 fillComposite.setLayoutData(data);
142                 fillComposite.setLayout(new FillLayout(SWT.VERTICAL));
143
144                 {
145                         changeBrowser = new CheckboxTreeViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION  );
146                         
147                         changeBrowser.setContentProvider(new UpdateTreeContentProvider());
148                         
149                         changeBrowser.getTree().setHeaderVisible(true);
150                         
151                         ColumnViewerToolTipSupport.enableFor(changeBrowser);
152
153                         
154                         TreeViewerColumn dataColumn = TableUtils.addColumn(changeBrowser, "Data", true, 600);
155
156                         dataColumn.setLabelProvider(new UpdateNodeLabelProvider());
157                         
158                         changeBrowser.addCheckStateListener(new ICheckStateListener() {
159                                 
160                                 @Override
161                                 public void checkStateChanged(CheckStateChangedEvent event) {
162                                         UpdateNode node = (UpdateNode) event.getElement();
163                                         if (node.getOp() != null) {
164                                                 node.getOp().select(Boolean.TRUE.equals(event.getChecked()));
165                                                 
166                                         }
167                                         refreshChecked();
168                                         
169                                 }
170                         });
171                         changeBrowser.addTreeListener(new ITreeViewerListener() {
172                                 
173                                 @Override
174                                 public void treeExpanded(TreeExpansionEvent event) {
175                                         event.getTreeViewer().getControl().getDisplay().asyncExec(new Runnable() {
176                                                 
177                                                 @Override
178                                                 public void run() {
179                                                         // TreeViewer uses lazy load, checked states must be updated when the tree is expanded. 
180                                                         refreshChecked();
181                                                 }
182                                         });
183                                         
184                                 }
185                                 
186                                 @Override
187                                 public void treeCollapsed(TreeExpansionEvent event) {
188                                         
189                                 }
190                         });
191                         changeBrowser.setUseHashlookup(true);
192                         
193                 }
194                 {
195                         changeViewer = new TableViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION);
196                         
197                         changeViewer.getTable().setHeaderVisible(true);
198                         changeViewer.getTable().setLinesVisible(true);
199                         
200                         changeViewer.setContentProvider(new ModificationListContentProvider());
201                         
202                         changeViewer.setUseHashlookup(true);
203                         
204                         TableViewerColumn selection = TableUtils.addColumn(changeViewer, getColumntTitle(0), false, false, 20);
205                         TableViewerColumn diagram = TableUtils.addColumn(changeViewer, getColumntTitle(1), true, true, 100);
206                         TableViewerColumn symbol = TableUtils.addColumn(changeViewer, getColumntTitle(2), true, true, 100);
207                         TableViewerColumn property = TableUtils.addColumn(changeViewer, getColumntTitle(3), true, true, 100);
208                         TableViewerColumn oldValue = TableUtils.addColumn(changeViewer, getColumntTitle(4), true, true, 100);
209                         TableViewerColumn newValue = TableUtils.addColumn(changeViewer, getColumntTitle(5), true, true, 100);
210                         
211                         diagram.setLabelProvider(getLabelProvider(1));
212                         symbol.setLabelProvider(getLabelProvider(2));
213                         property.setLabelProvider(getLabelProvider(3));
214                         oldValue.setLabelProvider(getLabelProvider(4));
215                         newValue.setLabelProvider(getLabelProvider(5));
216                         
217                         selection.setLabelProvider(new SelectionLabelProvider(selected));
218                         selection.getColumn().addSelectionListener(new SelectionAdapter() {
219                                 @Override
220                                 public void widgetSelected(SelectionEvent e) {
221                                         if (changes.getModifications().size() > 0) {
222                                                 if (selected.contains(changes.getModifications().get(0))) {
223                                                         for (Pair<Statement, Statement> nr : changes.getModifications())
224                                                                 selected.remove(nr);
225                                                 } else {
226                                                         for (Pair<Statement, Statement> nr : changes.getModifications())
227                                                                 selected.add(nr);
228                                                 }
229                                                 changeViewer.refresh();
230                                         }
231                                 }
232                         });
233                         selection.setEditingSupport(new SelectionEditingSupport(changeViewer, selected));
234                 
235                 }
236                 Composite buttonComposite = new Composite(this, SWT.NONE);
237                 
238                 data = new GridData();
239                 data.grabExcessHorizontalSpace = true;
240                 data.grabExcessVerticalSpace = false;
241                 data.horizontalAlignment = SWT.FILL;
242                 data.verticalAlignment = SWT.BOTTOM;
243                 
244                 buttonComposite.setLayoutData(data);
245                 
246                 buttonComposite.setLayout(new GridLayout(3, false));
247                 
248                 Label label = new Label(buttonComposite, SWT.NONE);
249                 data = new GridData();
250                 data.grabExcessHorizontalSpace = true;
251                 data.grabExcessVerticalSpace = false;
252                 data.horizontalAlignment = SWT.FILL;
253                 data.verticalAlignment = SWT.CENTER;
254                 label.setLayoutData(data);
255                 
256                 updateAllButton = new Button(buttonComposite, SWT.PUSH);
257                 updateAllButton.setText("Update All");
258                 updateAllButton.addSelectionListener(new SelectionAdapter() {
259                         @Override
260                         public void widgetSelected(SelectionEvent e) {
261                                 applyAll();
262                         }
263                 });
264                 updateSelectedButton = new Button(buttonComposite, SWT.PUSH);
265                 updateSelectedButton.setText("Update Selected");
266                 updateSelectedButton.addSelectionListener(new SelectionAdapter() {
267                         @Override
268                         public void widgetSelected(SelectionEvent e) {
269                                 applySelected();
270                         }
271                 });
272         }
273         
274         protected Session getSession() {
275                 return SimanticsUI.getSession();
276         }
277         
278         protected String getColumntTitle(int i) {
279                 switch (i) {
280                 case 0:
281                         return "!";
282                 case 1:
283                         return "Diagram";
284                 case 2:
285                         return "Symbol";
286                 case 3:
287                         return "Property";
288                 case 4:
289                         return "Old Value";
290                 case 5:
291                         return "New Value";
292                 default:
293                         throw new RuntimeException("Unknown column index" + i);
294                         
295                 }
296         }
297         
298         protected abstract ColumnLabelProvider getLabelProvider(int i);
299         protected abstract Pair<GraphComparator,Boolean> getChanges(Resource r1, Resource r2)  throws DatabaseException;
300         protected abstract UpdateTree getUpdateTree(GraphChanges changes) throws DatabaseException;
301         
302         protected void addFilters(List<ChangeFilter> filters) {
303                 
304         }
305         
306         public GraphChanges getChanges() {
307                 return changes;
308         }
309         
310         public UpdateTree getUpdateTree() {
311                 return updateTree;
312         }
313         
314         public CheckboxTreeViewer getChangeBrowser() {
315                 return changeBrowser;
316         }
317         
318         public TableViewer getChangeViewer() {
319                 return changeViewer;
320         }
321         
322         private void showWarning(String text) {
323                 errorComposite.setVisible(true);
324                 
325                 Label label = new Label(errorComposite, SWT.NONE);
326                 label.setImage(warning);
327                 label = new Label(errorComposite, SWT.NONE);
328                 label.setText(text);
329                 //this.setStatusMessage("Update contains structural changes (new or deleted symbols), please create a new model.");
330                 this.layout(true);
331         }
332         
333         
334         private List<ICheckStateListener> checkStateListeners = new ArrayList<>();
335         
336         
337         public void addCheckStateListener(ICheckStateListener listener) {
338                 checkStateListeners.add(listener);
339         }
340         
341         public void removeCheckStateListener(ICheckStateListener listener) {
342                 checkStateListeners.remove(listener);
343         }
344         
345         public void refreshChecked() {
346                 Stack<UpdateNode> nodeStack = new Stack<UpdateNode>();
347                 nodeStack.push((UpdateNode)updateTree.getRootNode());
348                 while (!nodeStack.isEmpty()) {
349                         UpdateNode n = nodeStack.pop();
350                         if (n.getOp() != null) {
351                                 UpdateOp op = n.getOp();
352                                 if (!op.isAdd() && !op.isDelete()) {
353                                         changeBrowser.setGrayed(n, true);
354                                         changeBrowser.setChecked(n, true);
355                                 } else {
356                                         boolean applied = op.applied();
357                                         if (applied) {
358                                                 changeBrowser.setChecked(n, true);
359                                                 changeBrowser.setGrayed(n, true);
360                                                 selectedStructure.remove(n);
361                                         } else {
362                                                 boolean sel = op.selected();
363                                                 if (sel) {
364                                                         selectedStructure.add(n);
365                                                         
366                                                 } else {
367                                                         selectedStructure.remove(n);
368                                                 }
369                                                 changeBrowser.setChecked(n, sel);
370                                                 changeBrowser.setGrayed(n, false);
371                                         }
372                                 }
373                         } else {
374                                 changeBrowser.setGrayed(n, true);
375                                 changeBrowser.setChecked(n, true);
376                         }
377                         for (UpdateNode c : n.getChildren()) {
378                                 nodeStack.add((UpdateNode)c);
379                         }
380                 }
381                 
382                 changeBrowser.refresh();
383                 for (ICheckStateListener l : checkStateListeners) {
384                         l.checkStateChanged(new CheckStateChangedEvent(changeBrowser, null, false));
385                 }
386         }
387         
388         
389         
390         public void load(UpdateEditorInput uei) {
391                 
392                 addFilters(filters);
393
394                 Resource r1 = uei.getR1();
395                 Resource r2 = uei.getR2();
396                 
397
398                 try {
399                         
400                         Pair<GraphComparator,Boolean> result = getChanges(r1,r2);
401                         GraphComparator comparator  = result.first;
402                         if (result.second)
403                                 showWarning("Structural symbols have been changed. Model update is not able to update these, please create a new model.");
404                         comparator.test(getSession());
405                         changes = comparator.getChanges();
406                         changes = getSession().syncRequest(new FilterChangesRead(changes));
407                         updateTree = getUpdateTree(changes);
408                 } catch (DatabaseException e) {
409                         Text text = new Text(this, SWT.MULTI);
410                         text.setText(e.getMessage());
411                         e.printStackTrace();
412                         return;
413                 }
414         
415
416
417                 changeViewer.setInput(changes.getModifications());
418                 changeBrowser.setInput(updateTree);
419                 refreshChecked();
420         }
421         
422         
423         
424         private void applyAll() {
425                 updateAllButton.setEnabled(false);
426                 updateSelectedButton.setEnabled(false);
427                 getSession().asyncRequest(new WriteRequest(){
428                         @Override
429                         public void perform(WriteGraph graph) throws DatabaseException {
430                                 Layer0Utils.addCommentMetadata(graph, "Apply all model updates");
431                                 graph.markUndoPoint();
432                                 for (Pair<Statement, Statement> mod : changes.getModifications()) {
433                                         applyLiteralChange(graph, mod);
434                                 }
435                                 selected.clear();
436                                 changes.getModifications().clear();
437                                 
438                                 updateTree.getUpdateOps().applyAll(graph);
439                                 
440                                 Display.getDefault().asyncExec(new Runnable() {
441                                         
442                                         @Override
443                                         public void run() {
444                                                 
445                                                 updateAllButton.setEnabled(true);
446                                                 updateSelectedButton.setEnabled(true);
447                                                 refreshChecked();
448                                                 changeViewer.refresh();
449                                         }
450                                 });
451                         }
452                         
453                         
454                 }, new Callback<DatabaseException>() {
455                         @Override
456                         public void run(DatabaseException parameter) {
457                                 if (parameter != null)
458                                         ExceptionUtils.logAndShowError("Cannot update model", parameter);
459                         }
460                 });
461         }
462         
463         private void applyLiteralChange(WriteGraph graph, Pair<Statement, Statement> mod) throws DoesNotContainValueException, ServiceException, ManyObjectsForFunctionalRelationException {
464                 
465                 Resource s = changes.getComparable().getLeft(mod.second.getSubject());
466                 Resource pred = mod.first.getPredicate();
467                 if (graph.hasValue(mod.second.getObject())) {
468                         Object value = graph.getValue(mod.second.getObject());
469                         graph.claimLiteral(s, pred, value);
470                 } else {
471                         graph.deny(s,pred);
472                 }
473                 
474                 
475         }
476         
477         private void applySelected() {
478                 updateAllButton.setEnabled(false);
479                 updateSelectedButton.setEnabled(false);
480                 getSession().asyncRequest(new WriteRequest(){
481                         @Override
482                         public void perform(WriteGraph graph) throws DatabaseException {
483                                 Layer0Utils.addCommentMetadata(graph, "Apply selected model updates");
484                                 graph.markUndoPoint();
485                                 for (Pair<Statement, Statement> mod : selected) {
486                                         changes.getModifications().remove(mod);
487                                         applyLiteralChange(graph, mod);
488                                 }
489                                 selected.clear();
490                                 
491                                 updateTree.getUpdateOps().applySelected(graph);
492                                 
493                                 Display.getDefault().asyncExec(new Runnable() {
494                                         
495                                         @Override
496                                         public void run() {
497                                                 changeViewer.refresh();
498                                                 updateAllButton.setEnabled(true);
499                                                 updateSelectedButton.setEnabled(true);
500                                                 refreshChecked();
501                                         }
502                                 });
503                         }
504                 });
505         }
506
507         
508         /**
509          * Filters changes:
510          * 1. Changes that are not essential for model update (changes that can be found when the models are axcatly the same)
511          * 2. Runs custom filters for value changes. 
512          * 
513          * @param g
514          * @param changes
515          * @return
516          * @throws DatabaseException
517          */
518         protected GraphChanges filterChanges(ReadGraph g, GraphChanges changes) throws DatabaseException 
519     {
520                 
521                 List<Pair<Statement,Statement>> modifications = new ArrayList<Pair<Statement,Statement>>();
522                 
523         for (Pair<Statement, Statement> mod : changes.getModifications()) {
524                 
525                 boolean accept = true;
526                 for (ChangeFilter filter : filters) {
527                         if (!filter.accept(g, mod)) {
528                                 accept = false;
529                                 break;
530                         }       
531                 }
532                 if (accept)
533                         modifications.add(mod);
534         }
535         GraphChanges newChanges =  new GraphChanges(changes.getResource1(),changes.getResource2(),changes.getDeletions(), changes.getAdditions(), modifications, changes.getComparable());
536         return newChanges;
537     }
538         
539         public interface ChangeFilter {
540                 public boolean accept(ReadGraph g, Pair<Statement, Statement> change) throws DatabaseException;
541         }
542         
543         
544         
545         
546         /**
547          * 
548          * Filters floating point value changes (default filter is set filter when the change is less than 1%)  
549          *
550          */
551         protected class FPValueFilter implements ChangeFilter  {
552                 
553                 private double percentage = 0.01;
554                 
555                 public FPValueFilter() {
556                         
557                 }
558                 
559                 public FPValueFilter(double percentage) {
560                         if (percentage < 0.0 || percentage > 1.0)
561                                 throw new IllegalArgumentException("Percentage must be between 0.0 and 1.0.");
562                         this.percentage = percentage;
563                 }
564                 
565                 @Override
566                 public boolean accept(ReadGraph g, Pair<Statement, Statement> change) throws DatabaseException {
567                         //filter floating point values that have less than 1% difference.
568                         if (!g.hasValue(change.first.getObject()) || !g.hasValue(change.second.getObject()))
569                                 return true;
570                 Object v1 = g.getValue(change.first.getObject());
571                 Object v2 = g.getValue(change.second.getObject());
572                 
573                 if (v1 instanceof Double && v2 instanceof Double) {
574                         double d1 = (Double)v1;
575                         double d2 = (Double)v2;
576                         if (Math.abs(d1-d2) / Math.max(Math.abs(d1), Math.abs(d2)) < percentage)
577                                 return false;
578                 } else if (v1 instanceof Float && v2 instanceof Float) {
579                         float d1 = (Float)v1;
580                         float d2 = (Float)v2;
581                         if (Math.abs(d1-d2) / Math.max(Math.abs(d1), Math.abs(d2)) < percentage)
582                                 return false;
583                 }
584
585                 return true;
586                 }
587         }
588
589         
590         private class FilterChangesRead implements Read<GraphChanges> {
591                 private GraphChanges changes;
592                 public FilterChangesRead(GraphChanges changes) {
593                         this.changes = changes;
594                 }
595                 
596                 @Override
597                 public GraphChanges perform(ReadGraph graph) throws DatabaseException {
598                         return filterChanges(graph, changes);
599                 }
600         }
601         
602         
603         private class ModificationListContentProvider implements IStructuredContentProvider {
604                 
605                 @SuppressWarnings("unchecked")
606                 @Override
607                 public Object[] getElements(Object inputElement) {
608                         if (inputElement == null)
609                                 return null;
610                         Collection<Pair<Statement, Statement>> coll = (Collection<Pair<Statement, Statement>>)inputElement;
611                         return coll.toArray();
612                 }
613                 
614                 @Override
615                 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
616                         
617                 }
618                 
619                 @Override
620                 public void dispose() {
621                         
622                 }
623         }
624         
625         private class UpdateTreeContentProvider implements ITreeContentProvider {
626                 @Override
627                 public Object[] getElements(Object inputElement) {
628                         if (inputElement instanceof UpdateTree)
629                                 return new Object[]{((UpdateTree)inputElement).getRootNode()};
630                         if (inputElement instanceof UpdateNode) {
631                                 UpdateNode node = (UpdateNode)inputElement;
632                                 return node.getChildren().toArray();
633                         }
634                         return new Object[0];
635                 }
636                 
637                 @Override
638                 public Object getParent(Object element) {
639                         return null;
640                 }
641                 
642                 @Override
643                 public Object[] getChildren(Object parentElement) {
644                         UpdateNode node = (UpdateNode)parentElement;
645                         return node.getChildren().toArray();
646                 }
647                 
648                 @Override
649                 public boolean hasChildren(Object element) {
650                         UpdateNode node = (UpdateNode)element;
651                         return node.getChildren().size() > 0;
652                 }
653                 
654                 @Override
655                 public void dispose() {
656                         
657                 }
658                 
659                 @Override
660                 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
661                         
662                 }
663         }
664         
665         private class SelectionLabelProvider extends ColumnLabelProvider {
666                 
667                 Collection<?>  selected;
668                 public SelectionLabelProvider(Collection<?>  selected) {
669                         this.selected = selected;
670                 }
671                 @Override
672                 public String getText(Object element) {
673                         return "";
674                 }
675                 
676                 @Override
677                 public Image getImage(Object element) {
678                         if (selected.contains(element))
679                                 return checked;
680                         else
681                                 return unchecked;
682                 }
683         }
684         
685         private class UpdateNodeLabelProvider extends ColumnLabelProvider {
686                 
687                 @Override
688                 public String getText(Object element) {
689                         final UpdateNode node = (UpdateNode)element;
690                         return node.getLabel();
691                 }
692                 
693                 @Override
694                 public Image getImage(Object element) {
695                         final UpdateNode node = (UpdateNode)element;
696                         try  {
697                                 ImageDescriptor id = getSession().syncRequest(new Read<ImageDescriptor>() {
698                                         @Override
699                                         public ImageDescriptor perform(ReadGraph graph) throws DatabaseException {
700                                                 return node.getImage(graph);
701                                         }
702                                 });
703                                 return manager.createImage(id);
704                         } catch (Exception e) {
705                                 return null;
706                         }
707                 }
708                 
709                 @Override
710                 public String getToolTipText(Object element) {
711                         final UpdateNode node = (UpdateNode)element;
712                         if (node.getOp() != null) {
713                                 return node.getOp().toString();
714                         } else {
715                                 return null;
716                         }
717                 }
718                 
719                 @Override
720                 public int getToolTipDisplayDelayTime(Object object) {
721                         return 1000;
722                 }
723                 
724                 @Override
725                 public int getToolTipTimeDisplayed(Object object) {
726                         return 10000;
727                 }
728
729                 @Override
730                 public Color getBackground(Object element) {
731                         final UpdateNode node = (UpdateNode)element;
732                         Status status = node.getStatus();
733                         if (status == Status.CONTAINS)
734                                 return containsColor;
735                         if (status == Status.DELETED)
736                                 return deletedColor;
737                         if (status == Status.NEW)
738                                 return addedColor;
739                         return null;            
740                 }
741         }
742         
743         private class SelectionEditingSupport extends EditingSupport {
744                 
745                 @SuppressWarnings("rawtypes")
746                 Collection selected;
747
748                 
749                 @SuppressWarnings("rawtypes")
750                 public SelectionEditingSupport(ColumnViewer viewer, Collection selected) {
751                         super(viewer);
752                         this.selected = selected;
753                         
754                 }
755
756                 @Override
757                 protected boolean canEdit(Object element) {
758                         return true;
759                 }
760                 
761                 @Override
762                 protected CellEditor getCellEditor(Object element) {
763                         return new CheckboxCellEditor(null, SWT.CHECK);
764                 }
765                 
766                 @Override
767                 protected Object getValue(Object element) {
768                         return selected.contains(element);
769                 }
770                 
771                 @SuppressWarnings("unchecked")
772                 @Override
773                 protected void setValue(Object element, Object value) {
774                         if (Boolean.TRUE.equals(value))
775                                 selected.add(element);
776                         else
777                                 selected.remove(element);
778                         
779                         getViewer().refresh(element);
780                 }
781                 
782                 
783         }
784
785
786 }