org.dawnsci.plotting.tools.window.WindowTool.java Source code

Java tutorial

Introduction

Here is the source code for org.dawnsci.plotting.tools.window.WindowTool.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
 */
/*
 * Copyright 2012 Diamond Light Source Ltd.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.dawnsci.plotting.tools.window;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.dawb.common.ui.util.GridUtils;
import org.dawnsci.common.richbeans.components.scalebox.IntegerBox;
import org.dawnsci.common.richbeans.components.scalebox.NumberBox;
import org.dawnsci.common.richbeans.event.ValueAdapter;
import org.dawnsci.common.richbeans.event.ValueEvent;
import org.dawnsci.plotting.roi.SurfacePlotROI;
import org.dawnsci.plotting.tools.Activator;
import org.dawnsci.plotting.util.PlottingUtils;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.dawnsci.analysis.api.dataset.IDataset;
import org.eclipse.dawnsci.analysis.api.roi.IROI;
import org.eclipse.dawnsci.analysis.dataset.impl.Dataset;
import org.eclipse.dawnsci.analysis.dataset.roi.LinearROI;
import org.eclipse.dawnsci.analysis.dataset.roi.RectangularROI;
import org.eclipse.dawnsci.plotting.api.IPlottingSystem;
import org.eclipse.dawnsci.plotting.api.PlottingFactory;
import org.eclipse.dawnsci.plotting.api.region.IROIListener;
import org.eclipse.dawnsci.plotting.api.region.IRegion;
import org.eclipse.dawnsci.plotting.api.region.IRegionListener;
import org.eclipse.dawnsci.plotting.api.region.ROIEvent;
import org.eclipse.dawnsci.plotting.api.region.RegionEvent;
import org.eclipse.dawnsci.plotting.api.region.IRegion.RegionType;
import org.eclipse.dawnsci.plotting.api.tool.AbstractToolPage;
import org.eclipse.dawnsci.plotting.api.tool.IToolPageSystem;
import org.eclipse.dawnsci.plotting.api.trace.ILineStackTrace;
import org.eclipse.dawnsci.plotting.api.trace.IPaletteListener;
import org.eclipse.dawnsci.plotting.api.trace.IPaletteTrace;
import org.eclipse.dawnsci.plotting.api.trace.ISurfaceTrace;
import org.eclipse.dawnsci.plotting.api.trace.ITrace;
import org.eclipse.dawnsci.plotting.api.trace.ITraceListener;
import org.eclipse.dawnsci.plotting.api.trace.IWindowTrace;
import org.eclipse.dawnsci.plotting.api.trace.PaletteEvent;
import org.eclipse.dawnsci.plotting.api.trace.TraceEvent;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.mihalis.opal.rangeSlider.RangeSlider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A tool which has one box region for configuring the region
 * which defines the window of a 3D plot.
 * 
 * @author Matthew Gerring
 *
 */
public class WindowTool extends AbstractToolPage {

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

    private IPlottingSystem windowSystem;
    private IRegionListener regionListener;
    private IROIListener roiListener;
    private ITraceListener traceListener;
    private IPaletteListener paletteListener;
    private WindowJob windowJob;
    private Composite sliceControl, windowControl, blankComposite;
    private Composite content;

    private RegionControlWindow regionControlWindow;

    public WindowTool() {
        try {
            this.windowSystem = PlottingFactory.createPlottingSystem();
            this.windowJob = new WindowJob();

            this.traceListener = new ITraceListener.Stub() {
                protected void update(TraceEvent evt) {
                    ITrace trace = getTrace();
                    if (trace != null) {
                        if (trace instanceof ISurfaceTrace)
                            updateWindowPlot((ISurfaceTrace) trace);
                    } else {
                        windowSystem.clear();
                    }
                }
            };

            this.paletteListener = new IPaletteListener.Stub() {
                @Override
                public void paletteChanged(PaletteEvent evt) {
                    try {
                        ITrace trace = windowSystem.getTraces().iterator().next();
                        if (trace instanceof IPaletteTrace) {
                            ((IPaletteTrace) trace).setPaletteData(evt.getPaletteData());
                        }
                    } catch (Exception ne) {
                        logger.error("Cannot set new palette.", ne);
                    }
                }
            };

            this.roiListener = new IROIListener() {
                @Override
                public void roiDragged(ROIEvent evt) {
                    IROI roi = evt.getROI();
                    if (roi != null && roi instanceof RectangularROI) {
                        SurfacePlotROI sroi = getSurfacePlotROI((RectangularROI) roi, true);
                        windowJob.schedule(sroi, false);
                    }
                }

                @Override
                public void roiChanged(ROIEvent evt) {
                    IROI roi = evt.getROI();
                    if (roi != null && roi instanceof RectangularROI) {
                        SurfacePlotROI sroi = getSurfacePlotROI((RectangularROI) roi, false);
                        windowJob.schedule(sroi, false);
                    }
                }

                @Override
                public void roiSelected(ROIEvent evt) {

                }
            };

            this.regionListener = new IRegionListener.Stub() {
                @Override
                public void regionAdded(RegionEvent evt) {
                    evt.getRegion().addROIListener(roiListener);
                }

                @Override
                public void regionRemoved(RegionEvent evt) {
                    evt.getRegion().removeROIListener(roiListener);
                }
            };
        } catch (Exception e) {
            logger.error("Cannot create a plotting system, something bad happened!", e);
        }
    }

