org.dawnsci.plotting.tools.history.ImageHistoryTool.java Source code

Java tutorial

Introduction

Here is the source code for org.dawnsci.plotting.tools.history.ImageHistoryTool.java

Source

/*
 * Copyright (c) 2012 Diamond Light Source Ltd.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package org.dawnsci.plotting.tools.history;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.dawb.common.gpu.IOperation;
import org.dawb.common.gpu.OperationFactory;
import org.dawb.common.gpu.Operator;
import org.dawb.common.ui.components.cell.ScaleCellEditor;
import org.dawb.common.ui.plot.tools.HistoryType;
import org.dawnsci.plotting.tools.Activator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.dawnsci.analysis.api.dataset.IDataset;
import org.eclipse.dawnsci.analysis.api.monitor.IMonitor;
import org.eclipse.dawnsci.analysis.dataset.impl.Dataset;
import org.eclipse.dawnsci.analysis.dataset.impl.IntegerDataset;
import org.eclipse.dawnsci.plotting.api.expressions.IExpressionObject;
import org.eclipse.dawnsci.plotting.api.preferences.PlottingConstants;
import org.eclipse.dawnsci.plotting.api.trace.IImageTrace;
import org.eclipse.dawnsci.plotting.api.trace.ITrace;
import org.eclipse.dawnsci.plotting.api.trace.ITraceListener;
import org.eclipse.dawnsci.plotting.api.trace.TraceEvent;
import org.eclipse.dawnsci.plotting.api.trace.TraceWillPlotEvent;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.events.MouseListener;
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.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Scale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Tool whereby images may be added to a static list which has various
 * operations. TODO Create a static method for adding images, for instance
 * from the Project Explorer.
 * 
 * @author Matthew Gerring
 *
 */
public class ImageHistoryTool extends AbstractHistoryTool implements MouseListener {

    private static Logger logger = LoggerFactory.getLogger(ImageHistoryTool.class);

    /**
     * We simply keep the history in a static map of traces.
     */
    private static final Map<String, HistoryBean> imageHistory;
    static {
        imageHistory = new LinkedHashMap<String, HistoryBean>(17);
    }

    protected Map<String, HistoryBean> getHistoryCache() {
        return imageHistory;
    }

    @Override
    public Serializable getToolData() {
        if (imageHistory == null || imageHistory.isEmpty())
            return null;
        final Map<String, IDataset> data = new HashMap<String, IDataset>(imageHistory.size());
        for (String key : imageHistory.keySet()) {
            data.put(key, imageHistory.get(key).getData());
        }
        return (Serializable) data;
    }

    /**
     * Assigned on the first activate and then kept to avoid
     * the wrong data being used as the base because the plot
     * will be changing.
     */
    private Dataset originalData;
    private MathsJob updateJob;

    private IOperation operation;

    private static ImageHistoryTool currentTool;

    private enum ImageHistoryMarker {
        MARKER
    }

    public ImageHistoryTool() {
        super(false);
        this.updateJob = new MathsJob();

        // Use CPU it is *not* slower for the maths this tool does
        // To try GPU change to getBasicGpuOperation()
        this.operation = OperationFactory.getBasicCpuOperation();

        this.traceListener = new ITraceListener.Stub() {

            @Override
            public void traceAdded(TraceEvent evt) {
                if (!isActive())
                    return;
                if (updatingPlotsAlready)
                    return;
                if (((IImageTrace) evt.getSource()).getUserObject() == ImageHistoryMarker.MARKER)
                    return;
                updatePlots(false);
            }

            @Override
            public void traceRemoved(TraceEvent evt) {
                if (!isActive())
                    return;
                if (updatingPlotsAlready)
                    return;
                if (((IImageTrace) evt.getSource()).getUserObject() == ImageHistoryMarker.MARKER)
                    return;
                updatePlots(false);
            }

            @Override
            public void traceWillPlot(final TraceWillPlotEvent evt) {
                if (!isActive())
                    return;
                if (updatingPlotsAlready)
                    return;
                if (evt.getImageTrace() == null)
                    return;
                if (evt.getImageTrace().getUserObject() == ImageHistoryMarker.MARKER)
                    return;
                originalData = (Dataset) evt.getImage();
                if (getImageTrace() == null)
                    return;
                if (!isActiveSelections())
                    return;

                Dataset set = getCombinedData(null);
                if (set == null)
                    return;
                if (set.getSize() == 1) {
                    evt.doit = false;
                    return;
                }
                if (!set.isCompatibleWith(originalData))
                    return;

                evt.getImageTrace().setUserObject(ImageHistoryMarker.MARKER);
                evt.setImageData(set, evt.getImageTrace().getAxes());
            }

        };

    }

