org.dawb.workbench.ui.data.PlotDataComponent.java Source code

Java tutorial

Introduction

Here is the source code for org.dawb.workbench.ui.data.PlotDataComponent.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.dawb.workbench.ui.data;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EventListener;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.dawb.common.services.ServiceManager;
import org.dawb.common.ui.DawbUtils;
import org.dawb.common.ui.monitor.ProgressMonitorWrapper;
import org.dawb.common.ui.plot.tools.IDataReductionToolPage;
import org.dawb.common.ui.util.DialogUtils;
import org.dawb.common.ui.util.EclipseUtils;
import org.dawb.common.util.io.FileUtils;
import org.dawb.common.util.io.PropUtils;
import org.dawb.common.util.text.NumberUtils;
import org.dawb.workbench.ui.Activator;
import org.dawb.workbench.ui.data.wizard.PythonFilterWizard;
import org.dawb.workbench.ui.editors.preference.EditorConstants;
import org.dawb.workbench.ui.editors.preference.EditorPreferencePage;
import org.dawb.workbench.ui.transferable.TransferableDataObject;
import org.dawnsci.conversion.ui.ConvertWizard;
import org.dawnsci.io.h5.H5Loader;
import org.dawnsci.plotting.AbstractPlottingSystem;
import org.dawnsci.plotting.services.util.DatasetTitleUtils;
import org.dawnsci.plotting.tools.reduction.DataReductionWizard;
import org.dawnsci.python.rpc.action.InjectPyDevConsole;
import org.dawnsci.python.rpc.action.InjectPyDevConsoleAction;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.dawnsci.analysis.api.dataset.IDataset;
import org.eclipse.dawnsci.analysis.api.dataset.IErrorDataset;
import org.eclipse.dawnsci.analysis.api.dataset.ILazyDataset;
import org.eclipse.dawnsci.analysis.api.io.IDataHolder;
import org.eclipse.dawnsci.analysis.api.io.ILoaderService;
import org.eclipse.dawnsci.analysis.api.metadata.IMetadata;
import org.eclipse.dawnsci.analysis.api.monitor.IMonitor;
import org.eclipse.dawnsci.plotting.api.IPlottingSystem;
import org.eclipse.dawnsci.plotting.api.IPlottingSystemSelection;
import org.eclipse.dawnsci.plotting.api.PlotType;
import org.eclipse.dawnsci.plotting.api.axis.IAxis;
import org.eclipse.dawnsci.plotting.api.expressions.IExpressionObject;
import org.eclipse.dawnsci.plotting.api.expressions.IExpressionObjectService;
import org.eclipse.dawnsci.plotting.api.expressions.IVariableManager;
import org.eclipse.dawnsci.plotting.api.tool.IToolChangeListener;
import org.eclipse.dawnsci.plotting.api.tool.IToolPage;
import org.eclipse.dawnsci.plotting.api.tool.IToolPageSystem;
import org.eclipse.dawnsci.plotting.api.tool.ToolChangeEvent;
import org.eclipse.dawnsci.plotting.api.trace.ITraceListener;
import org.eclipse.dawnsci.plotting.api.trace.TraceEvent;
import org.eclipse.dawnsci.slicing.api.data.ITransferableDataObject;
import org.eclipse.dawnsci.slicing.api.data.ITransferableDataService;
import org.eclipse.dawnsci.slicing.api.system.DimsData;
import org.eclipse.dawnsci.slicing.api.system.DimsDataList;
import org.eclipse.dawnsci.slicing.api.system.ISliceSystem;
import org.eclipse.dawnsci.slicing.api.util.SliceUtils;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.JFacePreferences;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.resource.ColorRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Region;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.progress.IProgressService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import uk.ac.diamond.scisoft.analysis.io.LoaderFactory;
import uk.ac.diamond.scisoft.analysis.utils.OSUtils;

/**
 * This view can view and plot any file. It is most efficient if the Loader that LoaderFactory
 * uses for this file type is an IMetaLoader. 
 */