    @Override
    public void createControl(Composite parent) {

        this.content = new Composite(parent, SWT.NONE);
        final StackLayout stackLayout = new StackLayout();
        content.setLayout(stackLayout);

        this.regionControlWindow = new RegionControlWindow(content, getPlottingSystem(), windowSystem, windowJob);
        this.windowControl = regionControlWindow.createRegionControl(getTitle(), getSite(), getViewPart(),
                getImageDescriptor());
        this.sliceControl = createSliceControl();

        final ITrace trace = getTrace();
        if (trace instanceof ISurfaceTrace) {
            stackLayout.topControl = windowControl;
        } else if (trace instanceof ILineStackTrace) {
            stackLayout.topControl = sliceControl;
        }

        this.blankComposite = new Composite(content, SWT.BORDER);

    }

    @Override
    public IPlottingSystem getToolPlottingSystem() {
        return windowSystem;
    }

    private CLabel errorLabel;
    private RangeSlider sliceSlider;
    private NumberBox lowerControl, upperControl;
    private int lastLower = -1, lastUpper = -1;

    private Composite createSliceControl() {
        Composite sliceControl = new Composite(content, SWT.NONE);
        sliceControl.setLayout(new GridLayout(3, false));

        final Label info = new Label(sliceControl, SWT.WRAP);
        info.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 2));
        info.setText("Please edit the window of the data, not more than 100 symultaneous plots are allowed in 3D.");

        sliceSlider = new RangeSlider(sliceControl, SWT.HORIZONTAL);
        sliceSlider.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 2));
        sliceSlider.setMinimum(0);
        sliceSlider.setMaximum(25);
        sliceSlider.setLowerValue(0);
        sliceSlider.setUpperValue(25);
        sliceSlider.setIncrement(1);

        GridData gridData = new GridData(GridData.FILL, GridData.BEGINNING, false, false, 2, 1);
        gridData.widthHint = 130;

        lowerControl = new IntegerBox(sliceControl, SWT.NONE);
        lowerControl.setLabel(" Lower    ");
        lowerControl.setLayoutData(gridData);
        lowerControl.setIntegerValue(sliceSlider.getLowerValue());
        lowerControl.setActive(true);
        lowerControl.on();
        lowerControl.addValueListener(new ValueAdapter() {
            @Override
            public void valueChangePerformed(ValueEvent e) {
                sliceSlider.setLowerValue(lowerControl.getIntegerValue());
                final int lower = sliceSlider.getLowerValue();
                final int upper = sliceSlider.getUpperValue();
                if (lower < 0 || upper < 0)
                    return;
                updateSliceRange(lower, upper, sliceSlider.getMaximum(), false);
                lastLower = lower;
                lastUpper = upper;
            }
        });

        upperControl = new IntegerBox(sliceControl, SWT.NONE);
        upperControl.setLabel(" Upper    ");
        upperControl.setLayoutData(gridData);
        upperControl.setIntegerValue(sliceSlider.getUpperValue());
        upperControl.setActive(true);
        upperControl.on();
        upperControl.addValueListener(new ValueAdapter() {
            @Override
            public void valueChangePerformed(ValueEvent e) {
                sliceSlider.setUpperValue(upperControl.getIntegerValue());
                final int lower = sliceSlider.getLowerValue();
                final int upper = sliceSlider.getUpperValue();
                if (lower < 0 || upper < 0)
                    return;
                updateSliceRange(lower, upper, sliceSlider.getMaximum(), false);
                lastLower = lower;
                lastUpper = upper;
            }
        });

        upperControl.setMinimum(lowerControl);
        upperControl.setMaximum(25);
        lowerControl.setMinimum(0);
        lowerControl.setMaximum(upperControl);

        errorLabel = new CLabel(sliceControl, SWT.WRAP);
        errorLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
        errorLabel.setText("The slice range is too large.");
        errorLabel.setImage(Activator.getImage("icons/error.png"));

        sliceSlider.addMouseMoveListener(new MouseMoveListener() {
            @Override
            public void mouseMove(MouseEvent e) {
                if ((e.button & SWT.BUTTON1) == 0) {
                    final int lower = sliceSlider.getLowerValue();
                    final int upper = sliceSlider.getUpperValue();
                    if (lower < 0 || upper < 0)
                        return;
                    if (lower == lastLower && upper == lastUpper)
                        return;

                    sliceSlider.setToolTipText("(" + sliceSlider.getMinimum() + ")  " + lower + " <-> " + upper
                            + "  (" + sliceSlider.getMaximum() + ")");
                    upperControl.setIntegerValue(upper);
                    lowerControl.setIntegerValue(lower);
                    updateSliceRange(lower, upper, sliceSlider.getMaximum(), false);

                    lastLower = lower;
                    lastUpper = upper;
                }
            }
        });

        return sliceControl;
    }

    protected void updateSliceRange(int lower, int upper, int max, boolean setValue) {
        if (upper - lower > 100) {
            GridUtils.setVisible(errorLabel, true);
            errorLabel.getParent().layout();
            return;
        }

        GridUtils.setVisible(errorLabel, false);
        errorLabel.getParent().layout();

        if (setValue) { // Send to UI
            sliceSlider.setMaximum(max);
            sliceSlider.setLowerValue(lower);
            sliceSlider.setUpperValue(upper);
            lowerControl.setIntegerValue(lower);
            upperControl.setIntegerValue(upper);
            upperControl.setMaximum(max);
        } else { // Send to region
            final LinearROI roi = new LinearROI(new double[] { lower, 0 }, new double[] { upper, 0 });
            windowJob.schedule(roi);
        }

    }

    protected void updateTrace(ITrace trace) {
        if (content == null)
            return;
        if (trace instanceof ISurfaceTrace) {
            setActionsEnabled(true);
            updateWindowPlot((ISurfaceTrace) trace);
            ((ISurfaceTrace) trace).addPaletteListener(paletteListener);
        } else if (trace instanceof ILineStackTrace) {
            setActionsEnabled(false);
            updateSlicePlot((ILineStackTrace) trace);
        } else {
            setActionsEnabled(false);
            StackLayout stackLayout = (StackLayout) content.getLayout();
            stackLayout.topControl = blankComposite;
            content.layout();
        }
    }

    private void setActionsEnabled(boolean enabled) {
        if (getSite() == null)
            return;
        IContributionManager[] mans = new IContributionManager[] { getSite().getActionBars().getToolBarManager(),
                getSite().getActionBars().getMenuManager() };
        for (IContributionManager man : mans) {
            IContributionItem[] items = man.getItems();
            for (IContributionItem item : items) {
                item.setVisible(enabled);
            }
            man.update(true);
        }
    }

    private SurfacePlotROI getSurfacePlotROI(RectangularROI rroi, boolean isDrag) {
        int startX = (int) Math.round(rroi.getPointX());
        int startY = (int) Math.round(rroi.getPointY());
        int roiWidth = (int) Math.round(rroi.getLengths()[0]);
        int roiHeight = (int) Math.round(rroi.getLengths()[1]);
        int endX = (int) Math.round(rroi.getEndPoint()[0]);
        int endY = (int) Math.round(rroi.getEndPoint()[1]);
        regionControlWindow.setSpinnerValues(startX, startY, roiWidth, roiHeight);

        int xAspectRatio = 0, yAspectRatio = 0, binShape = 1, samplingMode = 0, lowerClipping = 0,
                upperClipping = 100000;
        if (regionControlWindow.isOverwriteAspect()) {
            xAspectRatio = regionControlWindow.getXAspectRatio();
            yAspectRatio = regionControlWindow.getYAspectRatio();
        }
        if (regionControlWindow.isApplyClipping()) {
            lowerClipping = regionControlWindow.getLowerClipping();
            upperClipping = regionControlWindow.getUpperClipping();
        }
        binShape = PlottingUtils.getBinShape(rroi.getLengths()[0], rroi.getLengths()[1], isDrag);

        if (binShape != 1) {
            // DownsampleMode.MEAN = 2
            samplingMode = 2;
        }
        SurfacePlotROI sroi = new SurfacePlotROI(startX, startY, endX, endY, samplingMode, samplingMode,
                xAspectRatio, yAspectRatio);
        sroi.setLengths(Double.valueOf(endX - startX), Double.valueOf(endY - startY));
        sroi.setXBinShape(binShape);
        sroi.setYBinShape(binShape);
        sroi.setLowerClipping(lowerClipping);
        sroi.setUpperClipping(upperClipping);
        sroi.setIsClippingApplied(regionControlWindow.isApplyClipping());
        return sroi;
    }

    protected void updateWindowPlot(ISurfaceTrace trace) {
        Dataset data = (Dataset) trace.getData();
        List<IDataset> axes = trace.getAxes();
        if (axes != null)
            axes = Arrays.asList(axes.get(0), axes.get(1));
        windowSystem.updatePlot2D(data, axes, null);
        if (regionControlWindow != null && regionControlWindow.isControlReady())
            regionControlWindow.createSurfaceRegion("Window", true);
        // manage layout
        if (content != null && content.isDisposed())
            return;
        StackLayout stackLayout = (StackLayout) content.getLayout();
        stackLayout.topControl = windowControl;
        content.layout();
    }

    protected void updateSlicePlot(ILineStackTrace trace) {

        StackLayout stackLayout = (StackLayout) content.getLayout();
        stackLayout.topControl = sliceControl;

        final LinearROI roi = (LinearROI) trace.getWindow();
        if (roi != null) {
            final int lower = roi.getIntPoint()[0];
            final int upper = (int) Math.round(((LinearROI) roi).getEndPoint()[0]);
            updateSliceRange(lower, upper, trace.getStack().length, true);
        }
        content.layout();
    }

    @Override
    public void activate() {
        super.activate();

        if (getPlottingSystem() != null) {
            getPlottingSystem().addTraceListener(traceListener);
        }
        if (windowSystem != null && windowSystem.getPlotComposite() != null) {
            final ITrace trace = getTrace();
            if (trace != null)
                updateTrace(trace);

            windowSystem.addRegionListener(regionListener);

            final Collection<IRegion> boxes = windowSystem.getRegions(RegionType.BOX);
            if (boxes != null)
                for (IRegion iRegion : boxes)
                    iRegion.addROIListener(roiListener);
            windowJob.schedule();
        }
        if (regionControlWindow != null)
            regionControlWindow.addSelectionListener();
    }

    @Override
    public void deactivate() {
        super.deactivate();

        if (getPlottingSystem() != null) {
            getPlottingSystem().removeTraceListener(traceListener);

        }
        if (windowSystem != null && windowSystem.getPlotComposite() != null) {
            windowSystem.removeRegionListener(regionListener);

            final Collection<IRegion> boxes = windowSystem.getRegions(RegionType.BOX);
            if (boxes != null)
                for (IRegion iRegion : boxes)
                    iRegion.removeROIListener(roiListener);
        }
        if (regionControlWindow != null)
            regionControlWindow.removeSelectionListener();
    }

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

    @Override
    public Control getControl() {
        return content;
    }

    @Override
    public Object getAdapter(@SuppressWarnings("rawtypes") Class clazz) {
        if (clazz == IToolPageSystem.class) {
            return windowSystem;
        } else {
            return super.getAdapter(clazz);
        }
    }

    @Override
    public void setFocus() {
        if (windowSystem != null && !windowSystem.isDisposed())
            windowSystem.setFocus();
    }

    @Override
    public void dispose() {
        super.dispose();
    }

    public class WindowJob extends Job {

        private IROI window;
        private boolean updateClipping;

        public WindowJob() {
            super("Window");
            setPriority(Job.INTERACTIVE);
            setUser(false);
            setSystem(true);
        }

        protected void schedule(IROI window) {
            cancel();
            this.window = window;
            schedule();
        }

        protected void schedule(IROI window, boolean updateClipping) {
            this.updateClipping = updateClipping;
            schedule(window);
        }

        @Override
        protected IStatus run(final IProgressMonitor monitor) {
            if (monitor.isCanceled())
                return Status.CANCEL_STATUS;

            monitor.beginTask("Sending data to plot", 100);

            final IWindowTrace windowTrace = getWindowTrace();
            if (windowTrace != null) {
                Display.getDefault().syncExec(new Runnable() {
                    public void run() {
                        if (monitor.isCanceled())
                            return;
                        try {
                            IStatus result = null;
                            if (windowTrace instanceof ISurfaceTrace) {
                                result = ((ISurfaceTrace) windowTrace).setWindow(window, updateClipping, monitor);
                            } else {
                                result = windowTrace.setWindow(window, monitor);
                            }
                            if (result == Status.CANCEL_STATUS)
                                return;
                        } catch (Exception ne) {
                            logger.error("Cannot window surface!", ne);
                        }
                    }
                });
            } else {
                return Status.CANCEL_STATUS;
            }
            monitor.done();
            return Status.OK_STATUS;
        }
    }
}