    @Override
    public void activate() {

        currentTool = this;
        if (getPlottingSystem() != null && originalData == null) {

            final IImageTrace imageTrace = getImageTrace();
            if (imageTrace != null && imageTrace.getUserObject() != ImageHistoryMarker.MARKER) {
                this.originalData = imageTrace != null ? (Dataset) imageTrace.getData() : null;
            }
        }
        super.activate();
        refresh();
    }

    public void deactivate() {
        currentTool = null;
        super.deactivate();
        operation.deactivate(); // It can still be used
    }

    @Override
    public ToolPageRole getToolPageRole() {
        return ToolPageRole.ROLE_2D;
    }

    @Override
    protected IAction createAddAction() {
        return new Action("Add image to compare table", Activator.getImageDescriptor("icons/add.png")) {
            public void run() {
                final Collection<ITrace> traces = getPlottingSystem().getTraces(IImageTrace.class);
                if (traces == null || traces.isEmpty())
                    return;

                // TODO Check if one of our history traces.
                for (ITrace iTrace : traces) {

                    if (iTrace.getUserObject() == HistoryType.HISTORY_PLOT)
                        continue;
                    final IImageTrace imageTrace = (IImageTrace) iTrace;
                    String plotName = getPlottingSystem().getTitle();
                    if (plotName == null || "".equals(plotName)) {
                        plotName = imageTrace.getName();
                    }
                    addImageToHistory((Dataset) imageTrace.getData(), plotName);
                }
                refresh();
            }
        };
    }

    protected void addImageToHistory(final Dataset data, String name) {

        if (name == null || "".equals(name))
            name = data.getName();
        if ("".equals(name))
            name = null;
        if (name == null)
            name = getPart().getTitle();

        final HistoryBean bean = new HistoryBean(this);
        bean.setData(data);
        final List<IDataset> axes = getImageTrace() != null ? getImageTrace().getAxes() : null;
        bean.setAxes(axes);
        bean.setTraceName(name);
        bean.setPlotName(getPlottingSystem().getPlotName());
        bean.setOperator(Operator.ADD);
        final String key = bean.getTraceKey();
        imageHistory.put(key, bean);
    }

    private static IAction include;

    protected MenuManager createActions(MenuManager manager) {

        if (include == null) {
            include = new Action("Include current plot",
                    Activator.getImageDescriptor("icons/include-current-image.png")) {

                public void run() {
                    Activator.getPlottingPreferenceStore().setValue(PlottingConstants.INCLUDE_ORIGINAL,
                            isChecked());
                    if (currentTool != null) {
                        currentTool.updatePlots(false);
                        currentTool.refresh();
                    }
                }
            };
            include.setChecked(
                    Activator.getPlottingPreferenceStore().getBoolean(PlottingConstants.INCLUDE_ORIGINAL));
        }

        final IAction revert = new Action("Revert plot", Activator.getImageDescriptor("icons/reset.gif")) {
            public void run() {
                Dataset plot = getOriginalData();
                if (plot == null)
                    return;

                for (String key : imageHistory.keySet()) {
                    imageHistory.get(key).setSelected(false);
                }
                setPlotImage(plot);
                Activator.getPlottingPreferenceStore().setValue(PlottingConstants.INCLUDE_ORIGINAL, true);
                include.setChecked(true);
                refresh();
            }
        };

        final IAction up = new Action("Move up", Activator.getImageDescriptor("icons/arrow_up.png")) {
            public void run() {
                moveBean(-1);
            }
        };

        final IAction down = new Action("Move down", Activator.getImageDescriptor("icons/arrow_down.png")) {
            public void run() {
                moveBean(1);
            }
        };

        getSite().getActionBars().getToolBarManager().add(include);
        getSite().getActionBars().getToolBarManager().add(revert);
        getSite().getActionBars().getToolBarManager().add(new Separator());

        getSite().getActionBars().getToolBarManager().add(up);
        getSite().getActionBars().getToolBarManager().add(down);
        getSite().getActionBars().getToolBarManager().add(new Separator());

        manager.add(include);
        manager.add(revert);
        manager.add(new Separator());
        manager.add(up);
        manager.add(down);
        manager.add(new Separator());

        super.createActions(manager);

        return manager;
    }

