]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.interop.update/src/org/simantics/interop/update/editor/ModelUpdateEditor.java
Fix introduced ConcurrentModficationException
[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.Map.Entry;
8 import java.util.Stack;
9
10 import org.eclipse.jface.resource.ImageDescriptor;
11 import org.eclipse.jface.resource.JFaceResources;
12 import org.eclipse.jface.resource.LocalResourceManager;
13 import org.eclipse.jface.viewers.CellEditor;
14 import org.eclipse.jface.viewers.CheckStateChangedEvent;
15 import org.eclipse.jface.viewers.CheckboxCellEditor;
16 import org.eclipse.jface.viewers.CheckboxTreeViewer;
17 import org.eclipse.jface.viewers.ColumnLabelProvider;
18 import org.eclipse.jface.viewers.ColumnViewer;
19 import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
20 import org.eclipse.jface.viewers.EditingSupport;
21 import org.eclipse.jface.viewers.ICheckStateListener;
22 import org.eclipse.jface.viewers.IStructuredContentProvider;
23 import org.eclipse.jface.viewers.ITreeContentProvider;
24 import org.eclipse.jface.viewers.ITreeViewerListener;
25 import org.eclipse.jface.viewers.TableViewer;
26 import org.eclipse.jface.viewers.TableViewerColumn;
27 import org.eclipse.jface.viewers.TreeExpansionEvent;
28 import org.eclipse.jface.viewers.TreeViewerColumn;
29 import org.eclipse.jface.viewers.Viewer;
30 import org.eclipse.swt.SWT;
31 import org.eclipse.swt.events.SelectionAdapter;
32 import org.eclipse.swt.events.SelectionEvent;
33 import org.eclipse.swt.graphics.Color;
34 import org.eclipse.swt.graphics.Image;
35 import org.eclipse.swt.graphics.RGB;
36 import org.eclipse.swt.layout.FillLayout;
37 import org.eclipse.swt.layout.GridData;
38 import org.eclipse.swt.layout.GridLayout;
39 import org.eclipse.swt.widgets.Button;
40 import org.eclipse.swt.widgets.Composite;
41 import org.eclipse.swt.widgets.Display;
42 import org.eclipse.swt.widgets.Label;
43 import org.eclipse.swt.widgets.Text;
44 import org.simantics.db.ReadGraph;
45 import org.simantics.db.Resource;
46 import org.simantics.db.Session;
47 import org.simantics.db.Statement;
48 import org.simantics.db.WriteGraph;
49 import org.simantics.db.common.request.WriteRequest;
50 import org.simantics.db.exception.DatabaseException;
51 import org.simantics.db.layer0.util.Layer0Utils;
52 import org.simantics.db.request.Read;
53 import org.simantics.interop.test.GraphChanges;
54 import org.simantics.interop.test.GraphComparator;
55 import org.simantics.interop.update.Activator;
56 import org.simantics.interop.update.model.UpdateList;
57 import org.simantics.interop.update.model.UpdateNode;
58 import org.simantics.interop.update.model.UpdateNode.Status;
59 import org.simantics.interop.update.model.UpdateOp;
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{
75
76         private Composite errorComposite;
77         
78         private CheckboxTreeViewer changeBrowser;
79         private TableViewer changeViewer;
80         
81         private GraphChanges changes;
82         private UpdateTree updateTree;
83         private UpdateList updateList;
84         
85         private GraphChanges changes2;
86         private GraphChanges changes3;
87         private UpdateTree updateTree2;
88         private UpdateList updateList2;
89         
90         private Button updateAllButton;
91         private Button updateSelectedButton;
92         
93         private LocalResourceManager manager = new LocalResourceManager(JFaceResources.getResources());
94         
95         private Image checked;
96         private Image unchecked;
97         private Image warning;
98         
99         private Color containsColor;
100         private Color deletedColor;
101         private Color addedColor;
102
103         
104         private HashSet<UpdateNode> selectedStructure = new HashSet<UpdateNode>();
105         
106         private List<ChangeFilter> filters = new ArrayList<ChangeFilter>();
107         
108         public ModelUpdateEditor(Composite parent) {
109                 super(parent,SWT.NONE);
110                 checked = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/tick.png"));
111                 unchecked = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/cross.png"));
112                 warning = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/error.png"));
113
114                 
115                 containsColor = new Color(parent.getDisplay(), new RGB(255,255,220));
116                 deletedColor = new Color(parent.getDisplay(), new RGB(255,220,220));
117                 addedColor = new Color(parent.getDisplay(), new RGB(220,255,220));
118                 
119                 this.setLayout(new GridLayout(1,false));
120                 
121                 errorComposite = new Composite(this, 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(this, 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 UpdateNodeLabelProvider());
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                                         refreshChecked();
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                                                         // TreeViewer uses lazy load, checked states must be updated when the tree is expanded. 
184                                                         refreshChecked();
185                                                 }
186                                         });
187                                         
188                                 }
189                                 
190                                 @Override
191                                 public void treeCollapsed(TreeExpansionEvent event) {
192                                         
193                                 }
194                         });
195                         changeBrowser.setUseHashlookup(true);
196                         
197                 }
198                 {
199                         changeViewer = new TableViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION);
200                         
201                         changeViewer.getTable().setHeaderVisible(true);
202                         changeViewer.getTable().setLinesVisible(true);
203                         
204                         changeViewer.setContentProvider(new ModificationListContentProvider());
205                         
206                         changeViewer.setUseHashlookup(true);
207                         
208                         TableViewerColumn selection = TableUtils.addColumn(changeViewer, getColumntTitle(0), false, false, 20);
209                         TableViewerColumn diagram = TableUtils.addColumn(changeViewer, getColumntTitle(1), true, true, 100);
210                         TableViewerColumn symbol = TableUtils.addColumn(changeViewer, getColumntTitle(2), true, true, 100);
211                         TableViewerColumn property = TableUtils.addColumn(changeViewer, getColumntTitle(3), true, true, 100);
212                         TableViewerColumn oldValue = TableUtils.addColumn(changeViewer, getColumntTitle(4), true, true, 100);
213                         TableViewerColumn newValue = TableUtils.addColumn(changeViewer, getColumntTitle(5), true, true, 100);
214                         
215                         diagram.setLabelProvider(getLabelProvider(1));
216                         symbol.setLabelProvider(getLabelProvider(2));
217                         property.setLabelProvider(getLabelProvider(3));
218                         oldValue.setLabelProvider(getLabelProvider(4));
219                         newValue.setLabelProvider(getLabelProvider(5));
220                         
221                         selection.setLabelProvider(new SelectionLabelProvider());
222                         selection.getColumn().addSelectionListener(new SelectionAdapter() {
223                                 @Override
224                                 public void widgetSelected(SelectionEvent e) {
225                                         if (updateList.getChanges().size() > 0) {
226                                                 if (updateList.getSelected().size() > 0) {
227                                                         updateList.clearSelected();
228                                                 } else {
229                                                         for (Pair<Statement, Statement> nr : updateList.getChanges())
230                                                                 updateList.addSelected(nr);
231                                                 }
232                                                 changeViewer.refresh();
233                                         }
234                                 }
235                         });
236                         selection.setEditingSupport(new SelectionEditingSupport(changeViewer));
237                 
238                 }
239                 Composite buttonComposite = new Composite(this, 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                                 applyAll();
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                                 applySelected();
273                         }
274                 });
275         }
276         
277         protected Session getSession() {
278                 return SimanticsUI.getSession();
279         }
280         
281         protected String getColumntTitle(int i) {
282                 switch (i) {
283                 case 0:
284                         return "!";
285                 case 1:
286                         return "Diagram";
287                 case 2:
288                         return "Symbol";
289                 case 3:
290                         return "Property";
291                 case 4:
292                         return "Old Value";
293                 case 5:
294                         return "New Value";
295                 default:
296                         throw new RuntimeException("Unknown column index" + i);
297                         
298                 }
299         }
300         
301         protected abstract ColumnLabelProvider getLabelProvider(int i);
302         protected abstract Pair<GraphComparator,String> getChanges(Resource r1, Resource r2)  throws DatabaseException;
303         protected abstract UpdateTree getUpdateTree(GraphChanges changes) throws DatabaseException;
304         protected UpdateList getUpdateList(GraphChanges changes) throws DatabaseException {
305                 return new UpdateList(changes.getModifications());
306         }
307         
308         protected void addFilters(List<ChangeFilter> filters) {
309                 
310         }
311         
312         public GraphChanges getChanges() {
313                 return changes;
314         }
315         
316         public UpdateTree getUpdateTree() {
317                 return updateTree;
318         }
319         
320         public UpdateList getUpdateList() {
321                 return updateList;
322         }
323         
324         public CheckboxTreeViewer getChangeBrowser() {
325                 return changeBrowser;
326         }
327         
328         public TableViewer getChangeViewer() {
329                 return changeViewer;
330         }
331         
332         private void showWarning(String text) {
333                 errorComposite.setVisible(true);
334                 
335                 Label label = new Label(errorComposite, SWT.NONE);
336                 label.setImage(warning);
337                 label = new Label(errorComposite, SWT.NONE);
338                 label.setText(text);
339                 //this.setStatusMessage("Update contains structural changes (new or deleted symbols), please create a new model.");
340                 this.layout(true);
341         }
342         
343         
344         private List<ICheckStateListener> checkStateListeners = new ArrayList<>();
345         
346         
347         public void addCheckStateListener(ICheckStateListener listener) {
348                 checkStateListeners.add(listener);
349         }
350         
351         public void removeCheckStateListener(ICheckStateListener listener) {
352                 checkStateListeners.remove(listener);
353         }
354         
355         public void refreshChecked() {
356                 Stack<UpdateNode> nodeStack = new Stack<UpdateNode>();
357                 nodeStack.push((UpdateNode)updateTree.getRootNode());
358                 while (!nodeStack.isEmpty()) {
359                         UpdateNode n = nodeStack.pop();
360                         if (n.getOp() != null) {
361                                 UpdateOp op = n.getOp();
362                                 if (!op.isAdd() && !op.isDelete()) {
363                                         changeBrowser.setGrayed(n, true);
364                                         changeBrowser.setChecked(n, true);
365                                 } else {
366                                         boolean applied = op.applied();
367                                         if (applied) {
368                                                 changeBrowser.setChecked(n, true);
369                                                 changeBrowser.setGrayed(n, true);
370                                                 selectedStructure.remove(n);
371                                         } else {
372                                                 boolean sel = op.selected();
373                                                 if (sel) {
374                                                         selectedStructure.add(n);
375                                                         
376                                                 } else {
377                                                         selectedStructure.remove(n);
378                                                 }
379                                                 changeBrowser.setChecked(n, sel);
380                                                 changeBrowser.setGrayed(n, false);
381                                         }
382                                 }
383                         } else {
384                                 changeBrowser.setGrayed(n, true);
385                                 changeBrowser.setChecked(n, true);
386                         }
387                         for (UpdateNode c : n.getChildren()) {
388                                 nodeStack.add((UpdateNode)c);
389                         }
390                 }
391                 
392                 changeBrowser.refresh();
393                 for (ICheckStateListener l : checkStateListeners) {
394                         l.checkStateChanged(new CheckStateChangedEvent(changeBrowser, null, false));
395                 }
396                 changeViewer.refresh();
397         }
398         
399         
400         
401         public void load(UpdateEditorInput uei) {
402                 
403                 addFilters(filters);
404
405                 Resource oldModel = uei.getR1(); // old model that is being updated, contains user made changes
406                 Resource newModel = uei.getR2(); // new model, 
407                 Resource originalModel = uei.getR3(); // original old model without user made changes 
408
409                 try {
410                         
411                         if (originalModel != null) {
412                                 // tree way comparison
413                                 // compare the original and the old model
414                                 Pair<GraphComparator,String> result2 = getChanges(originalModel, oldModel);
415                                 GraphComparator comparator2  = result2.first;
416                                 if (result2.second != null)
417                                         showWarning(result2.second);
418                                 comparator2.test(getSession());
419                                 changes2 = comparator2.getChanges();
420                                 changes2 = getSession().syncRequest(new FilterChangesRead(changes2));
421                                 updateTree2 = getUpdateTree(changes2);
422                                 updateList2 = getUpdateList(changes2);
423                                 
424                                 // compare the original and the new model
425                                 Pair<GraphComparator,String> result3 = getChanges(originalModel,newModel);
426                                 GraphComparator comparator3  = result3.first;
427                                 if (result3.second != null)
428                                         showWarning(result3.second);
429                                 comparator3.test(getSession());
430                                 changes3 = comparator3.getChanges();
431                                 changes3 = getSession().syncRequest(new FilterChangesRead(changes3));
432                         }
433                         
434                         Pair<GraphComparator,String> result = getChanges(oldModel,newModel);
435                         GraphComparator comparator  = result.first;
436                         if (result.second != null)
437                                 showWarning(result.second);
438                         if (originalModel != null) {
439                                 // three-way comparison: use change information to configure
440                                 // the comparison between the old and the new model.
441                                 
442                                 // 1. map comparable resources
443                                 for (Entry<Resource, Resource> origToOld : changes2.getComparable().getEntries()) {
444                                         Resource oldR = origToOld.getValue();
445                                         Resource newR = changes3.getComparable().getRight(origToOld.getKey());
446                                         if (newR != null) {
447                                                 comparator.addComparableResources(oldR, newR);
448                                         }
449                                 }
450                                 // 2. mark removed resources as distinct, so that comparison does not pair them
451                                 for (Statement s : changes2.getDeletions()) {
452                                         if (changes3.getComparable().containsLeft(s.getObject()))
453                                                 comparator.addNonMatchedRight(changes3.getComparable().getRight(s.getObject()));
454                                 }
455                                 
456                                 for (Statement s : changes3.getDeletions()) {
457                                         if (changes2.getComparable().containsLeft(s.getObject()))
458                                                 comparator.addNonMatchedLeft(changes2.getComparable().getRight(s.getObject()));
459                                 }
460                                 if (uei.isNewDistinct()) {
461                                         // 3. mark added resources as distinct, so that comparison does not pair them
462                                         for (Statement s : changes2.getAdditions()) {
463                                                 comparator.addNonMatchedLeft(s.getObject());
464                                         }
465                                         
466                                         for (Statement s : changes3.getAdditions()) {
467                                                 comparator.addNonMatchedRight(s.getObject());
468                                         }
469                                 }
470                         }
471                         comparator.test(getSession());
472                         changes = comparator.getChanges();
473                         changes = getSession().syncRequest(new FilterChangesRead(changes));
474                         updateTree = getUpdateTree(changes);
475                         updateList = getUpdateList(changes);
476                         
477                         if (originalModel != null) {
478                                 createDefaultSelections();
479                         }
480                         
481                 } catch (DatabaseException e) {
482                         Text text = new Text(this, SWT.MULTI);
483                         text.setText(e.getMessage());
484                         e.printStackTrace();
485                         return;
486                 }
487         
488                 setInputs();
489                 
490                 refreshChecked();
491         }
492         
493         protected void setInputs() {
494                 changeViewer.setInput(updateList.getChanges());
495                 changeBrowser.setInput(updateTree);
496         }
497         
498         private void applyAll() {
499                 updateAllButton.setEnabled(false);
500                 updateSelectedButton.setEnabled(false);
501                 getSession().asyncRequest(new WriteRequest(){
502                         @Override
503                         public void perform(WriteGraph graph) throws DatabaseException {
504                                 Layer0Utils.addCommentMetadata(graph, "Apply all model updates");
505                                 graph.markUndoPoint();
506                                 for (Pair<Statement, Statement> mod : updateList.getChanges()) {
507                                         applyLiteralChange(graph, mod);
508                                 }
509                                 updateList.clear();
510                                 
511                                 updateTree.getUpdateOps().applyAll(graph);
512                                 
513                                 Display.getDefault().asyncExec(new Runnable() {
514                                         
515                                         @Override
516                                         public void run() {
517                                                 
518                                                 updateAllButton.setEnabled(true);
519                                                 updateSelectedButton.setEnabled(true);
520                                                 refreshChecked();
521                                                 changeViewer.refresh();
522                                         }
523                                 });
524                         }
525                         
526                         
527                 }, new Callback<DatabaseException>() {
528                         @Override
529                         public void run(DatabaseException parameter) {
530                                 if (parameter != null)
531                                         ExceptionUtils.logAndShowError("Cannot update model", parameter);
532                         }
533                 });
534         }
535         
536         protected void applyLiteralChange(WriteGraph graph, Pair<Statement, Statement> mod) throws DatabaseException {
537                 if (mod.second == null) {
538                         graph.deny(mod.first);
539                         return;
540                 } 
541                 Resource s = changes.getComparable().getLeft(mod.second.getSubject());
542                 Resource pred = mod.second.getPredicate();
543                 if (graph.hasValue(mod.second.getObject())) {
544                         Object value = graph.getValue(mod.second.getObject());
545                         graph.claimLiteral(s, pred, value);
546                 } else {
547                         graph.deny(s,pred);
548                 }
549                 
550                 
551         }
552         
553         private void applySelected() {
554                 updateAllButton.setEnabled(false);
555                 updateSelectedButton.setEnabled(false);
556                 getSession().asyncRequest(new WriteRequest(){
557                         @Override
558                         public void perform(WriteGraph graph) throws DatabaseException {
559                                 Layer0Utils.addCommentMetadata(graph, "Apply selected model updates");
560                                 graph.markUndoPoint();
561                                 HashSet<Pair<Statement, Statement>> changes = new HashSet<>(updateList.getSelected());
562                                 for (Pair<Statement, Statement> mod : changes) {
563                                         updateList.removeChange(mod);
564                                         applyLiteralChange(graph, mod);
565                                 }
566                                 
567                                 updateTree.getUpdateOps().applySelected(graph);
568                                 
569                                 Display.getDefault().asyncExec(new Runnable() {
570                                         
571                                         @Override
572                                         public void run() {
573                                                 changeViewer.refresh();
574                                                 updateAllButton.setEnabled(true);
575                                                 updateSelectedButton.setEnabled(true);
576                                                 refreshChecked();
577                                         }
578                                 });
579                         }
580                 });
581         }
582         
583         protected void createDefaultSelections() {
584                 // select all changes
585                 for (Entry<Resource, UpdateOp> op : updateTree.getUpdateOps().getResourceMap().entrySet()) {
586                         op.getValue().select(true);
587                 }
588                 
589                 
590                 for (Pair<Statement, Statement> pair : updateList.getChanges()) {
591                         updateList.addSelected(pair);
592                 }
593                 
594                 // preserve user-made changes (by removing selections)
595                 for (Entry<Resource, UpdateOp> op : updateTree.getUpdateOps().getResourceMap().entrySet()) {
596                         UpdateOp op2 = updateTree2.getUpdateOps().getUpdateOp(op.getKey());
597                         if (op2 == null) {
598                                 if (changes3.getComparable().containsRight(op.getKey())){
599                                         op2 = updateTree2.getUpdateOps().getUpdateOp(changes3.getComparable().getLeft(op.getKey()));
600                                 }
601                         }
602                         if (op2 != null && op.getValue().getClass() == op2.getClass()) {
603                                 op.getValue().select(false);
604                         }
605                 }
606                 
607                 for (Pair<Statement, Statement> pair : updateList.getChanges()) {
608                         if (pair.first != null) {
609                                 boolean found = false;
610                                 for (Pair<Statement, Statement> pair2 : updateList2.getChanges()) {
611                                         if (pair.first.equals(pair2.first)) {
612                                                 found = true;
613                                                 break;
614                                         }
615                                 }
616                                 if (found) {
617                                         updateList.removeSelected(pair);
618                                 }
619                         }
620                 }
621                 
622         }
623
624         
625         /**
626          * Filters changes:
627          * 1. Changes that are not essential for model update (changes that can be found when the models are axcatly the same)
628          * 2. Runs custom filters for value changes. 
629          * 
630          * @param g
631          * @param changes
632          * @return
633          * @throws DatabaseException
634          */
635         protected GraphChanges filterChanges(ReadGraph g, GraphChanges changes) throws DatabaseException 
636     {
637                 
638                 List<Pair<Statement,Statement>> modifications = new ArrayList<Pair<Statement,Statement>>();
639                 
640         for (Pair<Statement, Statement> mod : changes.getModifications()) {
641                 
642                 boolean accept = true;
643                 for (ChangeFilter filter : filters) {
644                         if (!filter.accept(g, mod)) {
645                                 accept = false;
646                                 break;
647                         }       
648                 }
649                 if (accept)
650                         modifications.add(mod);
651         }
652         GraphChanges newChanges =  new GraphChanges(changes.getResource1(),changes.getResource2(),changes.getDeletions(), changes.getAdditions(), modifications, changes.getComparable());
653         return newChanges;
654     }
655         
656         public interface ChangeFilter {
657                 public boolean accept(ReadGraph g, Pair<Statement, Statement> change) throws DatabaseException;
658         }
659
660         
661         /**
662          * 
663          * Filters floating point value changes (default filter is set filter when the change is less than 1%)  
664          *
665          */
666         protected class FPValueFilter implements ChangeFilter  {
667                 
668                 private double percentage = 0.01;
669                 
670                 public FPValueFilter() {
671                         
672                 }
673                 
674                 public FPValueFilter(double percentage) {
675                         if (percentage < 0.0 || percentage > 1.0)
676                                 throw new IllegalArgumentException("Percentage must be between 0.0 and 1.0.");
677                         this.percentage = percentage;
678                 }
679                 
680                 @Override
681                 public boolean accept(ReadGraph g, Pair<Statement, Statement> change) throws DatabaseException {
682                         //filter floating point values that have less than 1% difference.
683                         if (!g.hasValue(change.first.getObject()) || !g.hasValue(change.second.getObject()))
684                                 return true;
685                 Object v1 = g.getValue(change.first.getObject());
686                 Object v2 = g.getValue(change.second.getObject());
687                 
688                 if (v1 instanceof Double && v2 instanceof Double) {
689                         double d1 = (Double)v1;
690                         double d2 = (Double)v2;
691                         if (Math.abs(d1-d2) / Math.max(Math.abs(d1), Math.abs(d2)) < percentage)
692                                 return false;
693                 } else if (v1 instanceof Float && v2 instanceof Float) {
694                         float d1 = (Float)v1;
695                         float d2 = (Float)v2;
696                         if (Math.abs(d1-d2) / Math.max(Math.abs(d1), Math.abs(d2)) < percentage)
697                                 return false;
698                 }
699
700                 return true;
701                 }
702         }
703
704         
705         private class FilterChangesRead implements Read<GraphChanges> {
706                 private GraphChanges changes;
707                 public FilterChangesRead(GraphChanges changes) {
708                         this.changes = changes;
709                 }
710                 
711                 @Override
712                 public GraphChanges perform(ReadGraph graph) throws DatabaseException {
713                         return filterChanges(graph, changes);
714                 }
715         }
716         
717         
718         private class ModificationListContentProvider implements IStructuredContentProvider {
719                 
720                 @SuppressWarnings("unchecked")
721                 @Override
722                 public Object[] getElements(Object inputElement) {
723                         if (inputElement == null)
724                                 return null;
725                         Collection<Pair<Statement, Statement>> coll = (Collection<Pair<Statement, Statement>>)inputElement;
726                         return coll.toArray();
727                 }
728                 
729                 @Override
730                 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
731                         
732                 }
733                 
734                 @Override
735                 public void dispose() {
736                         
737                 }
738         }
739         
740         private class UpdateTreeContentProvider implements ITreeContentProvider {
741                 @Override
742                 public Object[] getElements(Object inputElement) {
743                         if (inputElement instanceof UpdateTree)
744                                 return new Object[]{((UpdateTree)inputElement).getRootNode()};
745                         if (inputElement instanceof UpdateNode) {
746                                 UpdateNode node = (UpdateNode)inputElement;
747                                 return node.getChildren().toArray();
748                         }
749                         return new Object[0];
750                 }
751                 
752                 @Override
753                 public Object getParent(Object element) {
754                         return null;
755                 }
756                 
757                 @Override
758                 public Object[] getChildren(Object parentElement) {
759                         UpdateNode node = (UpdateNode)parentElement;
760                         return node.getChildren().toArray();
761                 }
762                 
763                 @Override
764                 public boolean hasChildren(Object element) {
765                         UpdateNode node = (UpdateNode)element;
766                         return node.getChildren().size() > 0;
767                 }
768                 
769                 @Override
770                 public void dispose() {
771                         
772                 }
773                 
774                 @Override
775                 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
776                         
777                 }
778         }
779         
780         private class SelectionLabelProvider extends ColumnLabelProvider {
781                 
782                 public SelectionLabelProvider() {
783                         
784                 }
785                 @Override
786                 public String getText(Object element) {
787                         return "";
788                 }
789                 
790                 @Override
791                 public Image getImage(Object element) {
792                         if (updateList == null)
793                                 return null;
794                         if (updateList.isSelected((Pair<Statement, Statement>) element))
795                                 return checked;
796                         else
797                                 return unchecked;
798                 }
799         }
800         
801         private class UpdateNodeLabelProvider extends ColumnLabelProvider {
802                 
803                 @Override
804                 public String getText(Object element) {
805                         final UpdateNode node = (UpdateNode)element;
806                         return node.getLabel();
807                 }
808                 
809                 @Override
810                 public Image getImage(Object element) {
811                         final UpdateNode node = (UpdateNode)element;
812                         try  {
813                                 ImageDescriptor id = getSession().syncRequest(new Read<ImageDescriptor>() {
814                                         @Override
815                                         public ImageDescriptor perform(ReadGraph graph) throws DatabaseException {
816                                                 return node.getImage(graph);
817                                         }
818                                 });
819                                 return manager.createImage(id);
820                         } catch (Exception e) {
821                                 return null;
822                         }
823                 }
824                 
825                 @Override
826                 public String getToolTipText(Object element) {
827                         final UpdateNode node = (UpdateNode)element;
828                         if (node.getOp() != null) {
829                                 return node.getOp().toString();
830                         } else {
831                                 return null;
832                         }
833                 }
834                 
835                 @Override
836                 public int getToolTipDisplayDelayTime(Object object) {
837                         return 1000;
838                 }
839                 
840                 @Override
841                 public int getToolTipTimeDisplayed(Object object) {
842                         return 10000;
843                 }
844
845                 @Override
846                 public Color getBackground(Object element) {
847                         final UpdateNode node = (UpdateNode)element;
848                         Status status = node.getStatus();
849                         if (status == Status.CONTAINS)
850                                 return containsColor;
851                         if (status == Status.DELETED)
852                                 return deletedColor;
853                         if (status == Status.NEW)
854                                 return addedColor;
855                         return null;            
856                 }
857         }
858         
859         private class SelectionEditingSupport extends EditingSupport {
860                 
861                 
862                 @SuppressWarnings("rawtypes")
863                 public SelectionEditingSupport(ColumnViewer viewer) {
864                         super(viewer);
865                         
866                 }
867
868                 @Override
869                 protected boolean canEdit(Object element) {
870                         return true;
871                 }
872                 
873                 @Override
874                 protected CellEditor getCellEditor(Object element) {
875                         return new CheckboxCellEditor(null, SWT.CHECK);
876                 }
877                 
878                 @Override
879                 protected Object getValue(Object element) {
880                         if (updateList == null)
881                                 return false;
882                         return updateList.isSelected((Pair<Statement, Statement>) element);
883                 }
884                 
885                 @SuppressWarnings("unchecked")
886                 @Override
887                 protected void setValue(Object element, Object value) {
888                         if (updateList == null)
889                                 return;
890                         if (Boolean.TRUE.equals(value))
891                                 updateList.addSelected((Pair<Statement, Statement>) element);
892                         else
893                                 updateList.removeSelected((Pair<Statement, Statement>) element);
894                         
895                         getViewer().refresh(element);
896                 }
897                 
898                 
899         }
900
901
902 }