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