    protected Dataset getOriginalData() {

        // Try and read the original data from the editor.
        return originalData; // We attempt to cache it otherwise.
    }

    protected void moveBean(int i) {

        final HistoryBean bean = getSelectedPlot();
        if (bean == null)
            return;

        final List<String> keys = new ArrayList<String>(imageHistory.keySet());
        final Map<String, HistoryBean> tmp = new HashMap<String, HistoryBean>(imageHistory);
        final int index = keys.indexOf(bean.getTraceKey());
        if (index < 0)
            return;

        if (index + 1 > keys.size() || index + 1 < 0)
            return;

        keys.remove(index);
        keys.add(index + i, bean.getTraceKey());

        imageHistory.clear();
        for (String key : keys) {
            imageHistory.put(key, tmp.get(key));
        }
        refresh();
        updatePlots(false);
    }

    @Override
    protected void updatePlots(boolean force) {
        if (!getPlottingSystem().is2D()) {
            logger.error("Plotting system is not plotting 2D data, image history should not be active.");
            return;
        }
        if (updatingPlotsAlready && !force)
            return;
        updatingPlotsAlready = true;
        updateJob.cancel();
        updateJob.schedule();
    }

    private class MathsJob extends Job {

        public MathsJob() {
            super("Process images");
            setUser(false);
            setPriority(Job.INTERACTIVE);
        }

        public IStatus run(IProgressMonitor monitor) {

            try {
                // Do nothing if 1D data plotted
                if (!getPlottingSystem().is2D())
                    return Status.CANCEL_STATUS;
                if (!isActive())
                    return Status.CANCEL_STATUS;
                if (!getPlottingSystem().getPlotType().is2D())
                    return Status.CANCEL_STATUS;

                final long start = System.currentTimeMillis();
                Dataset a = getCombinedData(monitor);
                if (a == null)
                    return Status.CANCEL_STATUS;
                if (a.getSize() == 1) {
                    getPlottingSystem().clear();
                    return Status.CANCEL_STATUS;
                }

                final long end = System.currentTimeMillis();
                logger.trace("Processed image maths in " + (end - start));

                setPlotImage(a);

                return Status.OK_STATUS;

            } finally {
                updatingPlotsAlready = false;
            }
        }

    }

    /**
     * 
     * @return Data to plot, size 1 dataset to do clear, null to do nothing
     */
    private Dataset getCombinedData(IProgressMonitor monitor) {

        boolean includeCurrentPlot = Activator.getPlottingPreferenceStore()
                .getBoolean(PlottingConstants.INCLUDE_ORIGINAL);

        // Loop over history and reprocess maths.
        Dataset od = getOriginalData();
        if (!isActiveSelections()) {
            if (includeCurrentPlot) {
                return od;
            } else {
                return new IntegerDataset(1); // Clear
            }
        }

        Dataset a = od != null && includeCurrentPlot ? od : null;
        if (od != null && od.getRank() != 2)
            return null; // This is image compare!

        for (String key : imageHistory.keySet()) {

            if (monitor != null && monitor.isCanceled())
                return null;
            if (!isActive())
                return null;

            final HistoryBean bean = imageHistory.get(key);
            if (bean == null)
                continue;
            if (!bean.isSelected())
                continue;
            if (bean.getWeighting() < 1)
                continue;

            if (a == null) {
                if (bean.getData() == null)
                    continue;
                a = bean.getData();
                continue;
            }

            if (!a.isCompatibleWith(bean.getData())) {
                bean.setSelected(false);
                Display.getDefault().syncExec(new Runnable() {
                    public void run() {
                        viewer.refresh(bean);
                    }
                });
                continue;
            }

            Dataset data = bean.getData();
            if (bean.getWeighting() < 100) { // Reduce its intensity
                data = operation.process(data, bean.getWeighting() / 100d, Operator.MULTIPLY);
            }
            a = operation.process(a, data, bean.getOperator());
        }

        return a;
    }

