org.dawnsci.plotting.roi.AxisPixelROIEditTable.java Source code

Java tutorial

Introduction

Here is the source code for org.dawnsci.plotting.roi.AxisPixelROIEditTable.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.roi;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.dawb.common.util.number.DoubleUtils;
import org.dawnsci.common.richbeans.components.cell.FieldComponentCellEditor;
import org.dawnsci.common.richbeans.components.wrappers.FloatSpinnerWrapper;
import org.dawnsci.common.richbeans.components.wrappers.SpinnerWrapper;
import org.eclipse.dawnsci.analysis.api.processing.model.AbstractOperationModel;
import org.eclipse.dawnsci.analysis.api.roi.IROI;
import org.eclipse.dawnsci.analysis.dataset.roi.RectangularROI;
import org.eclipse.dawnsci.plotting.api.IPlottingSystem;
import org.eclipse.dawnsci.plotting.api.axis.ICoordinateSystem;
import org.eclipse.dawnsci.plotting.api.region.IRegion;
import org.eclipse.dawnsci.plotting.api.trace.IImageTrace;
import org.eclipse.dawnsci.plotting.api.trace.ITrace;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Table;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Class to create a TableViewer that shows ROI information<br>
 * both with real (axis) and pixel values.<br>
 * This table uses JFace data binding to update its content.
 * TODO make it work with all ROIs (only working for RectangularROI currently)
 * @author wqk87977
 *
 */
public class AxisPixelROIEditTable {
    private Logger logger = LoggerFactory.getLogger(AxisPixelROIEditTable.class);

    private Composite parent;
    private TableViewer regionViewer;

    private AxisPixelTableViewModel viewModel;
    private AxisPixelProfileTableViewModel profileViewModel;
    private List<AxisPixelRowDataModel> values;

    private IPlottingSystem plottingSystem;

    private IROI roi;

    private int axisPrecision = 5;
    private int pixelPrecision = 0;

    private boolean isProfile = false;

    /**
     *
     * @param parent
     * @param plottingSystem
     */
    public AxisPixelROIEditTable(Composite parent, IPlottingSystem plottingSystem) {
        this.parent = parent;
        this.plottingSystem = plottingSystem;
    }

    /**
     * Method to create the Control
     */
    public void createControl() {
        // if we listen to the main plottingSystem
        if (!isProfile) {
            this.viewModel = new AxisPixelTableViewModel();
            final Table table = new Table(parent, SWT.FULL_SELECTION | SWT.SINGLE | SWT.V_SCROLL | SWT.BORDER);
            regionViewer = buildAndLayoutTable(table);
            regionViewer.setInput(viewModel.getValues());
        } else {
            this.profileViewModel = new AxisPixelProfileTableViewModel();
            final Table table = new Table(parent, SWT.FULL_SELECTION | SWT.SINGLE | SWT.V_SCROLL | SWT.BORDER);
            regionViewer = buildAndLayoutTable(table);
            regionViewer.setInput(profileViewModel.getValues());
        }
    }

    private TableViewer buildAndLayoutTable(final Table table) {

        TableViewer tableViewer = new TableViewer(table);
        tableViewer.setContentProvider(ArrayContentProvider.getInstance());
        table.setHeaderVisible(true);
        table.setLinesVisible(true);
        table.setLayoutData(new GridData(SWT.FILL, SWT.LEFT, true, false, 2, 2));

        TableViewerColumn viewerColumn = new TableViewerColumn(tableViewer, SWT.NONE, 0);
        viewerColumn.getColumn().setText("Name");
        viewerColumn.getColumn().setWidth(80);
        viewerColumn.setLabelProvider(new AxisPixelLabelProvider(0));
        RegionEditingSupport regionEditor = new RegionEditingSupport(tableViewer, 0);
        viewerColumn.setEditingSupport(regionEditor);

        viewerColumn = new TableViewerColumn(tableViewer, SWT.NONE, 1);
        viewerColumn.getColumn().setText("Start");
        viewerColumn.getColumn().setWidth(100);
        viewerColumn.setLabelProvider(new AxisPixelLabelProvider(1));
        regionEditor = new RegionEditingSupport(tableViewer, 1);
        viewerColumn.setEditingSupport(regionEditor);

        viewerColumn = new TableViewerColumn(tableViewer, SWT.NONE, 2);
        viewerColumn.getColumn().setText("End");
        viewerColumn.getColumn().setWidth(100);
        viewerColumn.setLabelProvider(new AxisPixelLabelProvider(2));
        regionEditor = new RegionEditingSupport(tableViewer, 2);
        viewerColumn.setEditingSupport(regionEditor);

        viewerColumn = new TableViewerColumn(tableViewer, SWT.NONE, 3);
        if (!isProfile)
            viewerColumn.getColumn().setText("Width(X), Height(Y)");
        else
            viewerColumn.getColumn().setText("Width");
        viewerColumn.getColumn().setWidth(100);
        viewerColumn.setLabelProvider(new AxisPixelLabelProvider(3));
        regionEditor = new RegionEditingSupport(tableViewer, 3);
        viewerColumn.setEditingSupport(regionEditor);

        return tableViewer;
    }

