ummisco.gama.ui.views.displays.SWTChartEditor.java Source code

Java tutorial

Introduction

Here is the source code for ummisco.gama.ui.views.displays.SWTChartEditor.java

Source

/*********************************************************************************************
 *
 * 'SWTChartEditor.java, in plugin ummisco.gama.ui.experiment, is part of the source code of the GAMA modeling and
 * simulation platform. (c) 2007-2016 UMI 209 UMMISCO IRD/UPMC & Partners
 *
 * Visit https://github.com/gama-platform/gama for license information and developers contact.
 * 
 *
 **********************************************************************************************/

package ummisco.gama.ui.views.displays;

import java.awt.BasicStroke;
import java.awt.Paint;
import java.awt.Stroke;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Transform;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.ColorDialog;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FontDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.Axis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.editor.ChartEditor;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.title.TextTitle;
import org.jfree.chart.title.Title;

import ummisco.gama.ui.resources.GamaColors;
import ummisco.gama.ui.utils.GraphicsHelper;
import ummisco.gama.ui.utils.WorkbenchHelper;

/**
 * An editor for chart properties.
 */
public class SWTChartEditor implements ChartEditor {

    /** The shell */
    final Shell shell;

    /** The chart which the properties have to be edited */
    final JFreeChart chart;

    /** A composite for displaying/editing the properties of the title. */
    final SWTTitleEditor titleEditor;

    /** A composite for displaying/editing the properties of the plot. */
    final SWTPlotEditor plotEditor;

    /** A composite for displaying/editing the other properties of the chart. */
    final SWTOtherEditor otherEditor;

    /** The resourceBundle for the localization. */
    // protected static ResourceBundle localizationResources =
    // ResourceBundleWrapper
    // .getBundle("org.jfree.chart.editor.LocalizationBundle");

