net.refractions.udig.style.sld.editor.raster.ClassifyDialog.java Source code

Java tutorial

Introduction

Here is the source code for net.refractions.udig.style.sld.editor.raster.ClassifyDialog.java

Source

/*
 *    uDig - User Friendly Desktop Internet GIS client
 *    http://udig.refractions.net
 *    (C) 2011, Refractions Research Inc.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
 * License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
 */
package net.refractions.udig.style.sld.editor.raster;

import java.awt.Color;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import net.refractions.udig.style.sld.SLDPlugin;
import net.refractions.udig.style.sld.internal.Messages;

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.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
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.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.opengis.coverage.grid.GridCoverageReader;

/**
 * Classify dialog for classifying raster values
 * into different bins.
 * 
 * @author Emily
 *
 */
public class ClassifyDialog extends TitleAreaDialog {

    private static final String GENERATE_LABEL = Messages.ClassifyDialog_GenerateBreaksButtonText;

    private ComboViewer cmbClass;
    private ListViewer cmbRanges;
    private Text txtIgnore;
    private Text txtSampleSize;

    private Label lblOp;
    private Text txtOp;
    private Button btnCompute;
    private Button chSampleSize;
    private List<Double> breaks;
    private GridCoverageReader layer;

    private ClassifyFunction currentSelection = null;
    private Number currentOption = null;
    private String currentIgnore = null;
    private Long currentSampleSize = null;

    private double[] defaultNoData = null;

    /**
     * Supported classifications
     *
     */
    private enum ClassifyFunction {
        EQUAL_INTERNAL(Messages.ClassifyDialog_EqualIntervalLabel,
                Messages.ClassifyDialog_NumberofIntervalsLabel), DEFINED_INTERVAL(
                        Messages.ClassifyDialog_DefinedIntervalLabel,
                        Messages.ClassifyDialog_IntervalSizeLabel), QUANTILE(Messages.ClassifyDialog_QuantileLabel,
                                Messages.ClassifyDialog_NumberOfBinsLabel);
        String guiName;
        String opName;

        private ClassifyFunction(String guiName, String opName) {
            this.guiName = guiName;
            this.opName = opName;
        }
    }

    /**
     * Creates a new classify dialog
     * @param parentShell parent shell
     * @param layer layer to classify
     */
    public ClassifyDialog(Shell parentShell, GridCoverageReader layer, double[] noDataValues) {
        super(parentShell);
        this.layer = layer;
        this.defaultNoData = noDataValues;

    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.dialogs.Dialog#close()
     */
    public boolean close() {
        computeValuesJob.cancel();
        return super.close();
    }

    @Override
    protected Control createDialogArea(Composite parent) {
        breaks = new ArrayList<Double>();

        Composite main = new Composite((Composite) super.createDialogArea(parent), SWT.NONE);
        main.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        GridLayout gl = new GridLayout(2, false);
        gl.marginWidth = gl.marginHeight = 20;
        main.setLayout(gl);

        Label lbl = new Label(main, SWT.NONE);
        lbl.setText(Messages.ClassifyDialog_ClassificationFunctionLabel);

        cmbClass = new ComboViewer(main, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER);
        cmbClass.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        cmbClass.setContentProvider(ArrayContentProvider.getInstance());
        cmbClass.setLabelProvider(new LabelProvider() {
            public String getText(Object x) {
                if (x instanceof ClassifyFunction) {
                    return ((ClassifyFunction) x).guiName;
                }
                return super.getText(x);
            }
        });
        cmbClass.setInput(ClassifyFunction.values());
        cmbClass.getCombo().addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {

                lblOp.setText(getCurrentSelection().opName);
                lblOp.getParent().layout();
            }
        });

        lblOp = new Label(main, SWT.NONE);
        lblOp.setText(ClassifyFunction.EQUAL_INTERNAL.opName);

        txtOp = new Text(main, SWT.BORDER);
        txtOp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        txtOp.setText("10"); //$NON-NLS-1$

        Label lbl4 = new Label(main, SWT.NONE);
        lbl4.setText(Messages.ClassifyDialog_ValuesToIgnoreLabel + "*"); //$NON-NLS-1$

        txtIgnore = new Text(main, SWT.BORDER);
        txtIgnore.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        if (defaultNoData == null) {
            txtIgnore.setText(String.valueOf(IColorMapTypePanel.DEFAULT_NO_DATA));
        } else {
            StringBuilder sb = new StringBuilder();
            for (double d : defaultNoData) {
                sb.append(d);
                sb.append(","); //$NON-NLS-1$
            }
            //remove last ","
            if (sb.length() > 0) {
                sb.deleteCharAt(sb.length() - 1);
            }
            txtIgnore.setText(sb.toString());
        }