    /**
     * Table viewer label provider
     *
     */
    private class AxisPixelLabelProvider extends ColumnLabelProvider {

        private int column;

        public AxisPixelLabelProvider(int column) {
            this.column = column;
        }

        @Override
        public Image getImage(Object element) {
            return null;
        }

        @Override
        public String getText(Object element) {
            final AxisPixelRowDataModel model = (AxisPixelRowDataModel) element;
            DecimalFormat pointFormat = new DecimalFormat("##0.###");
            switch (column) {
            case 0:
                return model.getName();
            case 1:
                return pointFormat.format(model.getStart());
            case 2:
                return pointFormat.format(model.getEnd());
            case 3:
                return pointFormat.format(model.getDiff());
            default:
                return "";
            }
        }

        @Override
        public String getToolTipText(Object element) {
            return "";
        }

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

    /**
     * EditingSupport Class
     *
     */
    private class RegionEditingSupport extends EditingSupport {

        private int column;

        public RegionEditingSupport(ColumnViewer viewer, int col) {
            super(viewer);
            this.column = col;
        }

        @Override
        protected CellEditor getCellEditor(final Object element) {
            AxisPixelRowDataModel model = (AxisPixelRowDataModel) element;
            FieldComponentCellEditor ed = null;
            try {
                ed = new FieldComponentCellEditor(((TableViewer) getViewer()).getTable(),
                        FloatSpinnerWrapper.class.getName(), SWT.RIGHT);
            } catch (ClassNotFoundException e) {
                logger.error("Cannot get FieldComponentCellEditor for " + SpinnerWrapper.class.getName(), e);
                return null;
            }

            final FloatSpinnerWrapper rb = (FloatSpinnerWrapper) ed.getFieldWidget();

            if (model != null && model.name.endsWith("Pixel")) {
                if (rb.getPrecision() < 3)
                    rb.setFormat(rb.getWidth(), 0);
            }

            if (model != null && model.name.endsWith("Axis")) {
                if (rb.getPrecision() < 3)
                    rb.setFormat(rb.getWidth(), 3);
            }

            rb.setMaximum(Double.MAX_VALUE);
            rb.setMinimum(-Double.MAX_VALUE);

            rb.setButtonVisible(false);
            rb.setActive(true);

            ((Spinner) rb.getControl()).addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    try {
                        setValue(element, rb.getValue(), false);
                    } catch (Exception e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            });
            return ed;
        }

        @Override
        protected boolean canEdit(Object element) {
            if (column == 0)
                return false;
            else
                return true;
        }

        @Override
        protected Object getValue(Object element) {
            try {
                return getRowValue(element);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return null;
            }
        }

        private Object getRowValue(Object element) throws Exception {

            final AxisPixelRowDataModel row = (AxisPixelRowDataModel) element;
            switch (column) {
            case 0:
                return row.getName();
            case 1:
                return row.getStart();
            case 2:
                return row.getEnd();
            case 3:
                return row.getDiff();
            default:
                return null;
            }
        }