    /**
     * Creates a new editor.
     *
     * @param display
     *            the display.
     * @param chart2edit
     *            the chart to edit.
     */
    public SWTChartEditor(final Display display, final JFreeChart chart2edit, final Point position) {
        this.shell = new Shell(display, SWT.APPLICATION_MODAL | SWT.NO_TRIM);
        this.shell.setSize(400, 500);
        this.shell.setBackground(WorkbenchHelper.getDisplay().getSystemColor(SWT.COLOR_BLACK));
        // this.shell.setAlpha(140);
        this.chart = chart2edit;
        this.shell.setText("Chart properties");
        this.shell.setLocation(position);
        final GridLayout layout = new GridLayout(2, false);
        layout.marginLeft = layout.marginTop = layout.marginRight = layout.marginBottom = 5;
        this.shell.setLayout(layout);
        final Composite main = new Composite(this.shell, SWT.NONE);
        main.setLayout(new FillLayout());
        main.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));

        final TabFolder tab = new TabFolder(main, SWT.BORDER);
        // build first tab
        final TabItem item1 = new TabItem(tab, SWT.NONE);
        item1.setText(" " + "Title" + " ");
        this.titleEditor = new SWTTitleEditor(tab, SWT.NONE, this.chart.getTitle());
        item1.setControl(this.titleEditor);
        // build second tab
        final TabItem item2 = new TabItem(tab, SWT.NONE);
        item2.setText(" " + "Plot" + " ");
        this.plotEditor = new SWTPlotEditor(tab, SWT.NONE, this.chart.getPlot());
        item2.setControl(this.plotEditor);
        // build the third tab
        final TabItem item3 = new TabItem(tab, SWT.NONE);
        item3.setText(" " + "Other" + " ");
        this.otherEditor = new SWTOtherEditor(tab, SWT.NONE, this.chart);
        item3.setControl(this.otherEditor);

        // ok and cancel buttons
        final Button cancel = new Button(this.shell, SWT.PUSH);
        cancel.setText(" Cancel ");
        cancel.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false));
        cancel.pack();
        cancel.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(final SelectionEvent e) {
                SWTChartEditor.this.shell.dispose();
            }
        });
        final Button ok = new Button(this.shell, SWT.PUSH | SWT.OK);
        ok.setText(" Ok ");
        ok.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false));
        ok.pack();
        ok.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(final SelectionEvent e) {
                updateChart(SWTChartEditor.this.chart);
                SWTChartEditor.this.shell.dispose();
            }
        });

    }

    /**
     * Opens the editor.
     */
    public void open() {
        this.shell.open();
        this.shell.layout();
        while (!this.shell.isDisposed()) {
            if (!this.shell.getDisplay().readAndDispatch()) {
                this.shell.getDisplay().sleep();
            }
        }
    }

    /**
     * Updates the chart properties.
     *
     * @param chart
     *            the chart.
     */
    @Override
    public void updateChart(final JFreeChart chart) {
        this.titleEditor.setTitleProperties(chart);
        this.plotEditor.updatePlotProperties(chart.getPlot());
        this.otherEditor.updateChartProperties(chart);
    }

    class SWTTitleEditor extends Composite {

        /** Whether or not to display the title on the chart. */
        boolean showTitle;

        /** The checkbox to indicate whether or not to display the title. */
        final Button showTitleCheckBox;

        /** A field for displaying/editing the title text. */
        final Text titleField;

        /** The font used to draw the title. */
        FontData titleFont;

        /** A field for displaying a description of the title font. */
        final Text fontField;

        /** The button to use to select a new title font. */
        final Button selectFontButton;

        /** The paint (color) used to draw the title. */
        Color titleColor;

        /**
         * The button to use to select a new paint (color) to draw the title.
         */
        final Button selectColorButton;

        /** The resourceBundle for the localization. */
        // protected static ResourceBundle localizationResources =
        // ResourceBundleWrapper
        // .getBundle("org.jfree.chart.editor.LocalizationBundle");

        /** Font object used to handle a change of font. */
        Font font;

        /**
         * Standard constructor: builds a panel for displaying/editing the properties of the specified title.
         *
         * @param parent
         *            the parent.
         * @param style
         *            the style.
         * @param title
         *            the title, which should be changed.
         *
         */
        SWTTitleEditor(final Composite parent, final int style, final Title title) {
            super(parent, style);
            final FillLayout layout = new FillLayout();
            layout.marginHeight = layout.marginWidth = 4;
            setLayout(layout);

            final TextTitle t = title != null ? (TextTitle) title : new TextTitle("Title");
            this.showTitle = title != null;
            this.titleFont = GraphicsHelper.toSwtFontData(getDisplay(), t.getFont(), true);
            this.titleColor = GraphicsHelper.toSwtColor(getDisplay(), t.getPaint());

            final Group general = new Group(this, SWT.NONE);
            general.setLayout(new GridLayout(3, false));
            general.setText("General");
            // row 1
            final Label label = new Label(general, SWT.NONE);
            label.setText("Show Title");
            final GridData gridData = new GridData();
            gridData.horizontalSpan = 2;
            label.setLayoutData(gridData);
            this.showTitleCheckBox = new Button(general, SWT.CHECK);
            this.showTitleCheckBox.setSelection(this.showTitle);
            this.showTitleCheckBox.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
            this.showTitleCheckBox.addSelectionListener(new SelectionAdapter() {

                @Override
                public void widgetSelected(final SelectionEvent event) {
                    SWTTitleEditor.this.showTitle = SWTTitleEditor.this.showTitleCheckBox.getSelection();
                }
            });
            // row 2
            new Label(general, SWT.NONE).setText("Text");
            this.titleField = new Text(general, SWT.BORDER);
            this.titleField.setText(t.getText());
            this.titleField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
            new Label(general, SWT.NONE).setText("");
            // row 3
            new Label(general, SWT.NONE).setText("Font");
            this.fontField = new Text(general, SWT.BORDER);
            this.fontField.setText(this.titleFont.toString());
            this.fontField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
            this.selectFontButton = new Button(general, SWT.PUSH);
            this.selectFontButton.setText("Select...");
            this.selectFontButton.addSelectionListener(new SelectionAdapter() {

                @Override
                public void widgetSelected(final SelectionEvent event) {
                    // Create the font-change dialog
                    final FontDialog dlg = new FontDialog(getShell());
                    dlg.setText("Font_Selection");
                    dlg.setFontList(new FontData[] { SWTTitleEditor.this.titleFont });
                    if (dlg.open() != null) {
                        // Dispose of any fonts we have created
                        if (SWTTitleEditor.this.font != null) {
                            SWTTitleEditor.this.font.dispose();
                        }
                        // Create the new font and set it into the title
                        // label
                        SWTTitleEditor.this.font = new Font(getShell().getDisplay(), dlg.getFontList());
                        // titleField.setFont(font);
                        SWTTitleEditor.this.fontField.setText(SWTTitleEditor.this.font.getFontData()[0].toString());
                        SWTTitleEditor.this.titleFont = SWTTitleEditor.this.font.getFontData()[0];
                    }
                }
            });
            // row 4
            new Label(general, SWT.NONE).setText("Color");
            // Use a SwtPaintCanvas to show the color, note that we must set the
            // heightHint.
            final SWTPaintCanvas colorCanvas = new SWTPaintCanvas(general, SWT.NONE, this.titleColor);
            final GridData canvasGridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
            canvasGridData.heightHint = 20;
            colorCanvas.setLayoutData(canvasGridData);
            this.selectColorButton = new Button(general, SWT.PUSH);
            this.selectColorButton.setText("Select...");
            this.selectColorButton.addSelectionListener(new SelectionAdapter() {

                @Override
                public void widgetSelected(final SelectionEvent event) {
                    // Create the color-change dialog
                    final ColorDialog dlg = new ColorDialog(getShell());
                    dlg.setText("Title_Color");
                    dlg.setRGB(SWTTitleEditor.this.titleColor.getRGB());
                    final RGB rgb = dlg.open();
                    if (rgb != null) {
                        // create the new color and set it to the
                        // SwtPaintCanvas
                        SWTTitleEditor.this.titleColor = new Color(getDisplay(), rgb);
                        colorCanvas.setColor(SWTTitleEditor.this.titleColor);
                    }
                }
            });
        }

        /**
         * Returns the title text entered in the panel.
         *
         * @return The title text entered in the panel.
         */
        public String getTitleText() {
            return this.titleField.getText();
        }

        /**
         * Returns the font selected in the panel.
         *
         * @return The font selected in the panel.
         */
        public FontData getTitleFont() {
            return this.titleFont;
        }

        /**
         * Returns the font selected in the panel.
         *
         * @return The font selected in the panel.
         */
        public Color getTitleColor() {
            return this.titleColor;
        }

        /**
         * Sets the properties of the specified title to match the properties defined on this panel.
         *
         * @param chart
         *            the chart whose title is to be modified.
         */
        public void setTitleProperties(final JFreeChart chart) {
            if (this.showTitle) {
                TextTitle title = chart.getTitle();
                if (title == null) {
                    title = new TextTitle();
                    chart.setTitle(title);
                }
                title.setText(getTitleText());
                title.setFont(GraphicsHelper.toAwtFont(getDisplay(), getTitleFont(), true));
                title.setPaint(GamaColors.toAwtColor(getTitleColor()));
            } else {
                chart.setTitle((TextTitle) null);
            }
        }
    }

    class SWTPlotEditor extends Composite {

        /**
         * A panel used to display/edit the properties of the domain axis (if any).
         */
        private final SWTAxisEditor domainAxisPropertyPanel;

        /**
         * A panel used to display/edit the properties of the range axis (if any).
         */
        private final SWTAxisEditor rangeAxisPropertyPanel;

        private final SWTPlotAppearanceEditor plotAppearance;

        /** The resourceBundle for the localization. */
        // protected static ResourceBundle localizationResources =
        // ResourceBundleWrapper
        // .getBundle("org.jfree.chart.editor.LocalizationBundle");

        /**
         * Creates a new editor for the specified plot.
         *
         * @param parent
         *            the parent.
         * @param style
         *            the style.
         * @param plot
         *            the plot.
         */
        public SWTPlotEditor(final Composite parent, final int style, final Plot plot) {
            super(parent, style);
            final FillLayout layout = new FillLayout();
            layout.marginHeight = layout.marginWidth = 4;
            setLayout(layout);

            final Group plotType = new Group(this, SWT.NONE);
            final FillLayout plotTypeLayout = new FillLayout();
            plotTypeLayout.marginHeight = plotTypeLayout.marginWidth = 4;
            plotType.setLayout(plotTypeLayout);
            plotType.setText(plot.getPlotType() + ":");

            final TabFolder tabs = new TabFolder(plotType, SWT.NONE);

            // deal with domain axis
            final TabItem item1 = new TabItem(tabs, SWT.NONE);
            item1.setText("Domain Axis");
            Axis domainAxis = null;
            if (plot instanceof CategoryPlot) {
                domainAxis = ((CategoryPlot) plot).getDomainAxis();
            } else if (plot instanceof XYPlot) {
                domainAxis = ((XYPlot) plot).getDomainAxis();
            }
            this.domainAxisPropertyPanel = SWTAxisEditor.getInstance(tabs, SWT.NONE, domainAxis);
            item1.setControl(this.domainAxisPropertyPanel);

            // deal with range axis
            final TabItem item2 = new TabItem(tabs, SWT.NONE);
            item2.setText("Range Axis");
            Axis rangeAxis = null;
            if (plot instanceof CategoryPlot) {
                rangeAxis = ((CategoryPlot) plot).getRangeAxis();
            } else if (plot instanceof XYPlot) {
                rangeAxis = ((XYPlot) plot).getRangeAxis();
            }
            this.rangeAxisPropertyPanel = SWTAxisEditor.getInstance(tabs, SWT.NONE, rangeAxis);
            item2.setControl(this.rangeAxisPropertyPanel);

            // deal with plot appearance
            final TabItem item3 = new TabItem(tabs, SWT.NONE);
            item3.setText("Appearance");
            this.plotAppearance = new SWTPlotAppearanceEditor(tabs, SWT.NONE, plot);
            item3.setControl(this.plotAppearance);
        }

        /**
         * Returns the current outline stroke.
         *
         * @return The current outline stroke.
         */
        public Color getBackgroundPaint() {
            return this.plotAppearance.getBackGroundPaint();
        }

        /**
         * Returns the current outline stroke.
         *
         * @return The current outline stroke.
         */
        public Color getOutlinePaint() {
            return this.plotAppearance.getOutlinePaint();
        }

        /**
         * Returns the current outline stroke.
         *
         * @return The current outline stroke.
         */
        public Stroke getOutlineStroke() {
            return this.plotAppearance.getStroke();
        }

        /**
         * Updates the plot properties to match the properties defined on the panel.
         *
         * @param plot
         *            The plot.
         */
        public void updatePlotProperties(final Plot plot) {
            // set the plot properties...
            plot.setBackgroundPaint(GamaColors.toAwtColor(getBackgroundPaint()));
            plot.setOutlinePaint(GamaColors.toAwtColor(getOutlinePaint()));
            plot.setOutlineStroke(getOutlineStroke());

            // set the axis properties
            if (this.domainAxisPropertyPanel != null) {
                Axis domainAxis = null;
                if (plot instanceof CategoryPlot) {
                    final CategoryPlot p = (CategoryPlot) plot;
                    domainAxis = p.getDomainAxis();
                } else if (plot instanceof XYPlot) {
                    final XYPlot p = (XYPlot) plot;
                    domainAxis = p.getDomainAxis();
                }
                if (domainAxis != null) {
                    this.domainAxisPropertyPanel.setAxisProperties(domainAxis);
                }
            }
            if (this.rangeAxisPropertyPanel != null) {
                Axis rangeAxis = null;
                if (plot instanceof CategoryPlot) {
                    final CategoryPlot p = (CategoryPlot) plot;
                    rangeAxis = p.getRangeAxis();
                } else if (plot instanceof XYPlot) {
                    final XYPlot p = (XYPlot) plot;
                    rangeAxis = p.getRangeAxis();
                }
                if (rangeAxis != null) {
                    this.rangeAxisPropertyPanel.setAxisProperties(rangeAxis);
                }
            }
            if (this.plotAppearance.getPlotOrientation() != null) {
                if (plot instanceof CategoryPlot) {
                    final CategoryPlot p = (CategoryPlot) plot;
                    p.setOrientation(this.plotAppearance.getPlotOrientation());
                } else if (plot instanceof XYPlot) {
                    final XYPlot p = (XYPlot) plot;
                    p.setOrientation(this.plotAppearance.getPlotOrientation());
                }
            }
        }
    }

    class SWTOtherEditor extends Composite {

        /**
         * A checkbox indicating whether or not the chart is drawn with anti-aliasing.
         */
        final Button antialias;

        /** The chart background color. */
        final SWTPaintCanvas backgroundPaintCanvas;

        /** The resourceBundle for the localization. */
        // protected static ResourceBundle localizationResources =
        // ResourceBundleWrapper
        // .getBundle("org.jfree.chart.editor.LocalizationBundle");

        /**
         * Creates a new instance.
         *
         * @param parent
         *            the parent.
         * @param style
         *            the style.
         * @param chart
         *            the chart.
         */
        public SWTOtherEditor(final Composite parent, final int style, final JFreeChart chart) {
            super(parent, style);
            final FillLayout layout = new FillLayout();
            layout.marginHeight = layout.marginWidth = 4;
            setLayout(layout);

            final Group general = new Group(this, SWT.NONE);
            general.setLayout(new GridLayout(3, false));
            general.setText("General");

            // row 1: antialiasing
            this.antialias = new Button(general, SWT.CHECK);
            this.antialias.setText("Draw anti-aliased");
            this.antialias.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 3, 1));
            this.antialias.setSelection(chart.getAntiAlias());

            // row 2: background paint for the chart
            new Label(general, SWT.NONE).setText("Background paint");
            this.backgroundPaintCanvas = new SWTPaintCanvas(general, SWT.NONE,
                    GraphicsHelper.toSwtColor(getDisplay(), chart.getBackgroundPaint()));
            final GridData bgGridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
            bgGridData.heightHint = 20;
            this.backgroundPaintCanvas.setLayoutData(bgGridData);
            final Button selectBgPaint = new Button(general, SWT.PUSH);
            selectBgPaint.setText("Select...");
            selectBgPaint.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
            selectBgPaint.addSelectionListener(new SelectionAdapter() {

                @Override
                public void widgetSelected(final SelectionEvent event) {
                    final ColorDialog dlg = new ColorDialog(getShell());
                    dlg.setText("Background_paint");
                    dlg.setRGB(SWTOtherEditor.this.backgroundPaintCanvas.getColor().getRGB());
                    final RGB rgb = dlg.open();
                    if (rgb != null) {
                        SWTOtherEditor.this.backgroundPaintCanvas.setColor(new Color(getDisplay(), rgb));
                    }
                }
            });
        }

        /**
         * Updates the chart.
         *
         * @param chart
         *            the chart.
         */
        public void updateChartProperties(final JFreeChart chart) {
            chart.setAntiAlias(this.antialias.getSelection());
            chart.setBackgroundPaint(GamaColors.toAwtColor(this.backgroundPaintCanvas.getColor()));
        }

    }

    public static class SWTAxisEditor extends Composite {

        /** The axis label. */
        final Text label;

        /** The font used to draw the axis labels. */
        FontData labelFont;

        /** The paint (color) used to draw the axis labels. */
        Color labelPaintColor;

        /** The font used to draw the axis tick labels. */
        FontData tickLabelFont;

        /** The paint (color) used to draw the axis tick labels. */
        final Color tickLabelPaintColor;

        /** A field showing a description of the label font. */
        final Text labelFontField;

        /**
         * A field containing a description of the font for displaying tick labels on the axis.
         */
        final Text tickLabelFontField;

        /** The resourceBundle for the localization. */
        // protected static ResourceBundle localizationResources =
        // ResourceBundleWrapper
        // .getBundle("org.jfree.chart.editor.LocalizationBundle");

        /** Font object used to handle a change of font. */
        Font font;

        /** A flag that indicates whether or not the tick labels are visible. */
        final Button showTickLabelsCheckBox;

        /** A flag that indicates whether or not the tick marks are visible. */
        final Button showTickMarksCheckBox;

        /** A tabbed pane for... */
        final TabFolder otherTabs;

        /**
         * Standard constructor: builds a composite for displaying/editing the properties of the specified axis.
         *
         * @param parent
         *            The parent composite.
         * @param style
         *            The SWT style of the SwtAxisEditor.
         * @param axis
         *            the axis whose properties are to be displayed/edited in the composite.
         */
        public SWTAxisEditor(final Composite parent, final int style, final Axis axis) {
            super(parent, style);
            this.labelFont = GraphicsHelper.toSwtFontData(getDisplay(), axis.getLabelFont(), true);
            this.labelPaintColor = GraphicsHelper.toSwtColor(getDisplay(), axis.getLabelPaint());
            this.tickLabelFont = GraphicsHelper.toSwtFontData(getDisplay(), axis.getTickLabelFont(), true);
            this.tickLabelPaintColor = GraphicsHelper.toSwtColor(getDisplay(), axis.getTickLabelPaint());

            final FillLayout layout = new FillLayout(SWT.VERTICAL);
            layout.marginHeight = layout.marginWidth = 4;
            setLayout(layout);
            final Group general = new Group(this, SWT.NONE);
            general.setLayout(new GridLayout(3, false));
            general.setText("General");
            // row 1
            new Label(general, SWT.NONE).setText("Label");
            this.label = new Text(general, SWT.BORDER);
            if (axis.getLabel() != null) {
                this.label.setText(axis.getLabel());
            }
            this.label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
            new Label(general, SWT.NONE).setText(""); // empty cell
            // row 2
            new Label(general, SWT.NONE).setText("Font");
            this.labelFontField = new Text(general, SWT.BORDER);
            this.labelFontField.setText(this.labelFont.toString());
            this.labelFontField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
            final Button selectFontButton = new Button(general, SWT.PUSH);
            selectFontButton.setText("Select...");
            selectFontButton.addSelectionListener(new SelectionAdapter() {

                @Override
                public void widgetSelected(final SelectionEvent event) {
                    // Create the color-change dialog
                    final FontDialog dlg = new FontDialog(getShell());
                    dlg.setText("Font Selection");
                    dlg.setFontList(new FontData[] { SWTAxisEditor.this.labelFont });
                    if (dlg.open() != null) {
                        // Dispose of any fonts we have created
                        if (SWTAxisEditor.this.font != null) {
                            SWTAxisEditor.this.font.dispose();
                        }
                        // Create the new font and set it into the title
                        // label
                        SWTAxisEditor.this.font = new Font(getShell().getDisplay(), dlg.getFontList());
                        // label.setFont(font);
                        SWTAxisEditor.this.labelFontField
                                .setText(SWTAxisEditor.this.font.getFontData()[0].toString());
                        SWTAxisEditor.this.labelFont = SWTAxisEditor.this.font.getFontData()[0];
                    }
                }
            });
            // row 3
            new Label(general, SWT.NONE).setText("Paint");
            // Use a colored text field to show the color
            final SWTPaintCanvas colorCanvas = new SWTPaintCanvas(general, SWT.NONE, this.labelPaintColor);
            final GridData canvasGridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
            canvasGridData.heightHint = 20;
            colorCanvas.setLayoutData(canvasGridData);
            final Button selectColorButton = new Button(general, SWT.PUSH);
            selectColorButton.setText("Select...");
            selectColorButton.addSelectionListener(new SelectionAdapter() {

                @Override
                public void widgetSelected(final SelectionEvent event) {
                    // Create the color-change dialog
                    final ColorDialog dlg = new ColorDialog(getShell());
                    dlg.setText("Title_Color");
                    dlg.setRGB(SWTAxisEditor.this.labelPaintColor.getRGB());
                    final RGB rgb = dlg.open();
                    if (rgb != null) {
                        // create the new color and set it to the
                        // SwtPaintCanvas
                        SWTAxisEditor.this.labelPaintColor = new Color(getDisplay(), rgb);
                        colorCanvas.setColor(SWTAxisEditor.this.labelPaintColor);
                    }
                }
            });
            final Group other = new Group(this, SWT.NONE);
            final FillLayout tabLayout = new FillLayout();
            tabLayout.marginHeight = tabLayout.marginWidth = 4;
            other.setLayout(tabLayout);
            other.setText("Other");

            this.otherTabs = new TabFolder(other, SWT.NONE);
            final TabItem item1 = new TabItem(this.otherTabs, SWT.NONE);
            item1.setText(" " + "Ticks" + " ");
            final Composite ticks = new Composite(this.otherTabs, SWT.NONE);
            ticks.setLayout(new GridLayout(3, false));
            this.showTickLabelsCheckBox = new Button(ticks, SWT.CHECK);
            this.showTickLabelsCheckBox.setText("Show tick labels");
            this.showTickLabelsCheckBox.setSelection(axis.isTickLabelsVisible());
            this.showTickLabelsCheckBox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
            new Label(ticks, SWT.NONE).setText("Tick label font");
            this.tickLabelFontField = new Text(ticks, SWT.BORDER);
            this.tickLabelFontField.setText(this.tickLabelFont.toString());
            // tickLabelFontField.setFont(SwtUtils.toSwtFontData(getDisplay(),
            // axis.getTickLabelFont()));
            this.tickLabelFontField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
            final Button selectTickLabelFontButton = new Button(ticks, SWT.PUSH);
            selectTickLabelFontButton.setText("Select...");
            selectTickLabelFontButton.addSelectionListener(new SelectionAdapter() {

                @Override
                public void widgetSelected(final SelectionEvent event) {
                    // Create the font-change dialog
                    final FontDialog dlg = new FontDialog(getShell());
                    dlg.setText("Font Selection");
                    dlg.setFontList(new FontData[] { SWTAxisEditor.this.tickLabelFont });
                    if (dlg.open() != null) {
                        // Dispose of any fonts we have created
                        if (SWTAxisEditor.this.font != null) {
                            SWTAxisEditor.this.font.dispose();
                        }
                        // Create the new font and set it into the title
                        // label
                        SWTAxisEditor.this.font = new Font(getShell().getDisplay(), dlg.getFontList());
                        // tickLabelFontField.setFont(font);
                        SWTAxisEditor.this.tickLabelFontField
                                .setText(SWTAxisEditor.this.font.getFontData()[0].toString());
                        SWTAxisEditor.this.tickLabelFont = SWTAxisEditor.this.font.getFontData()[0];
                    }
                }
            });
            this.showTickMarksCheckBox = new Button(ticks, SWT.CHECK);
            this.showTickMarksCheckBox.setText("Show tick marks");
            this.showTickMarksCheckBox.setSelection(axis.isTickMarksVisible());
            this.showTickMarksCheckBox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
            item1.setControl(ticks);
        }

        /**
         * A static method that returns a panel that is appropriate for the axis type.
         *
         * @param parent
         *            the parent.
         * @param style
         *            the style.
         * @param axis
         *            the axis whose properties are to be displayed/edited in the composite.
         * @return A composite or <code>null</code< if axis is <code>null</code> .
         */
        public static SWTAxisEditor getInstance(final Composite parent, final int style, final Axis axis) {

            if (axis != null) {
                // return the appropriate axis editor
                if (axis instanceof NumberAxis) {
                    return new SWTNumberAxisEditor(parent, style, (NumberAxis) axis);
                } else {
                    return new SWTAxisEditor(parent, style, axis);
                }
            } else {
                return null;
            }
        }

        /**
         * Returns a reference to the tabbed composite.
         *
         * @return A reference to the tabbed composite.
         */
        public TabFolder getOtherTabs() {
            return this.otherTabs;
        }

        /**
         * Returns the current axis label.
         *
         * @return The current axis label.
         */
        public String getLabel() {
            return this.label.getText();
        }

        /**
         * Returns the current label font.
         *
         * @return The current label font.
         */
        public java.awt.Font getLabelFont() {
            return GraphicsHelper.toAwtFont(getDisplay(), this.labelFont, true);
        }

        /**
         * Returns the current label paint.
         *
         * @return The current label paint.
         */
        public Paint getTickLabelPaint() {
            return GamaColors.toAwtColor(this.tickLabelPaintColor);
        }

        /**
         * Returns the current label font.
         *
         * @return The current label font.
         */
        public java.awt.Font getTickLabelFont() {
            return GraphicsHelper.toAwtFont(getDisplay(), this.tickLabelFont, true);
        }

        /**
         * Returns the current label paint.
         *
         * @return The current label paint.
         */
        public Paint getLabelPaint() {
            return GamaColors.toAwtColor(this.labelPaintColor);
        }

        /**
         * Sets the properties of the specified axis to match the properties defined on this panel.
         *
         * @param axis
         *            the axis.
         */
        public void setAxisProperties(final Axis axis) {
            axis.setLabel(getLabel());
            axis.setLabelFont(getLabelFont());
            axis.setLabelPaint(getLabelPaint());
            axis.setTickMarksVisible(this.showTickMarksCheckBox.getSelection());
            axis.setTickLabelsVisible(this.showTickLabelsCheckBox.getSelection());
            axis.setTickLabelFont(getTickLabelFont());
            axis.setTickLabelPaint(getTickLabelPaint());
        }
    }

    public static class SWTPaintCanvas extends Canvas {

        private Color myColor;

        /**
         * Creates a new instance.
         *
         * @param parent
         *            the parent.
         * @param style
         *            the style.
         * @param color
         *            the color.
         */
        public SWTPaintCanvas(final Composite parent, final int style, final Color color) {
            this(parent, style);
            this.setColor(color);
        }

        /**
         * Creates a new instance.
         *
         * @param parent
         *            the parent.
         * @param style
         *            the style.
         */
        public SWTPaintCanvas(final Composite parent, final int style) {
            super(parent, style);
            addPaintListener(e -> {
                e.gc.setForeground(e.gc.getDevice().getSystemColor(SWT.COLOR_BLACK));
                e.gc.setBackground(SWTPaintCanvas.this.myColor);
                e.gc.fillRectangle(getClientArea());
                e.gc.drawRectangle(getClientArea().x, getClientArea().y, getClientArea().width - 1,
                        getClientArea().height - 1);
            });
        }

        /**
         * Sets the color.
         *
         * @param color
         *            the color.
         */
        public void setColor(final Color color) {
            if (this.myColor != null) {
                this.myColor.dispose();
            }
            // this.myColor = new Color(getDisplay(), color.getRGB());
            this.myColor = color;
        }

        /**
         * Returns the color.
         *
         * @return The color.
         */
        public Color getColor() {
            return this.myColor;
        }

        /**
         * Overridden to do nothing.
         *
         * @param c
         *            the color.
         */
        @Override
        public void setBackground(final Color c) {
            return;
        }

        /**
         * Overridden to do nothing.
         *
         * @param c
         *            the color.
         */
        @Override
        public void setForeground(final Color c) {
            return;
        }

        /**
         * Frees resources.
         */
        @Override
        public void dispose() {
            this.myColor.dispose();
        }
    }

    static class SWTPlotAppearanceEditor extends Composite {

        final Spinner selectStroke;

        /** The stroke (pen) used to draw the outline of the plot. */
        final SWTStrokeCanvas strokeCanvas;

        /** The paint (color) used to fill the background of the plot. */
        final SWTPaintCanvas backgroundPaintCanvas;

        /** The paint (color) used to draw the outline of the plot. */
        final SWTPaintCanvas outlinePaintCanvas;

        /** The orientation for the plot. */
        PlotOrientation plotOrientation;

        Combo orientation;

        /** Orientation constants. */
        final static String[] orientationNames = { "Vertical", "Horizontal" };
        final static int ORIENTATION_VERTICAL = 0;
        final static int ORIENTATION_HORIZONTAL = 1;

        /** The resourceBundle for the localization. */
        // protected static ResourceBundle localizationResources =
        // ResourceBundleWrapper
        // .getBundle("org.jfree.chart.editor.LocalizationBundle");

        SWTPlotAppearanceEditor(final Composite parent, final int style, final Plot plot) {
            super(parent, style);
            final FillLayout layout = new FillLayout();
            layout.marginHeight = layout.marginWidth = 4;
            setLayout(layout);

            final Group general = new Group(this, SWT.NONE);
            final GridLayout groupLayout = new GridLayout(3, false);
            groupLayout.marginHeight = groupLayout.marginWidth = 4;
            general.setLayout(groupLayout);
            general.setText("General");

            // row 1: stroke
            new Label(general, SWT.NONE).setText("Outline stroke");
            this.strokeCanvas = new SWTStrokeCanvas(general, SWT.NONE);
            this.strokeCanvas.setStroke(plot.getOutlineStroke());
            final GridData strokeGridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
            strokeGridData.heightHint = 20;
            this.strokeCanvas.setLayoutData(strokeGridData);
            this.selectStroke = new Spinner(general, SWT.BORDER);
            this.selectStroke.setMinimum(1);
            this.selectStroke.setMaximum(3);
            this.selectStroke.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
            this.selectStroke.addSelectionListener(new SelectionAdapter() {

                @Override
                public void widgetSelected(final SelectionEvent event) {
                    final int w = SWTPlotAppearanceEditor.this.selectStroke.getSelection();
                    if (w > 0) {
                        SWTPlotAppearanceEditor.this.strokeCanvas.setStroke(new BasicStroke(w));
                        SWTPlotAppearanceEditor.this.strokeCanvas.redraw();
                    }
                }
            });
            // row 2: outline color
            new Label(general, SWT.NONE).setText("Outline Paint");
            this.outlinePaintCanvas = new SWTPaintCanvas(general, SWT.NONE,
                    GraphicsHelper.toSwtColor(getDisplay(), plot.getOutlinePaint()));
            final GridData outlineGridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
            outlineGridData.heightHint = 20;
            this.outlinePaintCanvas.setLayoutData(outlineGridData);
            final Button selectOutlineColor = new Button(general, SWT.PUSH);
            selectOutlineColor.setText("Select...");
            selectOutlineColor.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
            selectOutlineColor.addSelectionListener(new SelectionAdapter() {

                @Override
                public void widgetSelected(final SelectionEvent event) {
                    final ColorDialog dlg = new ColorDialog(getShell());
                    dlg.setText("Outline Paint");
                    dlg.setRGB(SWTPlotAppearanceEditor.this.outlinePaintCanvas.getColor().getRGB());
                    final RGB rgb = dlg.open();
                    if (rgb != null) {
                        SWTPlotAppearanceEditor.this.outlinePaintCanvas.setColor(new Color(getDisplay(), rgb));
                    }
                }
            });
            // row 3: background paint
            new Label(general, SWT.NONE).setText("Background paint");
            this.backgroundPaintCanvas = new SWTPaintCanvas(general, SWT.NONE,
                    GraphicsHelper.toSwtColor(getDisplay(), plot.getBackgroundPaint()));
            final GridData bgGridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
            bgGridData.heightHint = 20;
            this.backgroundPaintCanvas.setLayoutData(bgGridData);
            final Button selectBgPaint = new Button(general, SWT.PUSH);
            selectBgPaint.setText("Select...");
            selectBgPaint.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
            selectBgPaint.addSelectionListener(new SelectionAdapter() {

                @Override
                public void widgetSelected(final SelectionEvent event) {
                    final ColorDialog dlg = new ColorDialog(getShell());
                    dlg.setText("Background paint");
                    dlg.setRGB(SWTPlotAppearanceEditor.this.backgroundPaintCanvas.getColor().getRGB());
                    final RGB rgb = dlg.open();
                    if (rgb != null) {
                        SWTPlotAppearanceEditor.this.backgroundPaintCanvas.setColor(new Color(getDisplay(), rgb));
                    }
                }
            });
            // row 4: orientation
            if (plot instanceof CategoryPlot) {
                this.plotOrientation = ((CategoryPlot) plot).getOrientation();
            } else if (plot instanceof XYPlot) {
                this.plotOrientation = ((XYPlot) plot).getOrientation();
            }
            if (this.plotOrientation != null) {
                final boolean isVertical = this.plotOrientation.equals(PlotOrientation.VERTICAL);
                final int index = isVertical ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL;
                new Label(general, SWT.NONE).setText("Orientation");
                this.orientation = new Combo(general, SWT.DROP_DOWN);
                this.orientation.setItems(orientationNames);
                this.orientation.select(index);
                this.orientation.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false, 2, 1));
                this.orientation.addSelectionListener(new SelectionAdapter() {

                    @Override
                    public void widgetSelected(final SelectionEvent event) {
                        switch (SWTPlotAppearanceEditor.this.orientation.getSelectionIndex()) {
                        case ORIENTATION_HORIZONTAL:
                            SWTPlotAppearanceEditor.this.plotOrientation = PlotOrientation.HORIZONTAL;
                            break;
                        default:
                            SWTPlotAppearanceEditor.this.plotOrientation = PlotOrientation.VERTICAL;
                        }
                    }
                });
            }
        }

        /**
         * Returns the plot orientation.
         *
         * @return The plot orientation.
         */
        public PlotOrientation getPlotOrientation() {
            return this.plotOrientation;
        }

        /**
         * Returns the background paint.
         *
         * @return The background paint.
         */
        public Color getBackGroundPaint() {
            return this.backgroundPaintCanvas.getColor();
        }

        /**
         * Returns the outline paint.
         *
         * @return The outline paint.
         */
        public Color getOutlinePaint() {
            return this.outlinePaintCanvas.getColor();
        }

        /**
         * Returns the stroke.
         *
         * @return The stroke.
         */
        public Stroke getStroke() {
            return this.strokeCanvas.getStroke();
        }
    }

    static class SWTNumberAxisEditor extends SWTAxisEditor implements FocusListener {

        /**
         * A flag that indicates whether or not the axis range is determined automatically.
         */
        private boolean autoRange;

        /** The lowest value in the axis range. */
        private double minimumValue;

        /** The highest value in the axis range. */
        private double maximumValue;

        /**
         * A checkbox that indicates whether or not the axis range is determined automatically.
         */
        private final Button autoRangeCheckBox;

        /** A text field for entering the minimum value in the axis range. */
        private final Text minimumRangeValue;

        /** A text field for entering the maximum value in the axis range. */
        private final Text maximumRangeValue;

        /**
         * Creates a new editor.
         *
         * @param parent
         *            the parent.
         * @param style
         *            the style.
         * @param axis
         *            the axis.
         */
        public SWTNumberAxisEditor(final Composite parent, final int style, final NumberAxis axis) {
            super(parent, style, axis);
            this.autoRange = axis.isAutoRange();
            this.minimumValue = axis.getLowerBound();
            this.maximumValue = axis.getUpperBound();

            final TabItem item2 = new TabItem(getOtherTabs(), SWT.NONE);
            item2.setText(" " + "Range" + " ");
            final Composite range = new Composite(getOtherTabs(), SWT.NONE);
            range.setLayout(new GridLayout(2, true));
            item2.setControl(range);

            this.autoRangeCheckBox = new Button(range, SWT.CHECK);
            this.autoRangeCheckBox.setText("Auto-adjust range");
            this.autoRangeCheckBox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
            this.autoRangeCheckBox.setSelection(this.autoRange);
            this.autoRangeCheckBox.addSelectionListener(new SelectionAdapter() {

                @Override
                public void widgetSelected(final SelectionEvent e) {
                    toggleAutoRange();
                }
            });
            new Label(range, SWT.NONE).setText("Minimum range value");
            this.minimumRangeValue = new Text(range, SWT.BORDER);
            this.minimumRangeValue.setText(String.valueOf(this.minimumValue));
            this.minimumRangeValue.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
            this.minimumRangeValue.setEnabled(!this.autoRange);
            // this.minimumRangeValue.addModifyListener(this);
            // this.minimumRangeValue.addVerifyListener(this);
            this.minimumRangeValue.addFocusListener(this);
            new Label(range, SWT.NONE).setText("Maximum range value");
            this.maximumRangeValue = new Text(range, SWT.BORDER);
            this.maximumRangeValue.setText(String.valueOf(this.maximumValue));
            this.maximumRangeValue.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
            this.maximumRangeValue.setEnabled(!this.autoRange);
            // this.maximumRangeValue.addModifyListener(this);
            // this.maximumRangeValue.addVerifyListener(this);
            this.maximumRangeValue.addFocusListener(this);
        }

        /**
         * Toggle the auto range setting.
         */
        public void toggleAutoRange() {
            this.autoRange = this.autoRangeCheckBox.getSelection();
            if (this.autoRange) {
                this.minimumRangeValue.setText(Double.toString(this.minimumValue));
                this.minimumRangeValue.setEnabled(false);
                this.maximumRangeValue.setText(Double.toString(this.maximumValue));
                this.maximumRangeValue.setEnabled(false);
            } else {
                this.minimumRangeValue.setEnabled(true);
                this.maximumRangeValue.setEnabled(true);
            }
        }

        /**
         * Revalidate the range minimum: it should be less than the current maximum.
         *
         * @param candidate
         *            the minimum value
         *
         * @return A boolean.
         */
        public boolean validateMinimum(final String candidate) {
            boolean valid = true;
            try {
                if (Double.parseDouble(candidate) >= this.maximumValue) {
                    valid = false;
                }
            } catch (final NumberFormatException e) {
                valid = false;
            }
            return valid;
        }

        /**
         * Revalidate the range maximum: it should be greater than the current minimum
         *
         * @param candidate
         *            the maximum value
         *
         * @return A boolean.
         */
        public boolean validateMaximum(final String candidate) {
            boolean valid = true;
            try {
                if (Double.parseDouble(candidate) <= this.minimumValue) {
                    valid = false;
                }
            } catch (final NumberFormatException e) {
                valid = false;
            }
            return valid;
        }

        /*
         * (non-Javadoc)
         *
         * @see org.eclipse.swt.events.FocusListener#focusGained( org.eclipse.swt.events.FocusEvent)
         */
        @Override
        public void focusGained(final FocusEvent e) {
            // don't need to do anything
        }

        /*
         * (non-Javadoc)
         *
         * @see org.eclipse.swt.events.FocusListener#focusLost( org.eclipse.swt.events.FocusEvent)
         */
        @Override
        public void focusLost(final FocusEvent e) {
            if (e.getSource() == this.minimumRangeValue) {
                // verify min value
                if (!validateMinimum(this.minimumRangeValue.getText())) {
                    this.minimumRangeValue.setText(String.valueOf(this.minimumValue));
                } else {
                    this.minimumValue = Double.parseDouble(this.minimumRangeValue.getText());
                }
            } else if (e.getSource() == this.maximumRangeValue) {
                // verify max value
                if (!validateMaximum(this.maximumRangeValue.getText())) {
                    this.maximumRangeValue.setText(String.valueOf(this.maximumValue));
                } else {
                    this.maximumValue = Double.parseDouble(this.maximumRangeValue.getText());
                }
            }
        }

        /**
         * Sets the properties of the specified axis to match the properties defined on this panel.
         *
         * @param axis
         *            the axis.
         */
        @Override
        public void setAxisProperties(final Axis axis) {
            super.setAxisProperties(axis);
            final NumberAxis numberAxis = (NumberAxis) axis;
            numberAxis.setAutoRange(this.autoRange);
            if (!this.autoRange) {
                numberAxis.setRange(this.minimumValue, this.maximumValue);
            }
        }
    }

    static class SWTStrokeCanvas extends Canvas {

        /**
         * Creates a new instance.
         *
         * @param parent
         *            the parent.
         * @param style
         *            the style.
         * @param image
         *            the image.
         */
        public SWTStrokeCanvas(final Composite parent, final int style, final Image image) {
            this(parent, style);
        }

        /**
         * Creates a new instance.
         *
         * @param parent
         *            the parent.
         * @param style
         *            the style.
         */
        public SWTStrokeCanvas(final Composite parent, final int style) {
            super(parent, style);
            addPaintListener(e -> {
                final BasicStroke stroke = getStroke();
                if (stroke != null) {
                    int x, y;
                    final Rectangle rect = getClientArea();
                    x = (rect.width - 100) / 2;
                    y = (rect.height - 16) / 2;
                    final Transform swtTransform = new Transform(e.gc.getDevice());
                    e.gc.getTransform(swtTransform);
                    swtTransform.translate(x, y);
                    e.gc.setTransform(swtTransform);
                    swtTransform.dispose();
                    e.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_BLACK));
                    e.gc.setLineWidth((int) stroke.getLineWidth());
                    e.gc.drawLine(10, 8, 90, 8);
                }
            });
        }

        /**
         * Sets the stroke.
         *
         * @param stroke
         *            the stroke.
         */
        public void setStroke(final Stroke stroke) {
            if (stroke instanceof BasicStroke) {
                setData(stroke);
            } else {
                throw new RuntimeException("Can only handle 'Basic Stroke' at present.");
            }
        }

        /**
         * Returns the stroke.
         *
         * @return The stroke.
         */
        public BasicStroke getStroke() {
            return (BasicStroke) this.getData();
        }

    }
}