        Label lbls = new Label(main, SWT.NONE);
        lbls.setText(Messages.ClassifyDialog_LimitSizeLabel);
        lbls.setToolTipText(Messages.ClassifyDialog_LimitSizeTooltip);

        Composite compSample = new Composite(main, SWT.NONE);
        GridLayout gla = new GridLayout(2, false);
        gla.marginHeight = gla.marginWidth = 0;
        compSample.setLayout(gla);
        compSample.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

        chSampleSize = new Button(compSample, SWT.CHECK);
        chSampleSize.setSelection(false);
        chSampleSize.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                txtSampleSize.setEnabled(chSampleSize.getSelection());
            }

        });
        txtSampleSize = new Text(compSample, SWT.BORDER);
        txtSampleSize.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        txtSampleSize.setText("100000"); //$NON-NLS-1$
        txtSampleSize.setEnabled(false);

        btnCompute = new Button(main, SWT.PUSH);
        btnCompute.setText(GENERATE_LABEL);
        btnCompute.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, false, 2, 1));
        btnCompute.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                computeValues();
            }
        });

        Label lblSep = new Label(main, SWT.SEPARATOR | SWT.HORIZONTAL);
        lblSep.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));

        Label lblRange = new Label(main, SWT.NONE);
        lblRange.setText(Messages.ClassifyDialog_BreaksLabel);
        lblRange.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));

        cmbRanges = new ListViewer(main, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
        GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1);
        gd.widthHint = 150;
        gd.heightHint = 200;
        cmbRanges.getControl().setLayoutData(gd);
        cmbRanges.setLabelProvider(new LabelProvider());
        cmbRanges.setContentProvider(ArrayContentProvider.getInstance());
        cmbRanges.setInput(breaks);

        Label lbl3 = new Label(main, SWT.WRAP);
        lbl3.setText("*" + Messages.ClassifyDialog_IgnoreValuesInfo); //$NON-NLS-1$
        lbl3.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));

        cmbClass.setSelection(new StructuredSelection(ClassifyFunction.EQUAL_INTERNAL));

        setMessage(Messages.ClassifyDialog_DialogMessage);
        setTitle(Messages.ClassifyDialog_DialogTitle);
        getShell().setText(Messages.ClassifyDialog_ShellTitle);
        return main;
    }

    /**
     * 
     * @return current selected classification function
     */
    private ClassifyFunction getCurrentSelection() {
        return (ClassifyFunction) ((IStructuredSelection) cmbClass.getSelection()).getFirstElement();
    }

    /*
     * computes the breaks
     */
    private void computeValues() {
        computeValuesJob.cancel();
        currentIgnore = txtIgnore.getText();
        currentSelection = getCurrentSelection();
        currentSampleSize = null;
        if (chSampleSize.getSelection()) {
            try {
                currentSampleSize = Long.parseLong(txtSampleSize.getText());
            } catch (Exception ex) {
                MessageDialog.openError(getShell(), Messages.ClassifyDialog_ErrorDialogTitle,
                        Messages.ClassifyDialog_ErrorMessage);
                return;
            }
        }

        if (currentSelection == ClassifyFunction.EQUAL_INTERNAL || currentSelection == ClassifyFunction.QUANTILE) {
            try {
                currentOption = Integer.parseInt(txtOp.getText());
            } catch (Exception ex) {
                MessageDialog.openError(getShell(), Messages.ClassifyDialog_ErrorDialogTitle, MessageFormat.format(
                        Messages.ClassifyDialog_InvalidValueOption, new Object[] { currentSelection.opName }));
                return;
            }
            if (currentOption.intValue() >= SingleBandEditorPage.MAX_ENTRIES) {
                MessageDialog.openError(getShell(), Messages.ClassifyDialog_ErrorDialogTitle,
                        MessageFormat.format(Messages.ClassifyDialog_MaxValueError,
                                new Object[] { SingleBandEditorPage.MAX_ENTRIES - 1 }));
                return;
            }

        } else if (currentSelection == ClassifyFunction.DEFINED_INTERVAL) {
            try {
                currentOption = Double.parseDouble(txtOp.getText());
            } catch (Exception ex) {
                MessageDialog.openError(getShell(), Messages.ClassifyDialog_ErrorDialogTitle3, MessageFormat.format(
                        Messages.ClassifyDialog_InvalidValueOption2, new Object[] { currentSelection.opName }));
            }

        }
        if (currentOption.doubleValue() <= 0) {
            MessageDialog.openError(getShell(), Messages.ClassifyDialog_ErrorDialogTitle3, MessageFormat
                    .format(Messages.ClassifyDialog_InvalidValue, new Object[] { currentSelection.opName }));
        }
        computeValuesJob.schedule();
    }

    @Override
    protected boolean isResizable() {
        return true;
    }

    /**
     * Updates the given panel with the new breaks.
     * 
     * @param panel must be IntervalValuesPanel or RampValuesPanel
     */
    public void updatePanel(IColorMapTypePanel panel) {
        if (panel instanceof IntervalValuesPanel || panel instanceof RampValuesPanel) {
            List<ColorEntry> entries = new ArrayList<ColorEntry>();
            for (Double d : breaks) {
                ColorEntry ce = new ColorEntry(Color.BLACK, 1, d, ""); //$NON-NLS-1$
                entries.add(ce);
            }

            if (panel instanceof IntervalValuesPanel) {
                ((IntervalValuesPanel) panel).setBreaks(entries);
            } else if (panel instanceof RampValuesPanel) {
                ((RampValuesPanel) panel).setBreaks(entries);
            }
        }
    }

    /*
     * Job for computing breaks
     */
    private Job computeValuesJob = new Job(Messages.ClassifyDialog_ComputeBreaksJobName) {

        @Override
        protected IStatus run(IProgressMonitor monitor) {
            ClassifyFunction function = currentSelection;
            Number op = currentOption;

            Long sampleSize = currentSampleSize;
            String ignore = currentIgnore;

            List<Double> toIgnore = new ArrayList<Double>();
            if (ignore.trim().length() > 0) {
                String[] str = ignore.split(","); //$NON-NLS-1$
                for (int i = 0; i < str.length; i++) {
                    try {
                        Double d = Double.parseDouble(str[i]);
                        toIgnore.add(d);
                    } catch (Exception ex) {
                        //eatme
                    }
                }
            }
            double[] valuesToIgnore = new double[toIgnore.size()];
            for (int i = 0; i < toIgnore.size(); i++) {
                valuesToIgnore[i] = toIgnore.get(i);
            }

            breaks.clear();
            final ClassificationEngine engine = new ClassificationEngine();
            if (function == null || op == null) {
                return Status.CANCEL_STATUS;
            }
            try {
                Display.getDefault().syncExec(new Runnable() {
                    @Override
                    public void run() {
                        cmbRanges.refresh();
                        btnCompute.setEnabled(false);
                    }
                });

                List<Double> newBreaks = null;
                if (function == ClassifyFunction.EQUAL_INTERNAL) {
                    newBreaks = engine.computeEqualInterval(((Integer) op).intValue(), valuesToIgnore, layer,
                            sampleSize);
                } else if (function == ClassifyFunction.DEFINED_INTERVAL) {
                    newBreaks = engine.computeDefinedInterval(((Double) op).doubleValue(), valuesToIgnore, layer,
                            sampleSize);
                } else if (function == ClassifyFunction.QUANTILE) {
                    newBreaks = engine.computeQuantile(((Integer) op).intValue(), valuesToIgnore, layer, sampleSize,
                            monitor);
                }

                if (newBreaks == null || monitor.isCanceled()) {
                    return Status.CANCEL_STATUS;
                } else {
                    breaks.clear();
                    breaks.addAll(newBreaks);
                }
            } catch (final Exception ex) {
                Display.getDefault().syncExec(new Runnable() {
                    @Override
                    public void run() {
                        MessageDialog.openError(getShell(), Messages.ClassifyDialog_ErrorDialogTitle5,
                                MessageFormat.format(Messages.ClassifyDialog_ErrorComputingValues,
                                        new Object[] { ex.getLocalizedMessage() }));
                    }
                });
                SLDPlugin.log("Error classifying values", ex); //$NON-NLS-1$
            } finally {
                Display.getDefault().syncExec(new Runnable() {
                    @Override
                    public void run() {
                        if (!cmbRanges.getControl().isDisposed()) {
                            setErrorMessage(engine.getLastErrorMessage());
                            cmbRanges.refresh();
                            btnCompute.setEnabled(true);
                        }
                    }
                });

            }
            return Status.OK_STATUS;
        }

    };
}