    public void setPlotImage(final Dataset plot) {

        Display.getDefault().syncExec(new Runnable() {
            public void run() {
                if (!getPlottingSystem().is2D())
                    return;
                if (!isActive())
                    return;
                if (!getPlottingSystem().getPlotType().is2D())
                    return;

                getPlottingSystem().removeTraceListener(traceListener);
                try {
                    IImageTrace imageTrace = getImageTrace();
                    if (imageTrace == null) {
                        getPlottingSystem().setFocus();
                        getPlottingSystem().reset();
                        imageTrace = getPlottingSystem()
                                .createImageTrace(plot.getName() != null ? plot.getName() : "");
                        imageTrace.setData(plot, null, false);
                        getPlottingSystem().addTrace(imageTrace);
                        getPlottingSystem().autoscaleAxes();
                        return;
                    }

                    boolean current = updatingPlotsAlready;
                    try {
                        updatingPlotsAlready = true;
                        getPlottingSystem().clear();
                    } finally {
                        updatingPlotsAlready = current;
                    }
                    final IImageTrace image = getPlottingSystem()
                            .createImageTrace(imageTrace != null ? imageTrace.getName() : "Image");
                    if (image == null)
                        return;
                    image.setData(plot, imageTrace != null ? imageTrace.getAxes() : null, false);
                    image.setUserObject(ImageHistoryMarker.MARKER);
                    getPlottingSystem().addTrace(image);
                    getPlottingSystem().repaint();

                } catch (Throwable ne) {
                    logger.error(ImageHistoryTool.class.getSimpleName()
                            + " unable to process image. This might not be a fatal error because an image might not be plotted.");
                } finally {
                    getPlottingSystem().addTraceListener(traceListener);
                }
            }
        });
    }

    protected boolean isActiveSelections() {
        final Map<String, HistoryBean> history = getHistoryCache();
        if (history == null || history.size() < 1)
            return false;
        for (HistoryBean historyBean : history.values()) {
            if (historyBean.isSelected())
                return true;
        }
        return false;
    }

    protected boolean isEmpty() {
        final Map<String, HistoryBean> history = getHistoryCache();
        if (history == null || history.size() < 1)
            return true;
        return false;
    }

    @Override
    protected void updatePlot(HistoryBean bean, boolean force) {
        updatePlots(force); // We update everything when one changes.
    }

    @Override
    protected int createColumns(TableViewer viewer) {

        viewer.getTable().addListener(SWT.MeasureItem, new Listener() {
            public void handleEvent(Event event) {
                // height cannot be per row so simply set
                event.height = 40;
            }
        });
        ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE);
        viewer.setColumnProperties(new String[] { "Selected", "Name", "Original Plot", "Operator" });

        TableViewerColumn var = new TableViewerColumn(viewer, SWT.LEFT, 0);
        var.getColumn().setText("Plot"); // Selected
        var.getColumn().setWidth(50);
        var.setLabelProvider(new ImageCompareLabelProvider());

        var = new TableViewerColumn(viewer, SWT.CENTER, 1);
        var.getColumn().setText("Name");
        var.getColumn().setWidth(200);
        var.setLabelProvider(new ImageCompareLabelProvider());
        var.setEditingSupport(new ImageNameEditingSupport(viewer));

        var = new TableViewerColumn(viewer, SWT.CENTER, 2);
        var.getColumn().setText("Original File");
        var.getColumn().setWidth(0);
        var.getColumn().setMoveable(false);
        var.getColumn().setResizable(false);
        var.setLabelProvider(new ImageCompareLabelProvider());