public class PlotDataComponent
        implements IVariableManager, MouseListener, KeyListener, IPlottingSystemSelection, IAdaptable {

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

    // Use table as it might get extended to do more later.
    protected TableViewer dataViewer;

    /**
     * data is the objects for the table, either a String or an ExpressionObject
     * currently. Probably a better design possible with a single object type.
     */
    protected List<ITransferableDataObject> data;
    protected String filePath;
    protected String fileName;
    private String rootName;
    private boolean staggerSupported = false;

    private IWorkbenchPart editor;
    private IPropertyChangeListener propListener;
    private ArrayList<IAction> dataComponentActions;
    private Composite container;
    private DataTableFilter dataFilter;

    private IAction dataReduction;
    private ITraceListener traceListener;
    private ITraceListener dataViewRefreshListener;
    private IToolChangeListener toolListener;

    private IDataHolder dataHolder;
    private IMetadata metaData;

    private ITransferableDataService transferableService;
    private IExpressionObjectService expressionService;

    public PlotDataComponent(final IWorkbenchPart editor) throws Exception {

        this.data = new ArrayList<ITransferableDataObject>(7);
        this.editor = editor;

        this.expressionService = (IExpressionObjectService) ServiceManager
                .getService(IExpressionObjectService.class);
        this.transferableService = (ITransferableDataService) ServiceManager
                .getService(ITransferableDataService.class);

        this.propListener = new IPropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent event) {
                if (event.getProperty().equals(EditorConstants.IGNORE_DATASET_FILTERS)) {

                    if (filePath == null)
                        return;
                    IProgressService service = (IProgressService) PlatformUI.getWorkbench()
                            .getService(IProgressService.class);
                    try {
                        // Changed to cancellable as sometimes loading the tree takes ages and you
                        // did not mean such to choose the file.
                        service.run(true, true, new IRunnableWithProgress() {
                            @Override
                            public void run(IProgressMonitor monitor)
                                    throws InvocationTargetException, InterruptedException {
                                try {
                                    final IMetadata meta = LoaderFactory.getMetadata(filePath,
                                            new ProgressMonitorWrapper(monitor));
                                    Display.getDefault().syncExec(new Runnable() {
                                        public void run() {
                                            try {
                                                PlotDataComponent.this.setData(
                                                        LoaderFactory.getData(filePath, true, true, null), meta);
                                            } catch (Exception e) {
                                                logger.error("Cannot change file path", e);
                                            }
                                        }
                                    });
                                } catch (Exception e) {
                                    throw new InvocationTargetException(e);
                                }
                            }
                        });
                    } catch (Exception ne) {
                        logger.error("Unable to refresh data set list", ne);
                    }
                } else if (event.getProperty().equals(EditorConstants.SHOW_XY_COLUMN)) {
                    setColumnVisible(2, 32, (Boolean) event.getNewValue());
                } else if (event.getProperty().equals(EditorConstants.SHOW_DATA_SIZE)) {
                    setColumnVisible(3, 100, (Boolean) event.getNewValue());
                } else if (event.getProperty().equals(EditorConstants.SHOW_DIMS)) {
                    setColumnVisible(4, 100, (Boolean) event.getNewValue());
                } else if (event.getProperty().equals(EditorConstants.SHOW_SHAPE)) {
                    setColumnVisible(5, 100, (Boolean) event.getNewValue());
                } else if (event.getProperty().equals(EditorConstants.SHOW_VARNAME)) {
                    setColumnVisible(6, 100, (Boolean) event.getNewValue());
                } else if (event.getProperty().equals(EditorConstants.SHOW_LOCALNAME)) {
                    dataViewer.refresh();
                }
            }
        };
        // If they change the ignore filters activity, recompute the available data sets.
        Activator.getDefault().getPreferenceStore().addPropertyChangeListener(propListener);

        // Trace listener is used to refresh the table.
        this.dataViewRefreshListener = new ITraceListener.Stub() {
            protected void update(TraceEvent evt) {
                if (dataViewer == null || dataViewer.getControl().isDisposed())
                    return;
                dataViewer.refresh();
            }
        };
        if (getPlottingSystem() != null)
            getPlottingSystem().addTraceListener(dataViewRefreshListener);
    }

    public Composite getControl() {
        return container;
    }

    protected void setColumnVisible(final int col, final int width, boolean isVis) {
        if (this.dataViewer == null || this.dataViewer.getControl().isDisposed())
            return;
        dataViewer.getTable().getColumn(col).setWidth(isVis ? width : 0);
        dataViewer.getTable().getColumn(col).setResizable(isVis ? true : false);
    }

    /**
     * Create contents of the view part.
     * @param parent
     */
    public void createPartControl(final Composite parent, IActionBars bars) throws Exception {

        this.container = new Composite(parent, SWT.NONE);
        if (parent.getLayout() instanceof GridLayout)
            container.setLayoutData(new GridData(GridData.FILL_BOTH));
        container.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));

        GridLayout gl_container = new GridLayout(1, false);
        gl_container.verticalSpacing = 0;
        gl_container.marginWidth = 0;
        gl_container.marginHeight = 0;
        gl_container.horizontalSpacing = 0;

        container.setLayout(gl_container);

        final Text searchText = new Text(container, SWT.SINGLE | SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL);
        searchText.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
        searchText.setToolTipText(
                "Search on data set name or shape\nFor instance '132, 4096' to find all of that shape.");

        this.dataViewer = new TableViewer(container,
                SWT.FULL_SELECTION | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.VIRTUAL);

        dataViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));
        dataViewer.getTable().addMouseListener(this);
        dataViewer.getTable().addKeyListener(this);
        dataViewer.getTable().setLinesVisible(true);
        dataViewer.getTable().setHeaderVisible(true);

        ColorRegistry colorRegistry = JFaceResources.getColorRegistry();
        Label label = new Label(container, SWT.RIGHT);
        label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false));
        label.setForeground(new Color(label.getDisplay(), colorRegistry.getRGB(JFacePreferences.QUALIFIER_COLOR)));
        label.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
        label.setText("* Click to change value  ");

        label = new Label(container, SWT.HORIZONTAL | SWT.SEPARATOR);
        label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

        createColumns();
        dataViewer.setColumnProperties(new String[] { "Data", "Length" });

        dataViewer.getTable().setItemCount(data.size());
        dataViewer.setUseHashlookup(true);

        dataViewer.setContentProvider(new IStructuredContentProvider() {
            @Override
            public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
            }

            @Override
            public void dispose() {
            }

            @Override
            public Object[] getElements(Object inputElement) {

                List<ITransferableDataObject> visible = new ArrayList<ITransferableDataObject>(data);
                if (Activator.getDefault().getPreferenceStore().getBoolean(EditorConstants.SHOW_SIGNAL_ONLY)) {
                    filterNonSignalData(visible);
                }
                return visible.toArray(new Object[visible.size()]);
            }
        });

        // Maybe being the selection provider cause the left mouse problem
        //if (getSite()!=null) getSite().setSelectionProvider(dataViewer);
        dataViewer.setInput(new String());

        createActions(bars);

        setColumnVisible(2, 36,
                Activator.getDefault().getPreferenceStore().getBoolean(EditorConstants.SHOW_XY_COLUMN));
        setColumnVisible(3, 150,
                Activator.getDefault().getPreferenceStore().getBoolean(EditorConstants.SHOW_DATA_SIZE));
        setColumnVisible(4, 150, Activator.getDefault().getPreferenceStore().getBoolean(EditorConstants.SHOW_DIMS));
        setColumnVisible(5, 150,
                Activator.getDefault().getPreferenceStore().getBoolean(EditorConstants.SHOW_SHAPE));
        setColumnVisible(6, 150,
                Activator.getDefault().getPreferenceStore().getBoolean(EditorConstants.SHOW_VARNAME));

        try {

            this.traceListener = new ITraceListener.Stub() {
                @Override
                public void tracesUpdated(TraceEvent evt) {
                    updateSelection(true);
                    dataViewer.refresh();
                }
            };
            if (getPlottingSystem() != null)
                getPlottingSystem().addTraceListener(traceListener);

            if (dataReduction != null) {
                this.toolListener = new IToolChangeListener() {

                    @Override
                    public void toolChanged(ToolChangeEvent evt) {
                        if (dataReduction != null) {
                            dataReduction.setEnabled(isDataReductionToolActive());
                        }
                    }
                };
                if (getAbstractPlottingSystem() != null)
                    getAbstractPlottingSystem().addToolChangeListener(toolListener);
            }
            if (getAbstractPlottingSystem() != null)
                getAbstractPlottingSystem().addPropertyChangeListener(new IPropertyChangeListener() {
                    @Override
                    public void propertyChange(PropertyChangeEvent event) {
                        try {
                            saveAxisSettings(".xAxis", getPlottingSystem().getSelectedXAxis());
                            saveAxisSettings(".yAxis", getPlottingSystem().getSelectedYAxis());
                        } catch (Throwable ne) {
                            logger.error("Cannot save settings for plotting configuration!", ne);
                        }
                    }
                });

            readAxisSettings(".xAxis", getPlottingSystem().getSelectedXAxis());
            readAxisSettings(".yAxis", getPlottingSystem().getSelectedYAxis());

            this.dataFilter = new DataTableFilter();
            dataViewer.addFilter(dataFilter);
            searchText.addModifyListener(new ModifyListener() {
                @Override
                public void modifyText(ModifyEvent e) {
                    if (parent.isDisposed())
                        return;
                    dataFilter.setSearchText(searchText.getText());
                    dataViewer.refresh();
                }
            });
        } catch (Exception ne) {
            logger.error("Cannot add trace listener!", ne);
        }

        // Allow the colours to be drawn nicely.
        final Table table = dataViewer.getTable();
        if (OSUtils.isWindowsOS())
            table.addListener(SWT.EraseItem, new Listener() {
                public void handleEvent(Event event) {

                    GC gc = event.gc;
                    Color foreground = gc.getForeground();
                    Color background = gc.getBackground();

                    try {
                        Rectangle area = table.getClientArea();
                        /*
                         * If you wish to paint the selection beyond the end of last column,
                         * you must change the clipping region.
                         */
                        int columnCount = table.getColumnCount();
                        if (event.index == columnCount - 1 || columnCount == 0) {
                            int width = area.x + area.width - event.x;
                            if (width > 0) {
                                Region region = new Region();
                                gc.getClipping(region);
                                region.add(event.x, event.y, width, event.height);
                                gc.setClipping(region);
                                region.dispose();
                            }
                        }

                        gc.setAdvanced(true);
                        if (gc.getAdvanced())
                            gc.setAlpha(50);

                        if ((event.detail & SWT.SELECTED) != 0) {
                            gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_SELECTION));
                            gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
                        }

                        final TableItem item = table.getItem(new Point(event.x, event.y));
                        // Draw the colour in the Value column
                        if (item != null && item.getData() instanceof TransferableDataObject) {

                            Rectangle nameArea = item.getBounds(1); // Name column
                            TransferableDataObject cn = (TransferableDataObject) item.getData();

                            if (cn.isChecked() && !cn.isExpression() && nameArea.contains(event.x, event.y)) {
                                int origAlpha = gc.getAlpha();
                                gc.setAlpha(255);
                                final Color plotColor = get1DPlotColor(cn);
                                if (plotColor != null) {
                                    gc.setForeground(plotColor);
                                    int offset = cn.getFilterPath() != null ? 20 : 0;
                                    gc.drawText(cn.getDisplayName(rootName), item.getBounds().x + 16 + offset,
                                            item.getBounds().y + 1);
                                    event.doit = false;
                                }
                                gc.setAlpha(origAlpha);
                            }

                            if ((event.detail & SWT.HOT) != 0) {
                                // Draw the colour in the Value column
                                gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_SELECTION));
                                Rectangle bounds = event.getBounds();
                                gc.fillGradientRectangle(0, bounds.y, 500, bounds.height, false);
                            }
                        }

                    } finally {
                        if ((event.detail & SWT.SELECTED) != 0)
                            event.detail &= ~SWT.SELECTED;
                        if ((event.detail & SWT.HOT) != 0)
                            event.detail &= ~SWT.HOT;
                        // restore colors for subsequent drawing
                        gc.setForeground(foreground);
                        gc.setBackground(background);
                    }

                }

            });

    }

    /**
     * Actually filters passed in list to remove data without a signal attribute.
     * @param visible
     */
    protected void filterNonSignalData(List<ITransferableDataObject> visible) {

        for (Iterator<ITransferableDataObject> it = visible.iterator(); it.hasNext();) {
            ITransferableDataObject dataObject = it.next();
            if (metaData != null && !dataObject.isExpression()) {
                try {
                    final Object signalAttrib = metaData.getMetaValue(dataObject + "@signal");
                    if (signalAttrib != null && !"".equals(signalAttrib)) {
                        continue;
                    }
                    it.remove();
                } catch (Exception e) {
                    logger.error("Cannot determine signal from " + dataObject);
                }
            }
        }
    }

    private static final String LOG_PREF = "org.dawb.workbench.ui.editors.log.axis-";
    private static final String TIME_PREF = "org.dawb.workbench.ui.editors.time.axis-";
    private static final String FORMAT_PREF = "org.dawb.workbench.ui.editors.format.axis-";

    private void saveAxisSettings(String key, IAxis selectedAxis) {

        final IPreferenceStore store = Activator.getDefault().getPreferenceStore();

        if (store.getBoolean(EditorConstants.SAVE_LOG_FORMAT))
            store.setValue(LOG_PREF + getExtension() + key, selectedAxis.isLog10());
        if (store.getBoolean(EditorConstants.SAVE_TIME_FORMAT))
            store.setValue(TIME_PREF + getExtension() + key, selectedAxis.isDateFormatEnabled());
        if (store.getBoolean(EditorConstants.SAVE_FORMAT_STRING))
            store.setValue(FORMAT_PREF + getExtension() + key, selectedAxis.getFormatPattern());
    }

    private void readAxisSettings(String key, IAxis selectedAxis) {

        final IPreferenceStore store = Activator.getDefault().getPreferenceStore();
        if (store.getBoolean(EditorConstants.SAVE_LOG_FORMAT))
            if (store.contains(LOG_PREF + getExtension() + key)) {
                selectedAxis.setLog10(store.getBoolean(LOG_PREF + getExtension() + key));
            }
        if (store.getBoolean(EditorConstants.SAVE_TIME_FORMAT))
            if (store.contains(TIME_PREF + getExtension() + key)) {
                selectedAxis.setDateFormatEnabled(store.getBoolean(TIME_PREF + getExtension() + key));
            }
        if (store.getBoolean(EditorConstants.SAVE_FORMAT_STRING))
            if (store.contains(FORMAT_PREF + getExtension() + key)) {
                selectedAxis.setFormatPattern(store.getString(FORMAT_PREF + getExtension() + key));
            }
    }

    private final String getExtension() {
        try {
            return FileUtils.getFileExtension(filePath);

        } catch (Throwable ne) {
            return "";
        }
    }

    public void setFocus() {
        if (dataViewer != null && !dataViewer.getControl().isDisposed()) {
            dataViewer.getControl().setFocus();

            if (dataReduction != null) {
                dataReduction.setEnabled(isDataReductionToolActive());
            }

        }
    }

    private void readExpressions() throws Exception {

        final String cachePath = DawbUtils.getDawnHome() + getFileName() + ".properties";
        Properties props = PropUtils.loadProperties(cachePath);
        if (props != null) {
            try {
                for (Object ob : props.keySet()) {
                    final String mementoKey = (String) ob;
                    final String memento = props.getProperty(mementoKey);
                    if (TransferableDataObject.isMementoKey(mementoKey)) {
                        final String possibleName = TransferableDataObject.getName(memento);
                        ITransferableDataObject o = getCheckableObjectByName(possibleName);
                        if (o != null) {
                            o.setVariable(TransferableDataObject.getVariable(memento));
                        } else {
                            o = transferableService.createExpression(dataHolder, metaData);
                            o.createExpression(this, mementoKey, props.getProperty(mementoKey));
                            data.add(o);
                        }
                    }
                }
            } catch (Exception ne) {
                throw new PartInitException(ne.getMessage());
            }
        }
    }

    public void saveExpressions() {
        try {
            final Properties props = new Properties();
            for (ITransferableDataObject check : data) {
                props.put(check.getMementoKey(), check.getMemento());
            }
            // Save properties to workspace.
            final String cachePath = DawbUtils.getDawnHome() + getFileName() + ".properties";
            PropUtils.storeProperties(props, cachePath);

        } catch (Exception e) {
            logger.error("Cannot save expression", e);
        }
    }

    /**
     * Puts actions on right click menu and in action bar.
     * @param bars
     */
    private void createActions(final IActionBars bars) {

        final MenuManager menuManager = new MenuManager();
        menuManager.setRemoveAllWhenShown(true);
        dataViewer.getControl().setMenu(menuManager.createContextMenu(dataViewer.getControl()));

        final List<Object> rightClickActions = new ArrayList<Object>(11);
        createDimensionalActions(rightClickActions, false);

        PlotDataComponent.this.dataReduction = new Action("Data reduction...",
                Activator.getImageDescriptor("icons/data-reduction.png")) {
            @Override
            public void run() {
                DataReductionWizard wiz = null;
                try {
                    wiz = (DataReductionWizard) EclipseUtils.openWizard(DataReductionWizard.ID, false);
                } catch (Exception e) {
                    logger.error("Cannot open wizard " + DataReductionWizard.ID, e);
                }
                wiz.setData(getFile(), getSelectionNames().get(0),
                        (IDataReductionToolPage) getAbstractPlottingSystem().getActiveTool(), getSliceSet());
                wiz.setSlice(getSliceSet(), getSliceData());

                // TODO Should be non modal, it takes a while.
                WizardDialog wd = new WizardDialog(Display.getDefault().getActiveShell(), wiz);
                wd.setTitle(wiz.getWindowTitle());
                wd.create();
                wd.getShell().setSize(650, 800);
                DialogUtils.centerDialog(Display.getDefault().getActiveShell(), wd.getShell());
                wd.open();
            }
        };

        final Action showSignal = new Action("Show only data with a 'signal' attribute", IAction.AS_CHECK_BOX) {
            public void run() {
                Activator.getDefault().getPreferenceStore().setValue(EditorConstants.SHOW_SIGNAL_ONLY, isChecked());
                refresh();
            }
        };
        showSignal.setImageDescriptor(Activator.getImageDescriptor("icons/signal.png"));
        bars.getToolBarManager().add(showSignal);
        bars.getToolBarManager().add(new Separator("signal.group"));
        showSignal.setChecked(
                Activator.getDefault().getPreferenceStore().getBoolean(EditorConstants.SHOW_SIGNAL_ONLY));

        final Action copy = new Action("Copy selected data (it can then be pasted to another data list.)",
                Activator.getImageDescriptor("icons/copy.gif")) {
            public void run() {
                final ITransferableDataObject sel = (ITransferableDataObject) ((IStructuredSelection) dataViewer
                        .getSelection()).getFirstElement();
                if (sel == null)
                    return;
                transferableService.setBuffer(sel);
            }
        };
        bars.getToolBarManager().add(copy);
        copy.setEnabled(false);

        final Action paste = new Action("Paste", Activator.getImageDescriptor("icons/paste.gif")) {
            public void run() {
                ITransferableDataObject checkedObject = getCheckedObject(transferableService.getBuffer());
                if (checkedObject == null)
                    return;
                data.add(checkedObject);
                checkedObject.setChecked(!checkedObject.isChecked());
                selectionChanged(checkedObject, true);
                dataViewer.refresh();

                final ISliceSystem system = (ISliceSystem) editor.getAdapter(ISliceSystem.class);
                if (system != null)
                    system.refresh();
            }
        };
        bars.getToolBarManager().add(paste);
        paste.setEnabled(false);

        final Action delete = new Action("Delete", Activator.getImageDescriptor("icons/delete.gif")) {
            public void run() {
                final Object sel = ((StructuredSelection) dataViewer.getSelection()).getFirstElement();
                final ITransferableDataObject ob = (ITransferableDataObject) sel;
                if (ob != null) {
                    boolean ok = data.remove(ob);
                    if (ok)
                        ob.dispose();
                }
                dataViewer.refresh();
            }
        };
        bars.getToolBarManager().add(delete);
        delete.setEnabled(false);

        // Fix to http://jira.diamond.ac.uk/browse/SCI-1558
        // remove feature.
        final Action createFilter = null;
        final Action clearFilter = null;

        // Used to have ability to choose a python script to filter datasets:
        //      bars.getToolBarManager().add(new Separator());
        //      final Action createFilter = new Action("Create Filter", Activator.getImageDescriptor("icons/filter.png")) {
        //         public void run() {
        //            final Object sel           = ((StructuredSelection)dataViewer.getSelection()).getFirstElement();
        //            final ITransferableDataObject ob  = (ITransferableDataObject)sel;
        //            if (ob==null) return;
        //            chooseFilterFile(ob);
        //         }
        //      };
        //      bars.getToolBarManager().add(createFilter);
        //      createFilter.setEnabled(false);
        //      
        //      final Action clearFilter = new Action("Clear filter", Activator.getImageDescriptor("icons/delete_filter.png")) {
        //         public void run() {
        //            final Object sel           = ((StructuredSelection)dataViewer.getSelection()).getFirstElement();
        //            final ITransferableDataObject ob  = (ITransferableDataObject)sel;
        //            if (ob==null) return;
        //            clearFilterFile(ob);
        //         }
        //      };
        //      bars.getToolBarManager().add(clearFilter);
        //      clearFilter.setEnabled(false);

        final Action export = new Action("Export...", Activator.getImageDescriptor("icons/export_wiz.gif")) {
            public void run() {

                final ConvertWizard cwizard = new ConvertWizard();
                final IStructuredSelection sel = (IStructuredSelection) dataViewer.getSelection();
                cwizard.setSelectionOverride(sel.toList());
                WizardDialog dialog = new WizardDialog(container.getShell(), cwizard);
                dialog.setPageSize(new Point(400, 450));
                dialog.create();
                dialog.open();

            }
        };
        export.setEnabled(false);
        bars.getToolBarManager().add(new Separator());
        bars.getToolBarManager().add(export);
        bars.getToolBarManager().add(new Separator());

        dataViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            @Override
            public void selectionChanged(SelectionChangedEvent event) {
                final Object sel = ((StructuredSelection) dataViewer.getSelection()).getFirstElement();
                final ITransferableDataObject ob = (ITransferableDataObject) sel;
                updateActions(copy, paste, delete, createFilter, clearFilter, export, ob, bars);
            }
        });

        final InjectPyDevConsoleAction inject = new InjectPyDevConsoleAction("Open Scripting");
        inject.setParameter(InjectPyDevConsole.CREATE_NEW_CONSOLE_PARAM, Boolean.TRUE.toString());
        inject.setParameter(InjectPyDevConsole.SETUP_SCISOFTPY_PARAM,
                InjectPyDevConsole.SetupScisoftpy.ALWAYS.toString());
        inject.setParameter(InjectPyDevConsole.VIEW_NAME_PARAM, editor.getTitle());

        menuManager.addMenuListener(new IMenuListener() {
            @Override
            public void menuAboutToShow(IMenuManager manager) {

                if (staggerSupported) {
                    updatePlotDimenionsSelected((IAction) rightClickActions.get(1),
                            (IAction) rightClickActions.get(2), (IAction) rightClickActions.get(3),
                            getPlottingSystem().getPlotType());
                }

                for (Object action : rightClickActions) {
                    if (action instanceof IAction) {
                        menuManager.add((IAction) action);
                    } else if (action instanceof IContributionItem) {
                        menuManager.add((IContributionItem) action);
                    }
                }

                menuManager.add(new Separator(getClass().getName() + "sep1"));
                menuManager.add(new Action("Clear") {
                    @Override
                    public void run() {
                        for (ITransferableDataObject co : data) {
                            co.setChecked(false);
                        }
                        selections.clear();
                        dataViewer.refresh();
                        fireSelectionListeners(Collections.<ITransferableDataObject>emptyList());
                    }
                });

                menuManager.add(new Separator(getClass().getName() + ".copyPaste"));

                final Object sel = ((StructuredSelection) dataViewer.getSelection()).getFirstElement();
                final ITransferableDataObject ob = (ITransferableDataObject) sel;
                menuManager.add(copy);
                menuManager.add(paste);
                menuManager.add(delete);
                menuManager.add(new Separator(getClass().getName() + ".filter"));
                if (createFilter != null)
                    menuManager.add(createFilter);
                if (clearFilter != null)
                    menuManager.add(clearFilter);

                updateActions(copy, paste, delete, createFilter, clearFilter, export, ob, null);

                menuManager.add(new Separator(getClass().getName() + ".export"));
                menuManager.add(export);

                if (H5Loader.isH5(getFileName())) {
                    menuManager.add(new Separator(getClass().getName() + "sep2"));

                    dataReduction.setEnabled(false);
                    menuManager.add(dataReduction);
                }

                menuManager.add(new Separator(getClass().getName() + ".error"));

                /**
                 * What follows is adding some actions for setting errors on other plotted data sets.
                 * The logic is a bit convoluted at the moment.
                 */
                final ILazyDataset currentSelectedData = ob != null ? getLazyValue(ob.getVariable(), null) : null;

                if (currentSelectedData != null) {
                    if (selections != null && selections.size() > 0) {
                        menuManager.add(new Action("Set '" + ob.getName() + "' as error on other plotted data...") {
                            @Override
                            public void run() {
                                final PlotDataChooseDialog dialog = new PlotDataChooseDialog(
                                        Display.getDefault().getActiveShell());
                                dialog.init(selections, ob);
                                final ITransferableDataObject plotD = dialog.choose();
                                if (plotD != null) {
                                    ILazyDataset set = (ILazyDataset) getLazyValue(plotD.getVariable(), null);

                                    if (set instanceof IErrorDataset) { // Data was all read in already.
                                        IErrorDataset errSet = (IErrorDataset) set;
                                        // Read plotted data into memory, so can read error data too.
                                        errSet.setError(getVariableValue(ob.getVariable(), null));

                                    } else { // Set errors lazily
                                        set.setError(currentSelectedData);
                                    }
                                    fireSelectionListeners(selections);

                                }
                            }
                        });
                    }

                    final boolean isDatasetError = currentSelectedData instanceof IErrorDataset
                            && ((IErrorDataset) currentSelectedData).hasErrors();
                    final boolean isLazyError = currentSelectedData.getError() != null;
                    if (isDatasetError || isLazyError) {
                        menuManager.add(new Action("Clear error on '" + currentSelectedData.getName() + "'") {
                            @Override
                            public void run() {
                                currentSelectedData.setError(null);
                                fireSelectionListeners(selections);
                            }
                        });
                    }
                }

                // TODO Send the dataset via the flattening service.
                if (currentSelectedData != null && currentSelectedData instanceof IDataset) {

                    inject.setData(ob.getVariable(), (IDataset) currentSelectedData);
                    inject.setText("Open '" + currentSelectedData.getName() + "' in scripting console");

                    menuManager.add(inject);
                }

                menuManager.add(new Separator(getClass().getName() + "sep3"));
                menuManager.add(new Action("Preferences...") {
                    @Override
                    public void run() {
                        PreferenceDialog pref = PreferencesUtil.createPreferenceDialogOn(
                                PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
                                "org.edna.workbench.editors.preferencePage", null, null);
                        if (pref != null)
                            pref.open();
                    }
                });

                menuManager.addMenuListener(new IMenuListener() {
                    @Override
                    public void menuAboutToShow(IMenuManager manager) {
                        if (dataReduction != null)
                            dataReduction.setEnabled(isDataReductionToolActive());
                    }
                });
            }
        });

    }

    private PlotDataFilterProvider filterProvider;

    /**
     * Choose a jython file to be used as the filter or create a new one.
     * 
     * @param ob
     */
    private void chooseFilterFile(ITransferableDataObject ob) {

        if (ob == null)
            return;

        PythonFilterWizard wiz = null;
        try {
            wiz = (PythonFilterWizard) EclipseUtils.openWizard(PythonFilterWizard.ID, false);
        } catch (Exception e) {
            logger.error("Cannot open wizard " + PythonFilterWizard.ID, e);
        }

        // TODO Should be non modal, it takes a while.
        WizardDialog wd = new WizardDialog(Display.getDefault().getActiveShell(), wiz);
        wd.setTitle(wiz.getWindowTitle());
        wd.create();
        wd.getShell().setSize(650, 800);
        DialogUtils.centerDialog(Display.getCurrent().getActiveShell(), wd.getShell());
        wd.open();

        final String filterPath = wiz.getPythonPath();
        if (filterPath == null)
            return;

        if (ob.getFilterPath() != null) {
            boolean ok = MessageDialog.openConfirm(Display.getDefault().getActiveShell(), "Confirm Overwrite",
                    "Do you want to replace filter '" + ob.getFilterPath() + "' with '" + filterPath);
            if (!ok)
                return;
        }

        ob.setFilterPath(filterPath);

        saveExpressions(); // TODO save filters as well.

        // We now create a filter which calls the associated cpython interperter to filter the data.
        if (filterProvider == null)
            filterProvider = new PlotDataFilterProvider(getPlottingSystem());
        try {
            filterProvider.createFilter(ob); // TODO Rank from dialog
        } catch (Exception ne) {
            ob.setFilterPath(null);
            String message = ne.getMessage() != null ? ne.getMessage()
                    : "Filter '" + ob.getFilterPath() + "' is not a valid python script!";
            MessageDialog.openInformation(Display.getDefault().getActiveShell(), "Cannot set filter", message);
            Activator.getDefault().getLog().log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, message));
        }

        ob.setChecked(!ob.isChecked());
        selectionChanged(ob, true);
    }

    protected void clearFilterFile(ITransferableDataObject ob) {

        if (ob == null)
            return;
        if (filterProvider != null)
            filterProvider.deleteFilter(ob);
        ob.setFilterPath(null);

        ob.setChecked(!ob.isChecked());
        selectionChanged(ob, true);

    }

    protected void updateActions(Action copy, Action paste, Action delete, Action createFilter, Action deleteFilter,
            Action export, ITransferableDataObject ob, IActionBars bars) {

        if (ob != null) {
            copy.setText("Copy '" + ob.getName() + "' (can be pasted into other data).");
            copy.setEnabled(true);
            export.setText("Export '" + ob.getName() + "'");
            export.setEnabled(true);
        } else {
            copy.setEnabled(false);
            export.setText("Export");
            export.setEnabled(false);
        }

        ITransferableDataObject currentCopiedData = transferableService.getBuffer();
        if (currentCopiedData != null) {
            paste.setText("Paste '" + currentCopiedData.getName() + "' (from file "
                    + currentCopiedData.getFileName() + ") into this data.");
            paste.setEnabled(true);
        } else {
            paste.setEnabled(false);
        }

        if (ob != null && ob.isTransientData()) {
            delete.setText("Delete '" + ob.getName());
            delete.setEnabled(true);
        } else {
            delete.setText("Delete");
            delete.setEnabled(false);
        }

        if (createFilter != null) {
            if (ob != null) {
                createFilter.setText("Filter plot of '" + ob.getName() + "' using python");
                createFilter.setEnabled(true);
            } else {
                createFilter.setEnabled(false);
            }
        }

        if (deleteFilter != null) {
            if (ob != null && ob.getFilterPath() != null) {
                deleteFilter.setText("Clear filter of '" + ob.getName() + "'");
                deleteFilter.setEnabled(true);
            } else {
                deleteFilter.setEnabled(false);
            }
        }

        if (bars != null) {
            bars.getToolBarManager().update(true);
            bars.updateActionBars();
        }
    }

    /**
     * Checks whether the object exists and if it does, asks the user for a new
     * name. If a new name is not provided or the user cancels, will return null.
     * @param original
     * @return cloned object with unique name or null if no paste-able object can be determined.
     */
    protected ITransferableDataObject getCheckedObject(final ITransferableDataObject original) {

        if (nameExists(original.getName())) {
            if (original.isExpression()) {
                MessageDialog.openWarning(Display.getDefault().getActiveShell(), "Cannot paste expression",
                        "Cannot paste expression '" + original.getName() + "' as it already exists");
                return null;

            } else {

                final IInputValidator validator = new IInputValidator() {
                    @Override
                    public String isValid(String newText) {
                        if (nameExists(newText)) {
                            return "'" + newText + "' already exists in this data.";
                        } else {
                            return null;
                        }
                    }
                };

                InputDialog dialog = new InputDialog(Display.getCurrent().getActiveShell(),
                        "'" + original.getName() + "' already exists",
                        "Please provide a new name for '" + original.getName() + "'", original.getName() + "_1",
                        validator);
                int rc = dialog.open();
                if (rc == Window.OK) {
                    ITransferableDataObject clone = original.clone();
                    clone.setName(dialog.getValue());

                    final String varName = clone.getVariable();

                    if (isVariableName(varName, null)) {
                        int i = 1;
                        while (isVariableName(varName + i, null)) {
                            ++i;
                        }
                        clone.setVariable(varName + i);
                    }

                    return clone;
                } else {
                    return null;
                }
            }
        }

        return original.clone();
    }

    private boolean nameExists(String original) {
        for (ITransferableDataObject existing : data) {
            if (existing.getName().equals(original)) {
                return true;
            }
        }
        return false;
    }

    public IAction getDataReductionAction() {

        return dataReduction;
    }

    protected DimsDataList getSliceData() {
        final ISliceSystem system = (ISliceSystem) editor.getAdapter(ISliceSystem.class);
        if (system != null)
            return system.getDimsDataList();

        return null;
    }

    protected ILazyDataset getSliceSet() {
        final ISliceSystem system = (ISliceSystem) editor.getAdapter(ISliceSystem.class);
        if (system != null && system.getData() != null)
            return system.getData().getLazySet();

        return selections.get(0).getLazyData(new IMonitor.Stub());
    }

    public File getFile() {
        File file = null;

        if (editor instanceof IEditorPart) {
            IEditorInput input = ((IEditorPart) editor).getEditorInput();
            try {
                file = EclipseUtils.getFile(input);
            } catch (Throwable ne) {
                file = null;
            }
        } else {
            IFile ifile = (IFile) editor.getAdapter(IFile.class);
            file = new File(ifile.getLocation().toOSString());
        }

        return file;
    }

    public IFile getIFile(boolean createNewFile) {

        IFile file = null;
        String name = null;
        IEditorInput input = null;
        if (editor instanceof IEditorPart) {
            input = ((IEditorPart) editor).getEditorInput();
            try {
                file = EclipseUtils.getIFile(input);
                name = input.getName();
            } catch (Throwable ne) {
                file = null;
            }
        } else {
            file = (IFile) editor.getAdapter(IFile.class);
            name = file != null ? file.getName() : null;
        }

        if (createNewFile && file == null) {// Might be external file
            final IProject data = ResourcesPlugin.getWorkspace().getRoot().getProject("data");
            if (!data.exists()) {
                try {
                    data.create(new NullProgressMonitor());
                } catch (CoreException e) {
                    logger.error("Cannot create 'data' project!", e);
                }
            }
            if (!data.isOpen()) {
                try {
                    data.open(new NullProgressMonitor());
                } catch (CoreException e) {
                    logger.error("Cannot open 'data' project!", e);
                }
            }
            file = data.getFile(name);
            if (file.exists()) {
                file = EclipseUtils.getUniqueFile(file, FileUtils.getFileExtension(name));
            }

            if (input != null)
                try {
                    file.create(new FileInputStream(EclipseUtils.getFile(input)), IResource.FORCE,
                            new NullProgressMonitor());
                    data.refreshLocal(IResource.DEPTH_ONE, new NullProgressMonitor());
                } catch (Exception e) {
                    logger.error("Cannot create file " + file.getName() + "!", e);
                }
        }

        return file;
    }

    protected List<String> getSelectionNames() {
        final List<String> names = new ArrayList<String>(3);
        for (ITransferableDataObject ob : getSelections()) {
            if (!ob.isExpression())
                names.add(ob.getPath());
            else {
                names.add(ob.getExpression().getExpressionName());
            }
        }
        return names;
    }

    public boolean isDataReductionToolActive() {

        if (H5Loader.isH5(getFileName()) || isSelectionReducible()) {

            IToolPageSystem toolSystem = (IToolPageSystem) getPlottingSystem().getAdapter(IToolPageSystem.class);
            IToolPage tool = toolSystem.getActiveTool();
            boolean probablyOk = tool != null && tool instanceof IDataReductionToolPage;

            // Check for advanced axes
            dataReduction.setText("Data reduction...");
            if (probablyOk) {
                final DimsDataList ddl = getSliceData();
                if (ddl != null)
                    for (DimsData dd : ddl.iterable()) {

                        if (dd.getPlotAxis().isAdvanced()) {
                            dataReduction.setText("Data reduction cannot be used with advanced axes.");
                            return false;
                        }
                    }
            }

            return probablyOk;
        }
        return false;
    }

    /**
     * if the table selection is reducible
     */
    private boolean isSelectionReducible() {
        final Object sel = ((StructuredSelection) dataViewer.getSelection()).getFirstElement();
        final ITransferableDataObject ob = (ITransferableDataObject) sel;
        if (ob == null)
            return false;
        ILazyDataset lazy = ob.getLazyData(null);
        if (lazy != null && lazy.getRank() >= 3)
            return true;
        return false;
    }

    private ExpressionEditingSupport expressionEditor;
    private VariableNameEditingSupport variableEditor;

    private void createColumns() throws Exception {

        ColumnViewerToolTipSupport.enableFor(dataViewer, ToolTip.NO_RECREATE);

        final TableViewerColumn tick = new TableViewerColumn(dataViewer, SWT.LEFT, 0);
        tick.getColumn().setText(" ");
        tick.getColumn().setWidth(30);
        tick.setLabelProvider(new DataSetColumnLabelProvider(0, this));

        final TableViewerColumn name = new TableViewerColumn(dataViewer, SWT.LEFT, 1);
        name.getColumn().setText("Name");
        name.getColumn().setWidth(Math.max(30,
                Activator.getDefault().getPreferenceStore().getInt(EditorConstants.PLOT_DATA_NAME_WIDTH)));
        name.getColumn().addListener(SWT.Resize, new Listener() {
            @Override
            public void handleEvent(Event event) {
                Activator.getDefault().getPreferenceStore().setValue(EditorConstants.PLOT_DATA_NAME_WIDTH,
                        name.getColumn().getWidth());
            }
        });
        name.setLabelProvider(new DelegatingStyledCellLabelProvider(new DataSetColumnLabelProvider(1, this)));

        expressionEditor = new ExpressionEditingSupport(dataViewer, this);
        name.setEditingSupport(expressionEditor);

        final TableViewerColumn axis = new TableViewerColumn(dataViewer, SWT.LEFT, 2);
        axis.getColumn().setText(" ");
        axis.getColumn().setWidth(32);
        axis.setLabelProvider(new DelegatingStyledCellLabelProvider(new DataSetColumnLabelProvider(2, this)));
        axis.setEditingSupport(new AxisEditingSupport(dataViewer, this));

        final TableViewerColumn size = new TableViewerColumn(dataViewer, SWT.LEFT, 3);
        size.getColumn().setText("Size");
        size.getColumn().setWidth(150);
        size.getColumn().setResizable(true);
        size.setLabelProvider(new DelegatingStyledCellLabelProvider(new DataSetColumnLabelProvider(3, this)));

        final TableViewerColumn dims = new TableViewerColumn(dataViewer, SWT.LEFT, 4);
        dims.getColumn().setText("Dimensions");
        dims.getColumn().setWidth(150);
        dims.getColumn().setResizable(true);
        dims.setLabelProvider(new DelegatingStyledCellLabelProvider(new DataSetColumnLabelProvider(4, this)));

        final TableViewerColumn shape = new TableViewerColumn(dataViewer, SWT.LEFT, 5);
        shape.getColumn().setText("Shape");
        shape.getColumn().setWidth(150);
        shape.getColumn().setResizable(true);
        shape.setLabelProvider(new DelegatingStyledCellLabelProvider(new DataSetColumnLabelProvider(5, this)));

        final TableViewerColumn varName = new TableViewerColumn(dataViewer, SWT.LEFT, 6);
        varName.getColumn().setText("Variable");
        varName.getColumn().setWidth(150);
        varName.getColumn().setResizable(true);
        varName.setLabelProvider(new DataSetColumnLabelProvider(6, this));

        variableEditor = new VariableNameEditingSupport(dataViewer, this);
        varName.setEditingSupport(variableEditor);
    }

    private void createDimensionalActions(List<Object> rightClickActions, boolean isToolbar) {

        this.dataComponentActions = new ArrayList<IAction>(11);

        final Action preferences = new Action("Configure column preferences...",
                Activator.getImageDescriptor("icons/application_view_columns.png")) {
            public void run() {
                PreferenceDialog pref = PreferencesUtil.createPreferenceDialogOn(
                        PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), EditorPreferencePage.ID,
                        null, null);
                if (pref != null)
                    pref.open();
            }

        };

        if (staggerSupported) {
            // Warning this is horrible:
            final Action xyAction = new Action("XY Plot", SWT.TOGGLE) {
                @Override
                public void run() {
                    setPlotMode(PlotType.XY);
                }
            };
            xyAction.setImageDescriptor(Activator.getImageDescriptor("/icons/chart_curve.png"));
            xyAction.setToolTipText("XY Graph of Data, overlayed for multiple data.");
            dataComponentActions.add(xyAction);

            final Action staggeredAction = new Action("XY staggered in Z", SWT.TOGGLE) {
                @Override
                public void run() {
                    setPlotMode(PlotType.XY_STACKED);
                }
            };
            staggeredAction.setImageDescriptor(Activator.getImageDescriptor("/icons/chart_curve_staggered.png"));
            staggeredAction.setToolTipText("XY Graph of Data, staggered in Z for multiple data.");
            dataComponentActions.add(staggeredAction);

            final Action xyzAction = new Action("XYZ", SWT.TOGGLE) {
                @Override
                public void run() {
                    setPlotMode(PlotType.XY_STACKED_3D);
                }
            };
            xyzAction.setImageDescriptor(Activator.getImageDescriptor("/icons/chart_curve_3D.png"));
            xyzAction.setToolTipText("XYZ, X is the first chosen data and Z the last.");
            dataComponentActions.add(xyzAction);

            rightClickActions.add(new Separator());
            rightClickActions.add(xyAction);
            rightClickActions.add(staggeredAction);
            rightClickActions.add(xyzAction);
            rightClickActions.add(new Separator());

            updatePlotDimenionsSelected(xyAction, staggeredAction, xyzAction, getPlottingSystem().getPlotType());

            // Removed when part disposed.
            addPlotModeListener(new PlotModeListener() {
                @Override
                public void plotChangePerformed(PlotType plotMode) {
                    updatePlotDimenionsSelected(xyAction, staggeredAction, xyzAction, plotMode);
                    updateSelection(true);
                }
            });

            final Display dis = PlatformUI.getWorkbench().getDisplay();
            if (isToolbar) {
                dis.asyncExec(new Runnable() {
                    @Override
                    public void run() {
                        updatePlotDimenionsSelected(xyAction, staggeredAction, xyzAction,
                                getPlottingSystem().getPlotType());
                    }
                });
            }
        }

        final Action setX = new Action("Set selected data as x-axis") {
            public void run() {

                final TransferableDataObject sel = (TransferableDataObject) ((IStructuredSelection) dataViewer
                        .getSelection()).getFirstElement();
                if (sel == null)
                    return;

                setAsX(sel);
            }
        };
        setX.setImageDescriptor(Activator.getImageDescriptor("/icons/to_x.png"));
        setX.setToolTipText("Changes the plot to use selected data set as the x-axis.");
        dataComponentActions.add(setX);
        rightClickActions.add(setX);
        rightClickActions.add(new Separator());

        final Action addExpression = new Action("Add expression") {
            public void run() {
                final ICommandService cs = (ICommandService) PlatformUI.getWorkbench()
                        .getService(ICommandService.class);
                try {
                    cs.getCommand("org.dawb.workbench.editors.addExpression")
                            .executeWithChecks(new ExecutionEvent());
                } catch (Exception e) {
                    logger.error("Cannot run action", e);
                }

            }
        };
        addExpression.setImageDescriptor(Activator.getImageDescriptor("/icons/add_expression.png"));
        addExpression
                .setToolTipText("Adds an expression which can be plotted. Must be function of other data sets.");
        dataComponentActions.add(addExpression);
        rightClickActions.add(addExpression);

        final Action deleteExpression = new Action("Delete expression") {
            public void run() {
                final ICommandService cs = (ICommandService) PlatformUI.getWorkbench()
                        .getService(ICommandService.class);
                try {
                    cs.getCommand("org.dawb.workbench.editors.deleteExpression")
                            .executeWithChecks(new ExecutionEvent());
                } catch (Exception e) {
                    logger.error("Cannot run action", e);
                }
            }
        };
        deleteExpression.setImageDescriptor(Activator.getImageDescriptor("/icons/delete_expression.png"));
        deleteExpression.setToolTipText("Deletes an expression.");
        dataComponentActions.add(deleteExpression);
        rightClickActions.add(deleteExpression);

        dataComponentActions.add(preferences);

    }

    public void clearExpressionCache(String... variableNames) {
        for (ITransferableDataObject ob : data) {
            if (ob.isExpression() && (variableNames == null || variableNames.length < 1
                    || ob.getExpression().containsVariable(variableNames))) {
                ob.getExpression().clear();
            }
        }
    }

    protected void setAsX(TransferableDataObject sel) {

        int[] shape = sel.getShape(true);
        if (shape.length != 1)
            return;
        sel.setChecked(true);

        if (selections.contains(sel))
            selections.remove(sel);
        selections.add(0, sel);
        getAbstractPlottingSystem().setXFirst(true);
        updateSelection(true);
        dataViewer.refresh();
    }

    public List<IAction> getDimensionalActions() {

        return dataComponentActions;

    }

    protected void updatePlotDimenionsSelected(IAction xyAction, IAction staggeredAction, IAction xyzAction,
            PlotType plotMode) {

        if (staggerSupported)
            return;
        xyAction.setChecked(PlotType.XY.equals(plotMode));
        staggeredAction.setChecked(PlotType.XY_STACKED.equals(plotMode));
        xyzAction.setChecked(PlotType.XY_STACKED_3D.equals(plotMode));
    }

    private List<ITransferableDataObject> selections = new ArrayList<ITransferableDataObject>(7);

    /**
     * @return Returns the selections.
     */
    public List<ITransferableDataObject> getSelections() {
        return selections;
    }

    public void mouseDoubleClick(MouseEvent e) {

        if (e.button == 1) {
            final Point pnt = new Point(e.x, e.y);
            final TableItem item = this.dataViewer.getTable().getItem(pnt);
            if (item == null)
                return;

            Rectangle rect1 = item.getBounds(1);
            Rectangle rect6 = item.getBounds(6);
            if (!rect1.contains(pnt) && !rect6.contains(pnt))
                return;
            try {
                ITransferableDataObject data = (ITransferableDataObject) item.getData();
                expressionEditor.setExpressionActive(true);
                variableEditor.setVariableNameActive(true);

                dataViewer.editElement(data, rect1.contains(pnt) ? 1 : 6);
            } finally {
                expressionEditor.setExpressionActive(false);
                variableEditor.setVariableNameActive(false);
            }

        }
    }

    /**
     * Sent when a mouse button is pressed.
     *
     * @param e an event containing information about the mouse button press
     */
    public void mouseDown(MouseEvent e) {

        expressionEditor.setExpressionActive(false);
        variableEditor.setVariableNameActive(false);
        if (e.button == 1) {

            final Point pnt = new Point(e.x, e.y);
            final TableItem item = this.dataViewer.getTable().getItem(pnt);
            if (item == null)
                return;

            Rectangle rect = item.getBounds(0); // First column (tick and name)
            if (!rect.contains(pnt))
                return;

            dataViewer.cancelEditing();
            final TransferableDataObject clicked = (TransferableDataObject) item.getData();

            if (e.stateMask == 131072) { // Shift is pressed
                try {
                    final ITransferableDataObject from = selections.get(selections.size() - 1);
                    // TODO Table may be filtered - then we cannot loop over the data
                    // only the visible data.
                    final int fromIndex = data.indexOf(from);
                    final int toIndex = data.indexOf(clicked);
                    final int inc = (fromIndex < toIndex) ? 1 : -1;

                    for (int i = fromIndex + inc; inc == 1 ? i < toIndex : i > toIndex; i += inc) {
                        ITransferableDataObject element = data.get(i);
                        if (dataFilter.isElementVisible(element)) {
                            selectionChanged(element, false);
                        }
                    }
                    selectionChanged(clicked, true);

                } catch (Throwable t) {
                    selectionChanged(clicked, true);
                }
            } else {
                selectionChanged(clicked, true);
                dataViewer.refresh();
            }
            dataViewer.cancelEditing();
        }
    }

    public void keyPressed(KeyEvent e) {
        if (e.keyCode == 13) {
            selectionChanged(
                    (TransferableDataObject) ((IStructuredSelection) dataViewer.getSelection()).getFirstElement(),
                    true);
        }
    }

    /**
     * Sent when a key is released on the system keyboard.
     *
     * @param e an event containing information about the key release
     */
    public void keyReleased(KeyEvent e) {
    }

    /**
     * Sent when a mouse button is released.
     *
     * @param e an event containing information about the mouse button release
     */
    public void mouseUp(MouseEvent e) {

    }

    protected void selectionChanged(final ITransferableDataObject check, boolean fireListeners) {

        if (selections == null)
            selections = new ArrayList<ITransferableDataObject>(7);

        if (check != null) {

            if (isInvalidExpression(check))
                return;

            check.setChecked(!check.isChecked());

            if (!check.isChecked()) {
                selections.remove(check);
            } else {
                // We only allow selection of one set not 1D
                final int[] shape = check.getShape(true);
                final int dims = shape.length;
                if (dims != 1) { // Nothing else gets selected
                    setAllChecked(false);
                    check.setChecked(true);
                    this.selections.clear();
                }
                if (!selections.contains(check)) {
                    selections.add(check);
                }

            }

            // 1D takes precidence
            boolean is1D = false;
            // We check selections to ensure that only n*1D or 1*2D+ are selected
            for (ITransferableDataObject set : selections) {
                final int[] shape = set.getShape(true);
                if (shape.length == 1)
                    is1D = true;
            }

            if (is1D)
                for (Iterator<ITransferableDataObject> it = selections.iterator(); it.hasNext();) {
                    ITransferableDataObject set = it.next();
                    final int[] shape = set.getShape(true);

                    if (shape.length != 1) {
                        set.setChecked(false);
                        it.remove();
                    }
                }

        } else {
            selections.clear();
        }

        updateSelection(fireListeners); // Results in job being done for the plotting.
        // Trace listener is used to refresh the table, added in construnctor
    }

    private boolean isInvalidExpression(ITransferableDataObject check) {

        if (!check.isExpression())
            return false;

        boolean isExprOk = check.getExpression().isValid(new IMonitor.Stub());
        if (!isExprOk) {
            List<String> names = check.getExpression().getInvalidVariables(new IMonitor.Stub());
            if (names != null && names.size() > 0) {
                MessageDialog.openWarning(Display.getDefault().getActiveShell(),
                        "Expression '" + check.getName() + "' is not valid.",
                        "Expression '" + check.getName() + "' is not valid.\n\n" + names + " cannot be resolved.");
            } else {
                ErrorDialog.openError(Display.getDefault().getActiveShell(),
                        "Expression '" + check.getName() + "' is not valid.",
                        "Expression '" + check.getName() + "' is not valid.", new Status(IStatus.ERROR,
                                "org.dawb.workbench.ui", check.getExpression().getInvalidReason()));
            }
            return true;
        }

        return false;

    }

    private synchronized void updateSelection(boolean fireListeners) {

        if (selections == null)
            return;

        // Record selections
        final String autoType = Activator.getDefault().getPreferenceStore()
                .getString(EditorConstants.SAVE_SEL_DATA);
        if (PlotDataSelection.isAuto(autoType))
            try { // If we are automatic we set the values for the fixed plot.
                StringBuilder buf = new StringBuilder();
                for (ITransferableDataObject ob : selections) {
                    buf.append(ob.getName());
                    buf.append(",");
                }

                Activator.getDefault().getPreferenceStore().setValue(EditorConstants.DATA_SEL, buf.toString());

            } catch (Throwable ne) {
                logger.error("Cannot save last selections!", ne);
            }

        if (fireListeners)
            fireSelectionListeners(selections);
    }

    @Override
    public void setAll1DSelected(final boolean overide) {

        if (!overide && getSelections() != null && getSelections().size() > 0) {
            return; // Something selected, leave it alone.
        }

        selections.clear();
        for (ITransferableDataObject sel : data) {
            final int[] shape = sel.getShape(true);
            if (shape.length == 1) {
                selections.add(sel);
                sel.setChecked(true);
            }
        }
        updateSelection(true);
        dataViewer.refresh();
    }

    private List<ISelectionChangedListener> listeners;

    /**
     * Call to be notified of data set collections being made.
     * The selections returned are a StructuredSelection with a list
     * of objects some are Strings for the data set name and
     * others are ExpressionObject if the user created expressions.
     * 
     * NOTE: The listener is NOT called on the GUI thread.
     * 
     * @param l
     */
    public void addSelectionListener(final ISelectionChangedListener l) {
        if (listeners == null)
            listeners = new ArrayList<ISelectionChangedListener>(7);
        listeners.add(l);
    }

    public void removeSelectionListener(final ISelectionChangedListener l) {
        if (listeners == null)
            return;
        listeners.remove(l);
    }

    protected void fireSelectionListeners(List<ITransferableDataObject> selections) {
        if (listeners == null)
            return;
        final SelectionChangedEvent event = new SelectionChangedEvent(this.dataViewer,
                new StructuredSelection(selections));
        for (ISelectionChangedListener l : listeners)
            l.selectionChanged(event);
    }

    public String getRootName() {
        return rootName;
    }

    /**
     * @param pm The plotMode to set.
     */
    public void setPlotMode(PlotType pm) {
        if (plotModeListeners != null) {
            for (PlotModeListener l : plotModeListeners) {
                l.plotChangePerformed(pm);
            }
        }
    }

    private List<PlotModeListener> plotModeListeners;

    protected void addPlotModeListener(PlotModeListener l) {
        if (plotModeListeners == null)
            plotModeListeners = new ArrayList<PlotModeListener>(7);
        plotModeListeners.add(l);
    }

    protected void removePlotModeListener(PlotModeListener l) {
        if (plotModeListeners == null)
            return;
        plotModeListeners.remove(l);
    }

    protected interface PlotModeListener extends EventListener {
        void plotChangePerformed(PlotType plotMode);
    }

    private List<String> getStringSelections(List<ITransferableDataObject> selections) {

        final List<String> ret = new ArrayList<String>(selections.size());
        for (ITransferableDataObject sel : selections) {
            if (!sel.isExpression())
                ret.add(sel.getName());
        }
        return ret;
    }

    @Override
    public IDataset getVariableValue(String variableName, final IMonitor monitor) {

        final ITransferableDataObject ob = getCheckableObjectByVariable(variableName);
        if (ob == null)
            return null;
        if (!ob.isExpression()) {
            return ob.getData(monitor);
        } else {
            try {
                return ob.getExpression().getDataSet(null, new IMonitor.Stub());
            } catch (Exception e) {
                return null;
            }
        }
    }

    @Override
    public ILazyDataset getLazyValue(String variableName, final IMonitor monitor) {
        final ITransferableDataObject ob = getCheckableObjectByVariable(variableName);
        return ob.getLazyData(monitor);
    }

    /**
     * Tries to get the lazy dataset for the name
     * @param dataName
     * @param monitor
     * @return
     */
    public ILazyDataset getDataValue(String dataName, final IMonitor monitor) {
        for (ITransferableDataObject ob : data) {
            if (ob == null)
                continue;
            if (ob.getName() != null && ob.getName().equals(dataName)) {
                if (ob.isExpression()) {
                    return ob.getExpression().getCachedLazyDataSet();
                } else {
                    return ob.getLazyData(monitor);
                }
            }
        }
        return null;
    }

    @Override
    public boolean isDataName(String dataName, IMonitor monitor) {
        for (ITransferableDataObject ob : data) {
            if (ob.getName().equals(dataName)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public List<String> getVariableNames() {
        List<String> ret = new ArrayList<String>(data.size());
        for (ITransferableDataObject ob : data) {
            ret.add(ob.getVariable());
        }
        return ret;
    }

    @Override
    public List<String> getDataNames() {
        List<String> ret = new ArrayList<String>(data.size());
        for (ITransferableDataObject ob : data) {
            ret.add(ob.getName());
        }
        return ret;
    }

    @Override
    public boolean isVariableName(String variableName, IMonitor monitor) {
        final ITransferableDataObject ob = getCheckableObjectByVariable(variableName);
        return ob != null;
    }

    private ITransferableDataObject getCheckableObjectByVariable(String variableName) {
        for (ITransferableDataObject ob : data) {
            if (ob.getVariable().equals(variableName))
                return ob;
        }
        return null;
    }

    private ITransferableDataObject getCheckableObjectByName(String name) {
        for (ITransferableDataObject ob : data) {
            if (ob.getName().equals(name))
                return ob;
        }
        return null;
    }

    public boolean isDataSetName(String name, IMonitor monitor) {
        final List<String> allNames = getStringSelections(data);
        return allNames.contains(name);
    }

    Color get1DPlotColor(ITransferableDataObject element) {
        final String axis = element.getAxis(selections, getPlottingSystem().is2D(),
                getAbstractPlottingSystem().isXFirst());
        if ("X".equals(axis))
            return PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_BLACK);
        final String name = element.toString();
        if (getPlottingSystem() != null) {
            final Color col = getAbstractPlottingSystem().get1DPlotColor(name);
            return col;
        }
        return null;
    }

    public void dispose() {

        Activator.getDefault().getPreferenceStore().removePropertyChangeListener(propListener);
        datasetSelection = null;

        this.metaData = null;
        this.dataHolder = null;
        this.filePath = null;

        if (listeners != null)
            listeners.clear();
        if (data != null) {
            for (ITransferableDataObject ob : data)
                ob.dispose();
            this.data.clear();
        }
        if (plotModeListeners != null)
            plotModeListeners.clear();
        if (getPlottingSystem() != null && traceListener != null) {
            getPlottingSystem().removeTraceListener(this.traceListener);
        }
        if (getPlottingSystem() != null && dataViewRefreshListener != null) {
            getPlottingSystem().removeTraceListener(this.dataViewRefreshListener);
        }

        if (getPlottingSystem() != null && toolListener != null) {
            getAbstractPlottingSystem().removeToolChangeListener(this.toolListener);
        }
        if (dataViewer != null && !dataViewer.getControl().isDisposed()) {
            dataViewer.getTable().removeMouseListener(this);
            dataViewer.getTable().removeKeyListener(this);
        }
        if (filterProvider != null) {
            filterProvider.dispose();
            filterProvider = null;
        }

    }

    public void addExpression() {

        if (!Activator.getDefault().getPreferenceStore().getBoolean(EditorConstants.SHOW_VARNAME)) {
            Activator.getDefault().getPreferenceStore().setValue(EditorConstants.SHOW_VARNAME, true);
        }
        final ITransferableDataObject newItem = transferableService.createExpression(dataHolder, metaData,
                expressionService.createExpressionObject(this, null, null));
        data.add(newItem);
        dataViewer.refresh();
        try {
            expressionEditor.setExpressionActive(true);
            dataViewer.editElement(newItem, 1);
        } finally {
            expressionEditor.setExpressionActive(false);
        }
    }

    protected void addExpression(IExpressionObject expressionObject) {
        data.add(transferableService.createExpression(dataHolder, metaData, expressionObject));
        dataViewer.refresh();
    }

    public void deleteExpression() {

        final Object sel = ((IStructuredSelection) dataViewer.getSelection()).getFirstElement();
        if (sel == null || !(sel instanceof TransferableDataObject))
            return;

        ITransferableDataObject ob = (ITransferableDataObject) sel;
        if (!ob.isExpression()) {
            if (ob.isTransientData()) { // We delete it
                boolean ok = data.remove(ob);
                if (ok)
                    ob.dispose();
                dataViewer.refresh();
                return;
            } else { // We tell them that we cannot.
                String name = ob.getName();
                MessageDialog.openWarning(Display.getDefault().getActiveShell(), "Cannot delete",
                        "The data '" + name + "' is not an expression.");
                return;
            }
        }

        // We have to process this in a job incase expressions now have to be reevaluated
        if (selections != null)
            selections.remove(sel);
        data.remove(sel);
        clearExpressionCache(ob.getVariable());
        dataViewer.refresh();
        saveExpressions();
        fireSelectionListeners(selections);
    }

    public static List<Pattern> getIgnored() {

        if (Activator.getDefault().getPreferenceStore().getBoolean(EditorConstants.IGNORE_DATASET_FILTERS))
            return null;

        final List<Pattern> patterns = new ArrayList<Pattern>(5);

        IConfigurationElement[] config = Platform.getExtensionRegistry()
                .getConfigurationElementsFor("uk.ac.diamond.scisoft.analysis.data.set.filter");

        for (IConfigurationElement e : config) {
            final String pattern = e.getAttribute("regularExpression");
            patterns.add(Pattern.compile(pattern));
        }

        return patterns;
    }

    public void setData(final IDataHolder dh, IMetadata meta) {
        setData(dh, meta, false);
    }

    /**
     * Used when the view is being controlled from a Dialog.
     * 
     * We actually clone the data holder because the user can paste in datasets
     * from outside this file in order to do expressions on them.
     * 
     * @param meta
     * @throws Exception 
     */
    public void setData(final IDataHolder dh, IMetadata meta, boolean isInit) {

        this.data.clear();
        this.dataHolder = dh.clone();
        this.metaData = meta;
        this.filePath = dh.getFilePath();

        if (metaData == null)
            metaData = dataHolder.getMetadata();

        final Collection<String> names = SliceUtils.getSlicableNames(dataHolder);
        for (String name : names)
            this.data.add(transferableService.createData(dataHolder, metaData, name));

        // Search names to see if they all have a common root, we do not show this.
        this.rootName = DatasetTitleUtils.getRootName(names);

        if (dataFilter != null)
            dataFilter.setMetaData(meta);

        try {
            readExpressions();
            autoSelectData(isInit, names);
        } catch (Exception ne) {
            logger.error("Cannot read expressions for file.", ne);
        }

    }

    /**
     * Method reads properties set to discover what datasets should be preselected.
     * If the file comes from an active data collection lazy dataset, this
     * lazy set it selected and the slice set to the index.
     * 
     * Otherwise the setting to auto-select data is read and previous dataset
     * names looked for.
     */
    private void autoSelectData(boolean isInit, final Collection<String> names) {

        // Find the name of the editor, providing we are init then it might give a clue as to what lazy dataset to auto-select.
        boolean foundData = false;
        if (isInit && editor != null) { // We look to see if the name of the part matches a Lazydataset in the data holder.
            ILoaderService service = (ILoaderService) PlatformUI.getWorkbench().getService(ILoaderService.class);
            final String name = editor.getTitle();
            final Matcher matcher = service.getStackMatcher(name);
            if (matcher.matches()) {
                String index = matcher.group(2);
                if (index != null)
                    index = NumberUtils.removeLeadingZeros(index);
                if (Integer.parseInt(index) == 1) {
                    String lazySetName = matcher.group(1);
                    if (dataHolder.contains(lazySetName)) {
                        for (ITransferableDataObject checker : data) {
                            if (checker.getName().equals(lazySetName)) {
                                if (!foundData)
                                    selections.clear();
                                checker.setChecked(true);
                                this.selections.add(checker);
                                foundData = true;
                            }
                        }
                    }
                }
            }
        }

        // Some of the meta data
        if (!foundData) {
            final String autoType = Activator.getDefault().getPreferenceStore()
                    .getString(EditorConstants.SAVE_SEL_DATA);
            if (PlotDataSelection.isActive(autoType)) {
                try {

                    final String prop = Activator.getDefault().getPreferenceStore()
                            .getString(EditorConstants.DATA_SEL);
                    if (prop != null) {
                        final Collection<String> saveSelections = Arrays.asList(prop.split(","));
                        if (data != null && !data.isEmpty()) {
                            for (ITransferableDataObject checker : data) {
                                if (saveSelections.contains(checker.getName())) {
                                    if (!foundData)
                                        selections.clear();
                                    checker.setChecked(true);
                                    this.selections.add(checker);
                                    foundData = true;
                                }
                            }
                        }
                    }
                } catch (Throwable ne) {
                    logger.error("Cannot save data previously selected!", ne);
                }
            }
        }

        if (foundData) {
            fireSelectionListeners(selections);
        }

        // If we are an image or a single data set, plot it.
        final List<String> namesNoStack = new ArrayList<String>(names);
        namesNoStack.remove("Image Stack");
        if (namesNoStack != null && namesNoStack.size() == 1) {
            ITransferableDataObject check = data.get(0);
            check.setChecked(false); // selectionChanged flips this
            selectionChanged(check, true);
            dataViewer.refresh();
        }

    }

    public void refresh() {
        this.dataViewer.refresh();
    }

    public String getFileName() {
        if (filePath != null)
            return (new File(filePath)).getName();
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    private IDataset datasetSelection = null;

    /**
     * Thread safe
     * @param name
     */
    public IDataset setDatasetSelected(final String name, final boolean clearOthers) {

        datasetSelection = null;
        PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
            @Override
            public void run() {
                if (clearOthers) {
                    PlotDataComponent.this.setAllChecked(false);
                    PlotDataComponent.this.selectionChanged(null, true);
                }

                final ITransferableDataObject check = PlotDataComponent.this.getObjectByName(name);
                check.setChecked(false);
                PlotDataComponent.this.selectionChanged(check, true);
                datasetSelection = check.getData((IMonitor) null);
            }
        });

        return datasetSelection;
    }

    protected void setAllChecked(boolean isChecked) {
        for (ITransferableDataObject check : data) {
            check.setChecked(isChecked);
        }
    }

    /**
     * Does a loop, may be bad...
     * @param name
     * @return
     */
    protected ITransferableDataObject getObjectByName(final String name) {
        for (ITransferableDataObject check : data) {
            if (name.equals(check.getName()))
                return check;
        }
        return null;
    }

    public IPlottingSystem getPlottingSystem() {
        if (editor == null)
            return null;
        return (IPlottingSystem) editor.getAdapter(IPlottingSystem.class);
    }

    /**
     * May return null! Editor does not have to be a plotting editor.
     * @return
     */
    private AbstractPlottingSystem getAbstractPlottingSystem() {
        return (AbstractPlottingSystem) getPlottingSystem();
    }

    public boolean isStaggerSupported() {
        return staggerSupported;
    }

    public void setStaggerSupported(boolean staggerSupported) {
        this.staggerSupported = staggerSupported;
    }

    public List<ITransferableDataObject> getData() {
        return data;
    }

    public ISelectionProvider getViewer() {
        return dataViewer;
    }

    @Override
    public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
        if (adapter == IPlottingSystem.class) {
            return getPlottingSystem();
        }
        return null;
    }

    IMetadata getMetaData() {
        return metaData;
    }

}