--- /dev/null
+package org.simantics.interop.update.editor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Stack;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxCellEditor;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.ITreeViewerListener;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TreeExpansionEvent;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IEditorInput;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Statement;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.DoesNotContainValueException;
+import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
+import org.simantics.db.exception.NoSingleResultException;
+import org.simantics.db.exception.ServiceException;
+import org.simantics.db.request.Read;
+import org.simantics.interop.test.GraphChanges;
+import org.simantics.interop.test.GraphComparator;
+import org.simantics.interop.test.NameComparator;
+import org.simantics.interop.update.Activator;
+import org.simantics.interop.update.model.UpdateNode;
+import org.simantics.interop.update.model.UpdateNode.Status;
+import org.simantics.interop.update.model.UpdateTree;
+import org.simantics.interop.utils.TableUtils;
+import org.simantics.layer0.Layer0;
+import org.simantics.ui.workbench.ResourceEditorPart2;
+import org.simantics.utils.datastructures.BijectionMap;
+import org.simantics.utils.datastructures.Callback;
+import org.simantics.utils.datastructures.Pair;
+import org.simantics.utils.ui.ExceptionUtils;
+
+
+/**
+ * Editor for updating models.
+ *
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public abstract class ModelUpdateEditor extends ResourceEditorPart2 {
+
+
+ private Composite composite;
+ private Composite errorComposite;
+
+ private CheckboxTreeViewer changeBrowser;
+ private TableViewer changeViewer;
+
+ private GraphChanges changes;
+ private UpdateTree updateTree;
+
+ private Button updateAllButton;
+ private Button updateSelectedButton;
+
+ private LocalResourceManager manager = new LocalResourceManager(JFaceResources.getResources());
+
+ private Image checked;
+ private Image unchecked;
+ private Image warning;
+
+ private Color containsColor;
+ private Color deletedColor;
+ private Color addedColor;
+
+ private HashSet<Pair<Statement, Statement>> selected = new HashSet<Pair<Statement,Statement>>();
+
+ private HashSet<UpdateNode> selectedStructure = new HashSet<UpdateNode>();
+
+ private List<ChangeFilter> filters = new ArrayList<ChangeFilter>();
+
+ public ModelUpdateEditor() {
+ checked = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/tick.png"));
+ unchecked = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/cross.png"));
+ warning = manager.createImage(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/error.png"));
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+
+ containsColor = new Color(parent.getDisplay(), new RGB(255,255,220));
+ deletedColor = new Color(parent.getDisplay(), new RGB(255,220,220));
+ addedColor = new Color(parent.getDisplay(), new RGB(220,255,220));
+
+ composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(1,false));
+
+ errorComposite = new Composite(composite, SWT.BORDER);
+ GridData data = new GridData();
+ data.grabExcessHorizontalSpace = true;
+ data.grabExcessVerticalSpace = false;
+ data.horizontalAlignment = SWT.FILL;
+ data.verticalAlignment = SWT.TOP;
+ errorComposite.setLayoutData(data);
+ errorComposite.setLayout(new GridLayout(2, false));
+
+ errorComposite.setVisible(false);
+
+ IEditorInput input = getEditorInput();
+ if (!(input instanceof UpdateEditorInput)) {
+ Label label = new Label(composite, SWT.NONE);
+ label.setText("Unknown input.");
+ return;
+ }
+
+ Composite fillComposite = new Composite(composite, SWT.NONE);
+ data = new GridData();
+ data.grabExcessHorizontalSpace = true;
+ data.grabExcessVerticalSpace = true;
+ data.horizontalAlignment = SWT.FILL;
+ data.verticalAlignment = SWT.FILL;
+ fillComposite.setLayoutData(data);
+ fillComposite.setLayout(new FillLayout(SWT.VERTICAL));
+
+ {
+ changeBrowser = new CheckboxTreeViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION );
+
+ changeBrowser.setContentProvider(new UpdateTreeContentProvider());
+
+ changeBrowser.getTree().setHeaderVisible(true);
+
+ ColumnViewerToolTipSupport.enableFor(changeBrowser);
+
+
+ TreeViewerColumn dataColumn = TableUtils.addColumn(changeBrowser, "Data", true, 600);
+
+ dataColumn.setLabelProvider(new UpdateNodeLabelProvicer());
+
+ changeBrowser.addCheckStateListener(new ICheckStateListener() {
+
+ @Override
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ UpdateNode node = (UpdateNode) event.getElement();
+ if (node.getOp() != null) {
+ node.getOp().select(Boolean.TRUE.equals(event.getChecked()));
+
+ }
+ updateSelection();
+
+ }
+ });
+ changeBrowser.addTreeListener(new ITreeViewerListener() {
+
+ @Override
+ public void treeExpanded(TreeExpansionEvent event) {
+ event.getTreeViewer().getControl().getDisplay().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ updateSelection();
+ }
+ });
+
+ }
+
+ @Override
+ public void treeCollapsed(TreeExpansionEvent event) {
+
+ }
+ });
+ changeBrowser.setUseHashlookup(true);
+
+ }
+ {
+ changeViewer = new TableViewer(fillComposite,SWT.MULTI|SWT.V_SCROLL|SWT.BORDER|SWT.FULL_SELECTION);
+
+ changeViewer.getTable().setHeaderVisible(true);
+ changeViewer.getTable().setLinesVisible(true);
+
+ changeViewer.setContentProvider(new ModificationListContentProvider());
+
+ changeViewer.setUseHashlookup(true);
+
+ TableViewerColumn selection = TableUtils.addColumn(changeViewer, getColumntTitle(0), false, false, 20);
+ TableViewerColumn diagram = TableUtils.addColumn(changeViewer, getColumntTitle(1), true, true, 100);
+ TableViewerColumn symbol = TableUtils.addColumn(changeViewer, getColumntTitle(2), true, true, 100);
+ TableViewerColumn property = TableUtils.addColumn(changeViewer, getColumntTitle(3), true, true, 100);
+ TableViewerColumn oldValue = TableUtils.addColumn(changeViewer, getColumntTitle(4), true, true, 100);
+ TableViewerColumn newValue = TableUtils.addColumn(changeViewer, getColumntTitle(5), true, true, 100);
+
+ diagram.setLabelProvider(getLabelProvider(1));
+ symbol.setLabelProvider(getLabelProvider(2));
+ property.setLabelProvider(getLabelProvider(3));
+ oldValue.setLabelProvider(getLabelProvider(4));
+ newValue.setLabelProvider(getLabelProvider(5));
+
+ selection.setLabelProvider(new SelectionLabelProvider(selected));
+ selection.getColumn().addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (changes.getModifications().size() > 0) {
+ if (selected.contains(changes.getModifications().get(0))) {
+ for (Pair<Statement, Statement> nr : changes.getModifications())
+ selected.remove(nr);
+ } else {
+ for (Pair<Statement, Statement> nr : changes.getModifications())
+ selected.add(nr);
+ }
+ changeViewer.refresh();
+ }
+ }
+ });
+ selection.setEditingSupport(new SelectionEditingSupport(changeViewer, selected));
+
+ }
+ Composite buttonComposite = new Composite(composite, SWT.NONE);
+
+ data = new GridData();
+ data.grabExcessHorizontalSpace = true;
+ data.grabExcessVerticalSpace = false;
+ data.horizontalAlignment = SWT.FILL;
+ data.verticalAlignment = SWT.BOTTOM;
+
+ buttonComposite.setLayoutData(data);
+
+ buttonComposite.setLayout(new GridLayout(3, false));
+
+ Label label = new Label(buttonComposite, SWT.NONE);
+ data = new GridData();
+ data.grabExcessHorizontalSpace = true;
+ data.grabExcessVerticalSpace = false;
+ data.horizontalAlignment = SWT.FILL;
+ data.verticalAlignment = SWT.CENTER;
+ label.setLayoutData(data);
+
+ updateAllButton = new Button(buttonComposite, SWT.PUSH);
+ updateAllButton.setText("Update All");
+ updateAllButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ updateAll();
+ }
+ });
+ updateSelectedButton = new Button(buttonComposite, SWT.PUSH);
+ updateSelectedButton.setText("Update Selected");
+ updateSelectedButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ updateSelected();
+ }
+ });
+
+ load();
+
+ }
+
+ protected String getColumntTitle(int i) {
+ switch (i) {
+ case 0:
+ return "!";
+ case 1:
+ return "Diagram";
+ case 2:
+ return "Symbol";
+ case 3:
+ return "Property";
+ case 4:
+ return "Old Value";
+ case 5:
+ return "New Value";
+ default:
+ throw new RuntimeException("Unknown column index" + i);
+
+ }
+ }
+
+ protected abstract ColumnLabelProvider getLabelProvider(int i);
+ protected abstract Pair<GraphComparator,Boolean> getChanges(Resource r1, Resource r2) throws DatabaseException;
+ protected abstract UpdateTree getUpdateTree(GraphChanges changes) throws DatabaseException;
+
+ protected void addFilters(List<ChangeFilter> filters) {
+
+ }
+
+ public GraphChanges getChanges() {
+ return changes;
+ }
+
+ private void showWarning(String text) {
+ errorComposite.setVisible(true);
+
+ Label label = new Label(errorComposite, SWT.NONE);
+ label.setImage(warning);
+ label = new Label(errorComposite, SWT.NONE);
+ label.setText(text);
+ //this.setStatusMessage("Update contains structural changes (new or deleted symbols), please create a new model.");
+ composite.layout(true);
+
+ }
+
+ private void updateSelection() {
+ Stack<UpdateNode> nodeStack = new Stack<UpdateNode>();
+ nodeStack.push((UpdateNode)updateTree.getRootNode());
+ while (!nodeStack.isEmpty()) {
+ UpdateNode n = nodeStack.pop();
+ if (n.getOp() != null) {
+ boolean applied = n.getOp().applied();
+ if (applied) {
+ changeBrowser.setChecked(n, true);
+ changeBrowser.setGrayed(n, true);
+ selectedStructure.remove(n);
+ } else {
+ boolean sel = n.getOp().selected();
+ if (sel) {
+ selectedStructure.add(n);
+
+ } else {
+ selectedStructure.remove(n);
+ }
+ changeBrowser.setChecked(n, sel);
+ changeBrowser.setGrayed(n, false);
+ }
+ } else {
+ changeBrowser.setGrayed(n, true);
+ changeBrowser.setChecked(n, true);
+ }
+ for (UpdateNode c : n.getChildren()) {
+ nodeStack.add((UpdateNode)c);
+ }
+ }
+
+ changeBrowser.refresh();
+ }
+
+
+
+ private void load() {
+
+ addFilters(filters);
+
+ UpdateEditorInput uei = (UpdateEditorInput)getEditorInput();
+ Resource r1 = uei.getR1();
+ Resource r2 = uei.getR2();
+
+
+ try {
+
+ Pair<GraphComparator,Boolean> result = getChanges(r1,r2);
+ GraphComparator comparator = result.first;
+ if (result.second)
+ showWarning("Structural symbols have been changed. Model update is not able to update these, please create a new model.");
+ comparator.test(getSession());
+ changes = comparator.getChanges();
+ changes = getSession().syncRequest(new FilterChangesRead(changes));
+ updateTree = getUpdateTree(changes);
+ } catch (DatabaseException e) {
+ Text text = new Text(composite, SWT.MULTI);
+ text.setText(e.getMessage());
+ e.printStackTrace();
+ return;
+ }
+
+
+
+ changeViewer.setInput(changes.getModifications());
+ changeBrowser.setInput(updateTree);
+ updateSelection();
+ }
+
+
+
+ private void updateAll() {
+ updateAllButton.setEnabled(false);
+ updateSelectedButton.setEnabled(false);
+ getSession().asyncRequest(new WriteRequest(){
+ @Override
+ public void perform(WriteGraph graph) throws DatabaseException {
+ for (Pair<Statement, Statement> mod : changes.getModifications()) {
+ applyLiteralChange(graph, mod);
+ }
+ selected.clear();
+ changes.getModifications().clear();
+
+ updateTree.getUpdateOps().applyAll(graph);
+
+ Display.getDefault().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+
+ updateAllButton.setEnabled(true);
+ updateSelectedButton.setEnabled(true);
+ updateSelection();
+ changeViewer.refresh();
+ }
+ });
+ }
+
+
+ }, new Callback<DatabaseException>() {
+ @Override
+ public void run(DatabaseException parameter) {
+ if (parameter != null)
+ ExceptionUtils.logAndShowError("Cannot update model", parameter);
+ }
+ });
+ }
+
+ private void applyLiteralChange(WriteGraph graph, Pair<Statement, Statement> mod) throws DoesNotContainValueException, ServiceException, ManyObjectsForFunctionalRelationException {
+
+ Resource s = changes.getComparable().getLeft(mod.second.getSubject());
+ Resource pred = mod.first.getPredicate();
+ if (graph.hasValue(mod.second.getObject())) {
+ Object value = graph.getValue(mod.second.getObject());
+ graph.claimLiteral(s, pred, value);
+ } else {
+ graph.deny(s,pred);
+ }
+
+
+ }
+
+ private void updateSelected() {
+ updateAllButton.setEnabled(false);
+ updateSelectedButton.setEnabled(false);
+ getSession().asyncRequest(new WriteRequest(){
+ @Override
+ public void perform(WriteGraph graph) throws DatabaseException {
+ for (Pair<Statement, Statement> mod : selected) {
+ changes.getModifications().remove(mod);
+ applyLiteralChange(graph, mod);
+ }
+ selected.clear();
+
+ updateTree.getUpdateOps().applySelected(graph);
+
+ Display.getDefault().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ changeViewer.refresh();
+ updateAllButton.setEnabled(true);
+ updateSelectedButton.setEnabled(true);
+ updateSelection();
+ }
+ });
+ }
+ });
+ }
+
+ @Override
+ public void setFocus() {
+ composite.setFocus();
+
+ }
+
+ /**
+ * Filters changes:
+ * 1. Changes that are not essential for model update (changes that can be found when the models are axcatly the same)
+ * 2. Runs custom filters for value changes.
+ *
+ * @param g
+ * @param changes
+ * @return
+ * @throws DatabaseException
+ */
+ protected GraphChanges filterChanges(ReadGraph g, GraphChanges changes) throws DatabaseException
+ {
+
+ List<Pair<Statement,Statement>> modifications = new ArrayList<Pair<Statement,Statement>>();
+
+ for (Pair<Statement, Statement> mod : changes.getModifications()) {
+
+ boolean accept = true;
+ for (ChangeFilter filter : filters) {
+ if (!filter.accept(g, mod)) {
+ accept = false;
+ break;
+ }
+ }
+ if (accept)
+ modifications.add(mod);
+ }
+ GraphChanges newChanges = new GraphChanges(changes.getResource1(),changes.getResource2(),changes.getDeletions(), changes.getAdditions(), modifications, changes.getComparable());
+ return newChanges;
+ }
+
+ public interface ChangeFilter {
+ public boolean accept(ReadGraph g, Pair<Statement, Statement> change) throws DatabaseException;
+ }
+
+
+
+
+ /**
+ *
+ * Filters floating point value changes (default filter is set filter when the change is less than 1%)
+ *
+ */
+ protected class FPValueFilter implements ChangeFilter {
+
+ private double percentage = 0.01;
+
+ public FPValueFilter() {
+
+ }
+
+ public FPValueFilter(double percentage) {
+ if (percentage < 0.0 || percentage > 1.0)
+ throw new IllegalArgumentException("Percentage must be between 0.0 and 1.0.");
+ this.percentage = percentage;
+ }
+
+ @Override
+ public boolean accept(ReadGraph g, Pair<Statement, Statement> change) throws DatabaseException {
+ //filter floating point values that have less than 1% difference.
+ if (!g.hasValue(change.first.getObject()) || !g.hasValue(change.second.getObject()))
+ return true;
+ Object v1 = g.getValue(change.first.getObject());
+ Object v2 = g.getValue(change.second.getObject());
+
+ if (v1 instanceof Double && v2 instanceof Double) {
+ double d1 = (Double)v1;
+ double d2 = (Double)v2;
+ if (Math.abs(d1-d2) / Math.max(Math.abs(d1), Math.abs(d2)) < percentage)
+ return false;
+ } else if (v1 instanceof Float && v2 instanceof Float) {
+ float d1 = (Float)v1;
+ float d2 = (Float)v2;
+ if (Math.abs(d1-d2) / Math.max(Math.abs(d1), Math.abs(d2)) < percentage)
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+
+ private class FilterChangesRead implements Read<GraphChanges> {
+ private GraphChanges changes;
+ public FilterChangesRead(GraphChanges changes) {
+ this.changes = changes;
+ }
+
+ @Override
+ public GraphChanges perform(ReadGraph graph) throws DatabaseException {
+ return filterChanges(graph, changes);
+ }
+ }
+
+
+ private class ModificationListContentProvider implements IStructuredContentProvider {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object[] getElements(Object inputElement) {
+ if (inputElement == null)
+ return null;
+ Collection<Pair<Statement, Statement>> coll = (Collection<Pair<Statement, Statement>>)inputElement;
+ return coll.toArray();
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+
+ }
+
+ @Override
+ public void dispose() {
+
+ }
+ }
+
+ private class UpdateTreeContentProvider implements ITreeContentProvider {
+ @Override
+ public Object[] getElements(Object inputElement) {
+ if (inputElement instanceof UpdateTree)
+ return new Object[]{((UpdateTree)inputElement).getRootNode()};
+ if (inputElement instanceof UpdateNode) {
+ UpdateNode node = (UpdateNode)inputElement;
+ return node.getChildren().toArray();
+ }
+ return new Object[0];
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ return null;
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ UpdateNode node = (UpdateNode)parentElement;
+ return node.getChildren().toArray();
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ UpdateNode node = (UpdateNode)element;
+ return node.getChildren().size() > 0;
+ }
+
+ @Override
+ public void dispose() {
+
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+
+ }
+ }
+
+ private class SelectionLabelProvider extends ColumnLabelProvider {
+
+ Collection<?> selected;
+ public SelectionLabelProvider(Collection<?> selected) {
+ this.selected = selected;
+ }
+ @Override
+ public String getText(Object element) {
+ return "";
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ if (selected.contains(element))
+ return checked;
+ else
+ return unchecked;
+ }
+ }
+
+ private class UpdateNodeLabelProvicer extends ColumnLabelProvider {
+
+ @Override
+ public String getText(Object element) {
+ final UpdateNode node = (UpdateNode)element;
+ try {
+ return getSession().syncRequest(new Read<String>() {
+ @Override
+ public String perform(ReadGraph graph) throws DatabaseException {
+ return node.getLabel(graph);
+ }
+ });
+ } catch (Exception e) {
+ return e.getMessage();
+ }
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ final UpdateNode node = (UpdateNode)element;
+ try {
+ ImageDescriptor id = getSession().syncRequest(new Read<ImageDescriptor>() {
+ @Override
+ public ImageDescriptor perform(ReadGraph graph) throws DatabaseException {
+ return node.getImage(graph);
+ }
+ });
+ return manager.createImage(id);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ @Override
+ public String getToolTipText(Object element) {
+ final UpdateNode node = (UpdateNode)element;
+ if (node.getOp() != null) {
+ return node.getOp().toString();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public int getToolTipDisplayDelayTime(Object object) {
+ return 1000;
+ }
+
+ @Override
+ public int getToolTipTimeDisplayed(Object object) {
+ return 10000;
+ }
+
+ @Override
+ public Color getBackground(Object element) {
+ final UpdateNode node = (UpdateNode)element;
+ Status status = node.getStatus();
+ if (status == Status.CONTAINS)
+ return containsColor;
+ if (status == Status.DELETED)
+ return deletedColor;
+ if (status == Status.NEW)
+ return addedColor;
+ return null;
+ }
+ }
+
+ private class SelectionEditingSupport extends EditingSupport {
+
+ @SuppressWarnings("rawtypes")
+ Collection selected;
+
+
+ @SuppressWarnings("rawtypes")
+ public SelectionEditingSupport(ColumnViewer viewer, Collection selected) {
+ super(viewer);
+ this.selected = selected;
+
+ }
+
+ @Override
+ protected boolean canEdit(Object element) {
+ return true;
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element) {
+ return new CheckboxCellEditor(null, SWT.CHECK);
+ }
+
+ @Override
+ protected Object getValue(Object element) {
+ return selected.contains(element);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void setValue(Object element, Object value) {
+ if (Boolean.TRUE.equals(value))
+ selected.add(element);
+ else
+ selected.remove(element);
+
+ getViewer().refresh(element);
+ }
+
+
+ }
+
+
+}