        var = new TableViewerColumn(viewer, SWT.CENTER, 3);
        var.getColumn().setText("Operator");
        var.getColumn().setWidth(100);
        var.setLabelProvider(new ImageCompareLabelProvider());
        var.setEditingSupport(new ImageOperatorEditingSupport(viewer));

        var = new TableViewerColumn(viewer, SWT.CENTER, 4);
        var.getColumn().setText("Shape");
        var.getColumn().setWidth(150);
        var.setLabelProvider(new ImageCompareLabelProvider());

        var = new TableViewerColumn(viewer, SWT.CENTER, 5);
        var.getColumn().setText("Weight");
        var.getColumn().setWidth(150);
        var.setLabelProvider(new ImageCompareLabelProvider());
        var.setEditingSupport(new ImageWeightingEditingSupport(viewer));

        return 6;
    }

    private class ImageCompareLabelProvider extends ColumnLabelProvider {

        private Image checkedIcon;
        private Image uncheckedIcon;
        private Color BLUE, RED;

        public ImageCompareLabelProvider() {

            ImageDescriptor id = Activator.getImageDescriptor("icons/ticked.png");
            checkedIcon = id.createImage();
            id = Activator.getImageDescriptor("icons/unticked.gif");
            uncheckedIcon = id.createImage();
            BLUE = Display.getDefault().getSystemColor(SWT.COLOR_BLUE);
            RED = Display.getDefault().getSystemColor(SWT.COLOR_RED);
        }

        private int columnIndex;

        public void update(ViewerCell cell) {
            columnIndex = cell.getColumnIndex();
            super.update(cell);
        }

        public Image getImage(Object element) {

            if (!(element instanceof HistoryBean))
                return null;

            if (columnIndex == 0) {
                final HistoryBean bean = (HistoryBean) element;
                return bean.isSelected() ? checkedIcon : uncheckedIcon;
            }

            return null;
        }

        public String getText(Object element) {

            if (element instanceof String)
                return "";

            final HistoryBean bean = (HistoryBean) element;
            if (columnIndex == 1) {
                final IExpressionObject o = bean.getExpression();
                if (o != null)
                    return o.getExpressionString();
                return bean.getTraceName();
            }
            if (columnIndex == 2) {
                return bean.getPlotName();
            }
            if (columnIndex == 3) {
                boolean includeCurrentPlot = Activator.getPlottingPreferenceStore()
                        .getBoolean(PlottingConstants.INCLUDE_ORIGINAL);
                if (getIndex(bean) == 0 && !includeCurrentPlot)
                    return "";
                return bean.getOperator().getName();
            }
            if (columnIndex == 4) {
                try {
                    return Arrays.toString(bean.getData().getShape());
                } catch (Throwable ne) {
                    return "";
                }
            }
            if (columnIndex == 5) {
                return bean.getWeighting() + " %";
            }
            return "";
        }

        private int getIndex(HistoryBean bean) {
            final List<String> keys = new ArrayList<String>(imageHistory.keySet());
            return keys.indexOf(bean.getTraceKey());
        }

        public Color getForeground(Object element) {
            if (!(element instanceof HistoryBean))
                return null;
            HistoryBean bean = (HistoryBean) element;

            if (columnIndex == 1) {
                final IExpressionObject o = ((HistoryBean) element).getExpression();
                if (o != null) {
                    return o.isValid(new IMonitor.Stub()) ? BLUE : RED;
                }
            }

            if (columnIndex == 4 && !isShapeCompatible(element)) {
                return Display.getDefault().getSystemColor(SWT.COLOR_RED);
            }

            return bean.isSelected() ? Display.getDefault().getSystemColor(SWT.COLOR_BLACK)
                    : Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY);
        }

        public String getToolTipText(Object element) {
            if (!isShapeCompatible(element))
                return "Shape of compare image is not the same as the plot.";
            return super.getToolTipText(element);
        }

        private boolean isShapeCompatible(Object element) {
            final Dataset od = getOriginalData();
            if (od == null)
                return true;
            if (!(element instanceof HistoryBean))
                return true;
            HistoryBean bean = (HistoryBean) element;
            if (bean.getData() == null)
                return false;
            return od.isCompatibleWith(bean.getData());
        }

        public void dispose() {
            super.dispose();
            checkedIcon.dispose();
            uncheckedIcon.dispose();
        }
    }

    private class ImageNameEditingSupport extends EditingSupport {

        public ImageNameEditingSupport(ColumnViewer viewer) {
            super(viewer);
        }

        @Override
        protected CellEditor getCellEditor(Object element) {
            return new TextCellEditor((Composite) getViewer().getControl());
        }

        @Override
        protected boolean canEdit(Object element) {
            return true;
        }

        @Override
        protected Object getValue(Object element) {
            return ((HistoryBean) element).getTraceName();
        }

        @Override
        protected void setValue(Object element, Object value) {
            final HistoryBean bean = (HistoryBean) element;
            final IExpressionObject o = bean.getExpression();
            if (o != null) {
                o.setExpressionString((String) value);
                clearExpressionCache();
            } else {
                final String old = bean.getTraceKey();
                final String key = bean.setTraceName((String) value, true);
                imageHistory.remove(old);
                imageHistory.put(key, bean);
            }
            viewer.refresh(element);
        }

    }

    private class ImageOperatorEditingSupport extends EditingSupport {

        public ImageOperatorEditingSupport(ColumnViewer viewer) {
            super(viewer);
        }

        @Override
        protected CellEditor getCellEditor(final Object element) {
            ComboBoxCellEditor ed = new ComboBoxCellEditor((Composite) getViewer().getControl(),
                    Operator.getOperators(), SWT.READ_ONLY);

            ((CCombo) ed.getControl()).addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    ImageOperatorEditingSupport.this.setValue(element,
                            ((CCombo) e.getSource()).getSelectionIndex());
                }
            });
            return ed;
        }

        @Override
        protected boolean canEdit(Object element) {
            return true;
        }

        @Override
        protected Object getValue(Object element) {
            return ((HistoryBean) element).getOperator().getIndex();
        }

        @Override
        protected void setValue(Object element, Object value) {
            ((HistoryBean) element).setOperator(Operator.getOperator((Integer) value));
            ((HistoryBean) element).setSelected(true);
            viewer.refresh(element);
            updatePlots(false);
        }

    }

    private class ImageWeightingEditingSupport extends EditingSupport {

        public ImageWeightingEditingSupport(ColumnViewer viewer) {
            super(viewer);
        }

        @Override
        protected CellEditor getCellEditor(final Object element) {
            final ScaleCellEditor ed = new ScaleCellEditor((Composite) getViewer().getControl());
            ed.setMinimum(0);
            ed.setMaximum(100);
            ed.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    int value = ((Scale) e.getSource()).getSelection();
                    HistoryBean bean = (HistoryBean) element;
                    if (value == 0) {
                        bean.setWeighting(0);
                        bean.setSelected(false);
                    } else if (value > 100) {
                        bean.setWeighting(100);
                        bean.setSelected(true);
                    } else {
                        bean.setWeighting(value);
                        bean.setSelected(true);
                    }
                    ed.getControl().setToolTipText(String.valueOf(value));
                    viewer.update(bean, new String[] { "Selected" });
                    updateJob.cancel();
                    updateJob.schedule();
                }
            });
            return ed;
        }

        @Override
        protected boolean canEdit(Object element) {
            return true;
        }

        @Override
        protected Object getValue(Object element) {
            return ((HistoryBean) element).getWeighting();
        }

        @Override
        protected void setValue(Object element, Object value) {
            ((HistoryBean) element).setWeighting((Integer) value);
            viewer.refresh(element);
            updatePlots(false);
        }

    }

    @Override
    public void setData(Object obj) {
        if (obj instanceof List<?>) {
            List<?> images = (List<?>) obj;
            clearCache();
            for (Object image : images) {
                if (image instanceof Dataset)
                    addImageToHistory((Dataset) image, ((Dataset) image).getName());
            }
        }
    }
}