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

Java tutorial

Introduction

Here is the source code for org.dawnsci.plotting.tools.history.HistoryTool.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.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.dawb.common.ui.plot.tools.HistoryType;
import org.dawnsci.plotting.tools.Activator;
import org.dawnsci.plotting.tools.history.HistoryBean.AxisType;
import org.dawnsci.plotting.tools.profile.ProfileType;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
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.plotting.api.axis.IAxis;
import org.eclipse.dawnsci.plotting.api.expressions.IExpressionObject;
import org.eclipse.dawnsci.plotting.api.trace.ILineTrace;
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.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.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HistoryTool extends AbstractHistoryTool implements MouseListener {

    private Logger logger = LoggerFactory.getLogger(HistoryTool.class);

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

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

    @Override
    public Serializable getToolData() {
        return (Serializable) history;
    }

    public HistoryTool() {
        super(true);
    }

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

    protected IAction createAddAction() {
        return new Action("Add currently plotted plot(s) to history",
                Activator.getImageDescriptor("icons/add.png")) {
            public void run() {
                addTraces();
            }
        };
    }

    protected void addTraces() {
        final Collection<ITrace> traces = getPlottingSystem().getTraces(ILineTrace.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;
            if (!iTrace.isUserTrace())
                continue;
            final ILineTrace lineTrace = (ILineTrace) iTrace;
            final HistoryBean bean = new HistoryBean(this);
            bean.setXdata((Dataset) lineTrace.getXData());
            bean.setYdata((Dataset) lineTrace.getYData());
            bean.setTraceName(iTrace.getName());
            if (lineTrace.getTraceColor() != null) {
                bean.setPlotColour(lineTrace.getTraceColor().getRGB());
            }
            if (lineTrace.getUserObject() != null && lineTrace.getUserObject() instanceof String) {
                bean.setVariable((String) lineTrace.getUserObject());
            }

            bean.setPlotName(getPlottingSystem().getPlotName());
            if (isLinkedToolPage()) {
                // Go back up one so that history of profiles can be done.
                // This is the plotting system for the image, so we take the
                // image name and use that.
                bean.setPlotName(getLinkedToolPage().getPlottingSystem().getPlotName());
            }

            // All profiles are treated as unique
            if (iTrace.getUserObject() == ProfileType.PROFILE) {
                bean.generateUniqueKey(history.keySet());
            }

            bean.setSelected(true);
            history.put(bean.getTraceKey(), bean);
        }
        refresh();
        updatePlots(true);
    }

    private ITraceListener autoAddTraceListener;
    private static Action autoAdd;

    /**
     * May be overridden to provide additional actions.
     */
    protected MenuManager createActions(final MenuManager rightClick) {

        this.autoAddTraceListener = new ITraceListener.Stub() {
            @Override
            public void tracesAdded(TraceEvent evt) {
                addTraces(); // Adds anything it can.
            }
        };

        MenuManager ret = super.createActions(rightClick);

        if (autoAdd == null)
            autoAdd = new Action("Automatically add any new plots to history", IAction.AS_CHECK_BOX) {
                public void run() {
                    toggleAutomaticallyAddTraces();
                }
            };
        getSite().getActionBars().getToolBarManager().add(autoAdd);

        autoAdd.setImageDescriptor(Activator.getImageDescriptor("icons/autoadd.png"));
        getSite().getActionBars().getToolBarManager().add(new Separator());
        getSite().getActionBars().getToolBarManager().add(autoAdd);
        getSite().getActionBars().getToolBarManager().add(new Separator());

        return ret;
    }

    protected void toggleAutomaticallyAddTraces() {
        if (autoAdd == null)
            return;
        if (autoAddTraceListener == null)
            return;
        if (getPlottingSystem() == null)
            return;
        if (autoAdd.isChecked()) {
            getPlottingSystem().addTraceListener(autoAddTraceListener);
            addTraces();
        } else {
            getPlottingSystem().removeTraceListener(autoAddTraceListener);
        }
    }

    public void activate() {
        super.activate();
        toggleAutomaticallyAddTraces();
    }

    public void deactivate() {
        super.deactivate();
        if (autoAddTraceListener == null)
            return;
        if (getPlottingSystem() == null)
            return;
        getPlottingSystem().removeTraceListener(autoAddTraceListener);
    }

    protected int createColumns(TableViewer viewer) {

        ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE);
        viewer.setColumnProperties(new String[] { "Selected", "Name", "Original Plot", "Color" });

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

        var = new TableViewerColumn(viewer, SWT.CENTER, ++count);
        var.getColumn().setText("Name");
        var.getColumn().setWidth(140);
        var.setLabelProvider(new HistoryLabelProvider());
        var.setEditingSupport(new ExpressionEditingSupport(viewer));

        var = new TableViewerColumn(viewer, SWT.CENTER, ++count);
        var.getColumn().setText("Original Plot");
        var.getColumn().setWidth(140);
        var.setLabelProvider(new HistoryLabelProvider());

        var = new TableViewerColumn(viewer, SWT.LEFT, ++count);
        var.getColumn().setText(" ");
        var.getColumn().setWidth(32);
        var.setLabelProvider(new AxisLabelProvider());
        var.setEditingSupport(new AxisEditingSupport(viewer));

        var = new TableViewerColumn(viewer, SWT.CENTER, ++count);
        var.getColumn().setText("Shape");
        var.getColumn().setWidth(80);
        var.setLabelProvider(new HistoryLabelProvider());

        return count + 1;
    }

    /**
     * Moves any axes that are X to Y1
     */
    private void removeXAxis() {
        for (HistoryBean bean : getHistoryCache().values()) {
            if (AxisType.X == bean.getAxis() && bean.isSelected()) {
                bean.setAxis(AxisType.Y1);
            }
        }
    }

    protected void updatePlots(boolean force) {

        if (!isActive())
            return;

        super.updatePlots(force);
        checkVisibleAxes();
    }

    protected HistoryBean toggleSelection() {
        final HistoryBean bean = super.toggleSelection();
        if (AxisType.X == bean.getAxis()) {
            getPlottingSystem().clear();
            updatePlots(true);
            return bean;
        }
        if (bean != null)
            checkVisibleAxes();
        return bean;
    }

    /**
     * Checks to see if all axes should still be visible.
     */
    private void checkVisibleAxes() {
        if (updatingPlotsAlready)
            return;
        // We now look for any unused axes and hide them.
        // Not an ideal thing to do but the 'Data' page and other tools
        // may be using the other axes so we cannot be sure to remove
        // any that we are no longer using here.
        final Collection<IAxis> usedAxes = new HashSet<IAxis>(3);
        usedAxes.add(getPlottingSystem().getSelectedXAxis());
        usedAxes.add(getPlottingSystem().getSelectedYAxis());
        for (ITrace trace : getPlottingSystem().getTraces()) {
            if (trace instanceof ILineTrace) {
                ILineTrace ltrace = (ILineTrace) trace;
                if (!ltrace.isVisible())
                    continue;
                usedAxes.add(ltrace.getXAxis());
                usedAxes.add(ltrace.getYAxis());
            }
        }
        // Finally change the visibility to those actually used
        final List<IAxis> allAxes = getPlottingSystem().getAxes();
        for (IAxis iAxis : allAxes) {
            iAxis.setVisible(usedAxes.contains(iAxis));
        }
    }

    /**
     * Pushes history plot to and from the main plot depending on if it is selected.
     */
    protected void updatePlot(HistoryBean bean, boolean force) {

        if (getPlottingSystem().is2D()) {
            logger.error("Plotting system is plotting 2D data, history should not be active.");
            return;
        }
        if (updatingAPlotAlready && !force)
            return;
        try {
            updatingAPlotAlready = true;

            final boolean isSamePlot = getPlottingSystem().getPlotName() != null
                    && getPlottingSystem().getPlotName().equals(bean.getPlotName());
            if (isSamePlot) {
                final String message = "Cannot update " + bean.getTraceName() + " from memory to plot in "
                        + bean.getPlotName() + " as it comes from this plot originally!";
                logger.trace(message);

                // User may be interested in this fact.
                Activator.getPluginLog().log(new Status(IStatus.WARNING, "org.dawnsci.plotting", message));
                final ITrace trace = getPlottingSystem().getTrace(bean.getTraceName());
                if (trace != null) {
                    //               bean.setPlotColour(((ILineTrace)trace).getTraceColor().getRGB());
                    //               if (viewer!=null) viewer.refresh(bean);
                    return;
                }
            }

            final String traceName = bean.createTraceName();

            if (!bean.isSelected()) {
                final ITrace trace = getPlottingSystem().getTrace(traceName);
                if (trace != null)
                    getPlottingSystem().removeTrace(trace);
            } else {

                if (getPlottingSystem().getTrace(traceName) != null) {
                    logger.warn("Cannot bring " + traceName + " from memory to plot in " + bean.getPlotName()
                            + " as it already exists there!");
                    return;
                } else {

                    IAxis selectedYAxis = getPlottingSystem().getSelectedYAxis();
                    try {
                        if (bean.getAxis() != null) {
                            if (bean.getAxis() == AxisType.Y2) {
                                IAxis y2 = getPlottingSystem().getAxis("Y2");
                                if (y2 == null) {
                                    y2 = getPlottingSystem().createAxis("Y2", true, SWT.LEFT);
                                    y2.setTitle("Y2");
                                }
                                y2.setVisible(true);
                                getPlottingSystem().setSelectedYAxis(y2);
                            } else if (bean.getAxis() == AxisType.X) {
                                return; // This is the X data which we will use.
                            }
                        }
                        final ILineTrace trace = getPlottingSystem().createLineTrace(traceName);
                        trace.setUserObject(HistoryType.HISTORY_PLOT);
                        trace.setData(getXData(bean), bean.getYdata());
                        if (!isColourOk(bean.getPlotColour())) {
                            getPlottingSystem().addTrace(trace);
                            bean.setPlotColour(trace.getTraceColor().getRGB());
                            if (viewer != null)
                                viewer.refresh(bean);
                        } else {
                            trace.setTraceColor(new Color(null, bean.getPlotColour()));
                            getPlottingSystem().addTrace(trace);
                        }
                    } finally {
                        getPlottingSystem().setSelectedYAxis(selectedYAxis);
                    }
                }
            }
            getPlottingSystem().repaint();
        } finally {
            updatingAPlotAlready = false;
        }
    }

    /**
     * Checks if any bean is set to X, if it is and the X is the right size,
     * will return this x-data, otherwise returns the x-data of the bean.
     * @param bean
     * @return
     */
    private IDataset getXData(HistoryBean bean) {
        if (bean.getAxis() == AxisType.X)
            throw new RuntimeException(
                    bean.getTraceName() + " is the X data and should not be plotted as Y anyway!");
        final IDataset origX = bean.getXdata();
        for (HistoryBean possibleX : history.values()) {
            if (possibleX.isSelected() && AxisType.X == possibleX.getAxis()) {
                final IDataset x = possibleX.getYdata();
                if (x != null && x.getSize() == origX.getSize())
                    return x;
            }
        }
        return origX;
    }

    private boolean isColourOk(RGB plotColour) {

        if (plotColour == null)
            return false;
        final Collection<ITrace> lines = getPlottingSystem().getTraces(ILineTrace.class);
        for (ITrace iTrace : lines) {
            final ILineTrace lineTrace = (ILineTrace) iTrace;
            if (lineTrace.getTraceColor() != null && lineTrace.getTraceColor().getRGB().equals(plotColour)) {
                return false;
            }
        }
        return true;
    }

    private class HistoryLabelProvider extends ColumnLabelProvider {

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

        public HistoryLabelProvider() {

            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 == 4) {
                Dataset data = bean.getYdata();
                if (data == null)
                    return "-";
                return Arrays.toString(bean.getYdata().getShape());
            }
            return "";
        }

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

        private Color getColor(Object element) {
            if (!(element instanceof HistoryBean))
                return null;
            if (columnIndex == 1) { // The name
                final HistoryBean bean = (HistoryBean) element;
                if (bean.getPlotColour() == null)
                    return null;
                return new Color(null, bean.getPlotColour());
            }
            return null;
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.IColorProvider#getForeground(java.lang.Object)
         */
        public Color getForeground(Object element) {
            if (columnIndex == 1) {
                final IExpressionObject o = ((HistoryBean) element).getExpression();
                if (o != null) {
                    return o.isValid(new IMonitor.Stub()) ? BLUE : RED;
                }
            }
            return getColor(element);
        }

    }

    private class ExpressionEditingSupport extends EditingSupport {

        public ExpressionEditingSupport(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) {
            final HistoryBean bean = ((HistoryBean) element);
            return bean.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);
            } else {
                ((HistoryBean) element).setTraceName((String) value);
            }
            getPlottingSystem().clear();
            updatePlots(true);
            viewer.refresh(element);
        }

    }

    private class AxisLabelProvider extends ColumnLabelProvider {

        @Override
        public String getText(Object ob) {
            if (ob == null || !(ob instanceof HistoryBean))
                return null;
            return ((HistoryBean) ob).getAxis().name();
        }
    }

    private class AxisEditingSupport extends EditingSupport {

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

        @Override
        protected CellEditor getCellEditor(final Object element) {
            // FIX to http://jira.diamond.ac.uk/browse/DAWNSCI-380 remove axes until they work
            ComboBoxCellEditor ce = new ComboBoxCellEditor((Composite) getViewer().getControl(),
                    new String[] { "X", "Y1", "Y2" /**,"Y3","Y4" **/
                    }, SWT.READ_ONLY);
            final CCombo ccombo = (CCombo) ce.getControl();
            ccombo.addSelectionListener(new SelectionAdapter() {
                public void widgetSelected(SelectionEvent e) {
                    setValue(element, ccombo.getItem(ccombo.getSelectionIndex()));
                }
            });
            return ce;
        }

        @Override
        protected boolean canEdit(Object ob) {
            if (ob == null || !(ob instanceof HistoryBean))
                return false;
            return true;
        }

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

        @Override
        protected void setValue(Object element, Object value) {
            viewer.cancelEditing();
            HistoryBean hb = (HistoryBean) element;
            if (value instanceof String) {
                final AxisType type = AxisType.valueOf((String) value);
                if (type == AxisType.X)
                    removeXAxis(); // Move the other x if there is one to Y1

                hb.setAxis(type);
                getPlottingSystem().clear();
                updatePlots(true);
                viewer.refresh(); // Must be complete refresh, we changed other axes.
            }
        }

    }
}