        @Override
        protected void setValue(Object element, Object value) {
            try {
                this.setValue(element, value, true);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        private void setValue(Object element, Object value, boolean tableRefresh) throws Exception {
            final AxisPixelRowDataModel row = (AxisPixelRowDataModel) element;

            switch (column) {
            case 0:
                row.setName((String) value);
                break;
            case 1:
                row.setStart((Double) value);
                row.setDiff(row.getEnd() - row.getStart());
                break;
            case 2:
                row.setEnd((Double) value);
                // set new diff
                row.setDiff(row.getEnd() - row.getStart());
                break;
            case 3:
                row.setDiff((Double) value);
                // set new end
                row.setEnd(row.getStart() + row.getDiff());
                break;
            default:
                break;
            }
            if (tableRefresh) {
                getViewer().refresh();
            }
            if (!isProfile)
                roi = createRoi(viewModel.getValues(), row.getName());
            else
                roi = createProfileRoi(profileViewModel.getValues());
            setTableValues(roi);
            // set new region
            IRegion region = plottingSystem.getRegions().iterator().next();
            region.setROI(roi);
        }
    }

    /**
     * Method that creates a ROI using the input of the table viewer
     * @param rows
     * @param rowName
     * @return IROI
     * @throws Exception
     */
    private IROI createRoi(List<AxisPixelRowDataModel> rows, String rowName) throws Exception {

        double ptx = 0, pty = 0, ptxEnd = 0, ptyEnd = 0, width = 0, height = 0, angle = 0, pixelPtx = 0,
                pixelPty = 0, pixelEndPtx = 0, pixelEndPty = 0;

        IROI ret = null;
        if (roi == null)
            roi = plottingSystem.getRegions().iterator().next().getROI();
        if (roi instanceof RectangularROI) {
            // if axis rows are being modified
            if (rowName.equals(RowName.XAXIS_ROW) || rowName.equals(RowName.YAXIS_ROW)) {
                AxisPixelRowDataModel xAxisRow = (AxisPixelRowDataModel) rows.get(0);
                AxisPixelRowDataModel yAxisRow = (AxisPixelRowDataModel) rows.get(1);
                //Convert from Axis to Pixel values
                // We get the axes data to convert from the axis to pixel values
                Collection<ITrace> traces = plottingSystem.getTraces();
                Iterator<ITrace> it = traces.iterator();
                while (it.hasNext()) {
                    ITrace trace = it.next();
                    if (trace instanceof IImageTrace) {
                        IImageTrace image = (IImageTrace) trace;
                        // x axis and width
                        ptx = xAxisRow.getStart();
                        pty = yAxisRow.getStart();
                        ptxEnd = xAxisRow.getEnd();
                        ptyEnd = yAxisRow.getEnd();
                        double[] newStartPoint = image.getPointInImageCoordinates(new double[] { ptx, pty });
                        pixelPtx = newStartPoint[0];
                        pixelPty = newStartPoint[1];
                        double[] newEndPoint = image.getPointInImageCoordinates(new double[] { ptxEnd, ptyEnd });
                        pixelEndPtx = newEndPoint[0];
                        pixelEndPty = newEndPoint[1];
                        width = pixelEndPtx - pixelPtx;
                        height = pixelEndPty - pixelPty;
                        ret = new RectangularROI(pixelPtx, pixelPty, width, height, angle);
                    }
                }
            }
            // if Pixel rows are being modified
            else if (rowName.equals(RowName.XPIXEL_ROW) || rowName.equals(RowName.YPIXEL_ROW)) {
                AxisPixelRowDataModel xPixelRow = (AxisPixelRowDataModel) rows.get(2);
                AxisPixelRowDataModel yPixelRow = (AxisPixelRowDataModel) rows.get(3);
                // x axis and width
                ptx = xPixelRow.getStart();
                pty = yPixelRow.getStart();
                ptxEnd = xPixelRow.getEnd();
                ptyEnd = yPixelRow.getEnd();
                width = ptxEnd - ptx;
                height = ptyEnd - pty;
                ret = new RectangularROI(ptx, pty, width, height, angle);
            }
        }
        return ret;
    }

    /**
     * Method that creates a ROI using the x row a profile table viewer
     * @param rows
     * @return IROI
     * @throws Exception
     */
    private IROI createProfileRoi(List<AxisPixelRowDataModel> rows) throws Exception {
        double ptx = 0, pty = 0, ptxEnd = 0, width = 0, height = 0, angle = 0;
        IROI ret = null;
        if (roi == null)
            roi = plottingSystem.getRegions().iterator().next().getROI();
        if (roi instanceof RectangularROI) {
            //Convert from Axis to Pixel values
            AxisPixelRowDataModel xAxisRow = (AxisPixelRowDataModel) rows.get(0);
            ptx = xAxisRow.getStart();
            ptxEnd = xAxisRow.getEnd();
            width = ptxEnd - ptx;
            pty = roi.getPointY();
            height = ((RectangularROI) roi).getEndPoint()[1] - pty;
            RectangularROI rr = new RectangularROI(ptx, pty, width, height, angle);
            ret = rr;
        }
        return ret;
    }

    /**
     * get point in axis coords
     * @param coords
     * @return
     */
    public double[] getAxisPoint(ICoordinateSystem coords, double... vals) {
        if (coords == null)
            return vals;
        try {
            return coords.getValueAxisLocation(vals);
        } catch (Exception e) {
            return vals;
        }
    }

    /**
     * get point in image coords
     * @param coords
     * @return
     */
    public double[] getImagePoint(ICoordinateSystem coords, double... vals) {
        if (coords == null)
            return vals;
        try {
            return coords.getAxisLocationValue(vals);
        } catch (Exception e) {
            return vals;
        }
    }

    public IStructuredSelection getSelection() {
        return (IStructuredSelection) regionViewer.getSelection();
    }

    public void setSelection(IStructuredSelection selection) {
        regionViewer.setSelection(selection, true);
    }

    /**
     * Method that returns the TableViewer
     * @return TableViewer
     */
    public TableViewer getTableViewer() {
        return regionViewer;
    }

    /**
     * Method used to set the {@link}AxisPixelROIEditTable<br>
     * to listen to the main plottingSystem or to a profile plottingSystems<br>
     * By default this class will create a table viewer used to listen to a<br>
     * main plottingSystem.
     *
     * @param isProfileTable
     */
    public void setIsProfileTable(boolean isProfileTable) {
        this.isProfile = isProfileTable;
    }

    /**
     * Method that sets the table viewer values given a Region of Interest
     * @param region
     */
    public void setTableValues(IROI region) {
        roi = region;
        if (!(roi instanceof RectangularROI))
            return;
        RectangularROI rroi = (RectangularROI) roi;
        if (roi == null)
            return;
        double xStart = roi.getPointX();
        double yStart = roi.getPointY();
        double xEnd = rroi.getEndPoint()[0];
        double yEnd = rroi.getEndPoint()[1];

        if (!isProfile) {
            values = viewModel.getValues();
            AxisPixelRowDataModel xAxisRow = (AxisPixelRowDataModel) values.get(0);
            AxisPixelRowDataModel yAxisRow = (AxisPixelRowDataModel) values.get(1);
            AxisPixelRowDataModel xPixelRow = (AxisPixelRowDataModel) values.get(2);
            AxisPixelRowDataModel yPixelRow = (AxisPixelRowDataModel) values.get(3);
            try {
                // We get the axes data to convert from the pixel to axis values
                IImageTrace image = null;
                ITrace trace = plottingSystem.getTraces().iterator().next();
                if (trace instanceof IImageTrace) {
                    image = (IImageTrace) trace;
                    double[] startPoint = image.getPointInAxisCoordinates(new double[] { xStart, yStart });
                    double[] endPoint = image.getPointInAxisCoordinates(new double[] { xEnd, yEnd });

                    xAxisRow.setStart(DoubleUtils.roundDouble(startPoint[0], axisPrecision));
                    xAxisRow.setEnd(DoubleUtils.roundDouble(endPoint[0], axisPrecision));
                    xAxisRow.setDiff(DoubleUtils.roundDouble(endPoint[0] - startPoint[0], axisPrecision));
                    yAxisRow.setStart(DoubleUtils.roundDouble(startPoint[1], axisPrecision));
                    yAxisRow.setEnd(DoubleUtils.roundDouble(endPoint[1], axisPrecision));
                    yAxisRow.setDiff(DoubleUtils.roundDouble(endPoint[1] - startPoint[1], axisPrecision));
                }

                xPixelRow.setStart(DoubleUtils.roundDouble(xStart, pixelPrecision));
                xPixelRow.setEnd(DoubleUtils.roundDouble(xEnd, pixelPrecision));
                xPixelRow.setDiff(DoubleUtils.roundDouble(xEnd - xStart, pixelPrecision));
                yPixelRow.setStart(DoubleUtils.roundDouble(yStart, pixelPrecision));
                yPixelRow.setEnd(DoubleUtils.roundDouble(yEnd, pixelPrecision));
                yPixelRow.setDiff(DoubleUtils.roundDouble(yEnd - yStart, pixelPrecision));
            } catch (ArrayIndexOutOfBoundsException ae) {
                // do nothing
            } catch (Exception e) {
                logger.debug("Error while updating the AxisPixelEditTable:" + e);
            }
        } else {
            values = profileViewModel.getValues();
            AxisPixelRowDataModel xAxisRow = (AxisPixelRowDataModel) values.get(0);
            xAxisRow.setStart(DoubleUtils.roundDouble(xStart, axisPrecision));
            xAxisRow.setEnd(DoubleUtils.roundDouble(xEnd, axisPrecision));
            xAxisRow.setDiff(DoubleUtils.roundDouble(xEnd - xStart, axisPrecision));
        }
        if (regionViewer.isCellEditorActive())
            return;
        regionViewer.refresh();
    }

    /**
     * Methods that returns the current ROI
     * @return ROIBase
     */
    public IROI getROI() {
        return roi;
    }

    public void setValues(List<AxisPixelRowDataModel> values) {
        this.values = values;
    }

    /**
     * Method to add a SelectionChangedListener to the TableViewer
     * @param listener
     */
    public void addSelectionChangedListener(ISelectionChangedListener listener) {
        regionViewer.addSelectionChangedListener(listener);
    }

    /**
     * Method to remove a SelectionChangedListener from the TableViewer
     * @param listener
     */
    public void removeSelectionChangedListener(ISelectionChangedListener listener) {
        regionViewer.removeSelectionChangedListener(listener);
    }

    private class RowName {
        public static final String XAXIS_ROW = "X Axis";
        public static final String YAXIS_ROW = "Y Axis";
        public static final String XPIXEL_ROW = "X Pixel";
        public static final String YPIXEL_ROW = "Y Pixel";
    }

    /**
     * View Model of  AxisPixel Table: main one
     *
     */
    private class AxisPixelTableViewModel {
        private List<AxisPixelRowDataModel> rows = new ArrayList<AxisPixelRowDataModel>();

        private AxisPixelRowDataModel xAxisRow;
        private AxisPixelRowDataModel yAxisRow;
        private AxisPixelRowDataModel xPixelRow;
        private AxisPixelRowDataModel yPixelRow;

        final private String description0 = "X-Axis values (Not yet editable)";
        final private String description1 = "Y-Axis values (Not yet editable)";
        final private String description2 = "X values as pixels (Editable)";
        final private String description3 = "X values as pixels (Editable)";

        {
            xAxisRow = new AxisPixelRowDataModel(new String(RowName.XAXIS_ROW), new Double(0), new Double(0),
                    new Double(0), description0);
            yAxisRow = new AxisPixelRowDataModel(new String(RowName.YAXIS_ROW), new Double(0), new Double(0),
                    new Double(0), description1);
            xPixelRow = new AxisPixelRowDataModel(new String(RowName.XPIXEL_ROW), new Double(0), new Double(0),
                    new Double(0), description2);
            yPixelRow = new AxisPixelRowDataModel(new String(RowName.YPIXEL_ROW), new Double(0), new Double(0),
                    new Double(0), description3);

            rows.add(xAxisRow);
            rows.add(yAxisRow);
            rows.add(xPixelRow);
            rows.add(yPixelRow);
        }

        public List<AxisPixelRowDataModel> getValues() {
            return rows;
        }
    }

    /**
     * View Model of  AxisPixel Table: profile one
     *
     */
    private class AxisPixelProfileTableViewModel {

        private List<AxisPixelRowDataModel> rows = new ArrayList<AxisPixelRowDataModel>();

        final private String description = "X-Axis values";
        private AxisPixelRowDataModel xAxisRow;

        {
            xAxisRow = new AxisPixelRowDataModel(new String(RowName.XAXIS_ROW), new Double(0), new Double(0),
                    new Double(0), description);
            rows.add(xAxisRow);
        }

        public List<AxisPixelRowDataModel> getValues() {
            return rows;
        }
    }

    /**
     * Model object for a Region Of Interest row used in an AxisPixel Table
     * @author wqk87977
     *
     */
    private class AxisPixelRowDataModel extends AbstractOperationModel {
        private String name;
        private double start;
        private double end;
        private double diff;
        private String description;

        public AxisPixelRowDataModel(String name, double start, double end, double diff, String description) {
            this.name = name;
            this.start = start;
            this.end = end;
            this.diff = diff;
            this.description = description;
        }

        public String getName() {
            return name;
        }

        public double getStart() {
            return start;
        }

        public double getEnd() {
            return end;
        }

        public double getDiff() {
            return diff;
        }

        @SuppressWarnings("unused")
        /**
         * TODO add a description in a tool tip<br>
         * but this can only be done by providing our own LabelProvider<br>
         * which is currently done by the ViewerSupport.bind mechanism.<br>
         *
         * @return string
         */
        public String getDescription() {
            return description;
        }

        public void setName(String name) {
            String oldValue = this.name;
            this.name = name;
            firePropertyChange("name", oldValue, this.name);
        }

        public void setStart(double start) {
            double oldValue = this.start;
            this.start = start;
            firePropertyChange("start", oldValue, this.start);
        }

        public void setEnd(double end) {
            double oldValue = this.end;
            this.end = end;
            firePropertyChange("end", oldValue, this.end);
        }

        public void setDiff(double diff) {
            double oldValue = this.diff;
            this.diff = diff;
            firePropertyChange("diff", oldValue, this.diff);
        }
    }

    public void cancelEditing() {
        regionViewer.cancelEditing();
    }
}