org.geopublishing.atlasViewer.swing.AtlasChartJPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.geopublishing.atlasViewer.swing.AtlasChartJPanel.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Stefan A. Tzeggai.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Stefan A. Tzeggai - initial API and implementation
 ******************************************************************************/
package org.geopublishing.atlasViewer.swing;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;

import org.apache.log4j.Logger;
import org.geopublishing.atlasViewer.AtlasConfig;
import org.geopublishing.atlasViewer.GpCoreUtil;
import org.geotools.feature.FeatureCollection;
import org.geotools.filter.identity.FeatureIdImpl;
import org.jfree.chart.JFreeChart;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.identity.Identifier;

import de.schmitzm.geotools.feature.FeatureUtil;
import de.schmitzm.geotools.gui.GeotoolsGUIUtil;
import de.schmitzm.geotools.gui.MapPaneToolBar;
import de.schmitzm.geotools.gui.MapView;
import de.schmitzm.geotools.gui.SelectableXMapPane;
import de.schmitzm.geotools.selection.ChartSelectionSynchronizer;
import de.schmitzm.geotools.selection.StyledFeatureLayerSelectionModel;
import de.schmitzm.geotools.selection.StyledLayerSelectionModel;
import de.schmitzm.geotools.selection.StyledLayerSelectionModelSynchronizer;
import de.schmitzm.geotools.styling.StyledFeaturesInterface;
import de.schmitzm.jfree.chart.SelectableChartPanel;
import de.schmitzm.jfree.chart.SelectableChartPanel.WindowSelectionMode;
import de.schmitzm.jfree.chart.selection.DatasetSelectionChangeEvent;
import de.schmitzm.jfree.chart.selection.DatasetSelectionListener;
import de.schmitzm.jfree.feature.FeatureChartPanel;
import de.schmitzm.jfree.feature.FeatureDatasetSelectionModel;
import de.schmitzm.jfree.feature.style.FeatureChartUtil;
import de.schmitzm.swing.Disposable;
import de.schmitzm.swing.ExceptionDialog;
import de.schmitzm.swing.SmallButton;
import de.schmitzm.swing.SmallToggleButton;

/**
 * Provides a JPanel that show charts. This static class manages all instances
 * of the dialogs. ChartJDialogs can only be created via
 * {@link #getInstanceFor(Component, AtlasChart, MapLegend)} which uses a cache
 * to return any an dialog if it exists.
 */
public class AtlasChartJPanel extends JPanel implements DatasetSelectionListener, Disposable {
    static final Logger LOGGER = Logger.getLogger(AtlasChartJPanel.class);

    /**
     * A reference to the {@link JFreeChart} that is passed on to the
     * {@link SelectableChartPanel}
     */
    private JFreeChart chart;

    static final ImageIcon ICON_SELECTION_ADD = new ImageIcon(
            MapView.class.getResource("resource/icons/selection_add.png"));

    static final ImageIcon ICON_SELECTION_CLEAR = new ImageIcon(
            MapView.class.getResource("resource/icons/selection_clear.png"));

    static final ImageIcon ICON_SELECTION_REMOVE = new ImageIcon(
            MapView.class.getResource("resource/icons/selection_remove.png"));

    static final ImageIcon ICON_SELECTION_SET = new ImageIcon(
            MapView.class.getResource("resource/icons/selection_set.png"));

    static final ImageIcon ICON_ZOOM = new ImageIcon(MapView.class.getResource("resource/icons/zoom_in.png"));

    static final ImageIcon ICON_FULL_EXTEND = new ImageIcon(
            MapView.class.getResource("resource/icons/zoom_full_extend.png"));

    private MapLegend mapLegend;

    /** A chart panel that **/
    private SelectableChartPanel selectableChartPanel;

    private StyledLayerSelectionModel<?> selectionModel;
    private final StyledFeaturesInterface<?> styledLayer;
    private JToolBar toolBar;

    private BufferedImage mapImageIcon;

    /** Keeps references to the listener for WeakHashSet **/
    private Set<DatasetSelectionListener> insertedListeners = new HashSet<DatasetSelectionListener>();

    /**
     * Instantiates am {@link AtlasChartJPanel} and sets the mouse selection
     * mode to WindowSelectionMode.SELECT_SET
     */
    public AtlasChartJPanel(JFreeChart chart, StyledFeaturesInterface<?> styledLayer, AtlasMapLegend mapLegend) {

        this.chart = chart;
        this.styledLayer = styledLayer;
        this.mapLegend = mapLegend;
        // TODO react to filter changes?! or what!?
        // mapLegend.getGeoMapPane().getMapPane().addMapPaneListener(
        // new JMapPaneListener() {
        //
        // @Override
        // public void performMapPaneEvent(JMapPaneEvent e) {
        // }
        //
        // });

        // **********************************************************************
        // If we find a mapIcon we will set it to be always rendered into the
        // map
        // **********************************************************************
        final URL mapIconURL = mapLegend.getMap().getAc().getResLoMan()
                .getResourceAsUrl(AtlasConfig.MAPLOGO_RESOURCE_NAME);
        if (mapIconURL != null) {
            try {
                mapImageIcon = ImageIO.read(mapIconURL);
            } catch (IOException e) {
                LOGGER.error(e);
            }

        } else {
            //         LOGGER.info("No " + AtlasConfig.MAPICON_RESOURCE_NAME
            //               + " found. Not displaying any icon on top of the chart");
        }

        initGUI();

    }

    /**
     * Returns a cached {@link SelectableChartPanel} - usually a
     * {@link FeatureChartPanel} - that has been constructed abound the original
     * {@link JFreeChart} chart. The anonymous extension of
     * {@link SelectableChartPanel} adds map-icon rendering to the chart.
     * 
     * @return
     */
    public SelectableChartPanel getSelectableChartPanel() {
        if (selectableChartPanel == null) {
            selectableChartPanel = new FeatureChartPanel(chart) {
                @Override
                public void paint(Graphics g) {
                    super.paint(g);

                    if (mapImageIcon != null) {
                        g.drawImage(mapImageIcon,
                                (int) (selectableChartPanel.getBounds().getWidth() - mapImageIcon.getWidth() - 10),
                                (int) (selectableChartPanel.getBounds().getHeight() - mapImageIcon.getHeight()
                                        - 10),
                                null);

                    }

                }

                @Override
                public void print(Graphics g) {
                    super.print(g);

                    if (mapImageIcon != null) {
                        g.drawImage(mapImageIcon,
                                (int) (selectableChartPanel.getBounds().getWidth() - mapImageIcon.getWidth() - 10),
                                (int) (selectableChartPanel.getBounds().getHeight() - mapImageIcon.getHeight()
                                        - 10),
                                null);

                    }
                }
            };
        }
        return selectableChartPanel;
    }

    /**
     * Returns the {@link JFreeChart} that is visualized in the
     * {@link SelectableChartPanel}
     */
    public JFreeChart getChart() {
        return getSelectableChartPanel().getChart();
    }

    /**
     * Returns the {@link JFreeChart} that is visualized in the
     * {@link SelectableChartPanel}
     */
    public void setChart(JFreeChart newChart) {
        this.chart = newChart;
        getSelectableChartPanel().setChart(chart);
    }

    protected StyledLayerSelectionModel<?> getSelectionModel() {
        if (selectionModel == null) {
            selectionModel = mapLegend != null ? mapLegend.getRememberSelection(styledLayer.getId()) : null;

            if ((selectionModel != null && selectionModel instanceof StyledFeatureLayerSelectionModel)) {
                StyledFeatureLayerSelectionModel featureSelectionModel = (StyledFeatureLayerSelectionModel) selectionModel;

                // get the selectionmodel(s) of the chart
                List<FeatureDatasetSelectionModel<?, ?, ?>> datasetSelectionModelFor = FeatureChartUtil
                        .getFeatureDatasetSelectionModelFor(getSelectableChartPanel().getChart());

                for (FeatureDatasetSelectionModel dsm : datasetSelectionModelFor) {

                    // create a synchronizer
                    ChartSelectionSynchronizer synchronizer = new ChartSelectionSynchronizer(featureSelectionModel,
                            dsm);

                    featureSelectionModel
                            .addSelectionListener((StyledLayerSelectionModelSynchronizer) synchronizer);
                    dsm.addSelectionListener(synchronizer);

                    featureSelectionModel.refreshSelection();
                }
            }

        }
        return selectionModel;
    }

    /**
     * Creates a {@link JToolBar} that has buttons to interact with the Chart
     * and it's SelectionModel.
     * 
     * @return
     */
    public JToolBar getToolBar() {
        if (toolBar == null) {

            toolBar = new JToolBar();
            toolBar.setFloatable(false);

            ButtonGroup bg = new ButtonGroup();

            /**
             * Add an Action to ZOOM/MOVE in the chart
             */
            JToggleButton zoomToolButton = new SmallToggleButton(new AbstractAction("", ICON_ZOOM) {

                @Override
                public void actionPerformed(ActionEvent e) {
                    getSelectableChartPanel().setWindowSelectionMode(WindowSelectionMode.ZOOM_IN_CHART);
                }

            }, GpCoreUtil.R("AtlasChartJPanel.zoom.tt"));
            toolBar.add(zoomToolButton);
            bg.add(zoomToolButton);

            toolBar.addSeparator();

            /**
             * Add an Action not change the selection but just move through the
             * chart
             */
            JToggleButton setSelectionButton = new SmallToggleButton(new AbstractAction("", ICON_SELECTION_SET) {

                @Override
                public void actionPerformed(ActionEvent e) {
                    getSelectableChartPanel().setWindowSelectionMode(WindowSelectionMode.SELECT_SET);
                }

            });
            setSelectionButton.setToolTipText(MapPaneToolBar.R("MapPaneButtons.Selection.SetSelection.TT"));
            toolBar.add(setSelectionButton);
            bg.add(setSelectionButton);

            /**
             * Add an Action to ADD the selection.
             */
            JToggleButton addSelectionButton = new SmallToggleButton(new AbstractAction("", ICON_SELECTION_ADD) {

                @Override
                public void actionPerformed(ActionEvent e) {
                    getSelectableChartPanel().setWindowSelectionMode(WindowSelectionMode.SELECT_ADD);
                }

            });
            addSelectionButton.setToolTipText(MapPaneToolBar.R("MapPaneButtons.Selection.AddSelection.TT"));
            toolBar.add(addSelectionButton);
            bg.add(addSelectionButton);

            /**
             * Add an Action to REMOVE the selection.
             */
            JToggleButton removeSelectionButton = new SmallToggleButton(
                    new AbstractAction("", ICON_SELECTION_REMOVE) {

                        @Override
                        public void actionPerformed(ActionEvent e) {
                            getSelectableChartPanel().setWindowSelectionMode(WindowSelectionMode.SELECT_REMOVE);
                        }

                    });
            removeSelectionButton.setToolTipText(MapPaneToolBar.R("MapPaneButtons.Selection.RemoveSelection.TT"));
            toolBar.add(removeSelectionButton);
            bg.add(removeSelectionButton);

            toolBar.addSeparator();

            /**
             * Add a normal Button to clear the selection. The Chart's selection
             * models are cleared. If a relation to a JMapPane exists, they will
             * be synchronized.
             */
            final SmallButton clearSelectionButton = new SmallButton(new AbstractAction("", ICON_SELECTION_CLEAR) {

                @Override
                public void actionPerformed(ActionEvent e) {
                    // getSelectionModel().clearSelection();

                    // get the selectionmodel(s) of the chart
                    List<FeatureDatasetSelectionModel<?, ?, ?>> datasetSelectionModelFor = FeatureChartUtil
                            .getFeatureDatasetSelectionModelFor(getSelectableChartPanel().getChart());

                    for (FeatureDatasetSelectionModel dsm : datasetSelectionModelFor) {
                        dsm.clearSelection();
                    }

                }

            }, MapPaneToolBar.R("MapPaneButtons.Selection.ClearSelection.TT"));

            {
                // Add listeners to the selection model, so we knwo when to
                // disable/enable the button

                // get the selectionmodel(s) of the chart
                List<FeatureDatasetSelectionModel<?, ?, ?>> datasetSelectionModelFor = FeatureChartUtil
                        .getFeatureDatasetSelectionModelFor(getSelectableChartPanel().getChart());
                for (final FeatureDatasetSelectionModel selModel : datasetSelectionModelFor) {
                    DatasetSelectionListener listener_ClearSelectionButtonEnbled = new DatasetSelectionListener() {

                        @Override
                        public void selectionChanged(DatasetSelectionChangeEvent e) {
                            if (!e.getSource().getValueIsAdjusting()) {

                                // Update the clearSelectionButton
                                clearSelectionButton.setEnabled(selModel.getSelectedFeatures().size() > 0);
                            }
                        }
                    };
                    insertedListeners.add(listener_ClearSelectionButtonEnbled);
                    selModel.addSelectionListener(listener_ClearSelectionButtonEnbled);

                    clearSelectionButton.setEnabled(selModel.getSelectedFeatures().size() > 0);
                }
            }

            toolBar.add(clearSelectionButton);

            toolBar.addSeparator();

            /**
             * Add a normal Button which opens the Chart'S print dialog
             */
            SmallButton printChartButton = new SmallButton(new AbstractAction("", Icons.ICON_PRINT_24) {

                @Override
                public void actionPerformed(ActionEvent e) {

                    getSelectableChartPanel().createChartPrintJob();

                }

            });
            printChartButton.setToolTipText(GpCoreUtil.R("AtlasChartJPanel.PrintChartButton.TT"));
            toolBar.add(printChartButton);

            /**
             * Add a normal Button which opens the Chart's export/save dialog
             */
            SmallButton saveChartAction = new SmallButton(new AbstractAction("", Icons.ICON_SAVEAS_24) {

                @Override
                public void actionPerformed(ActionEvent e) {

                    try {
                        getSelectableChartPanel().doSaveAs();
                    } catch (IOException e1) {
                        LOGGER.info("Saving a chart to file failed", e1);
                        ExceptionDialog.show(AtlasChartJPanel.this, e1);
                    }

                }

            });
            saveChartAction.setToolTipText(GpCoreUtil.R("AtlasChartJPanel.SaveChartButton.TT"));
            toolBar.add(saveChartAction);

            //
            // A JButton to open the attribute table
            //
            {
                final JButton openTable = new JButton();
                openTable.setAction(new AbstractAction(GpCoreUtil.R("LayerToolMenu.table"), Icons.ICON_TABLE) {

                    @Override
                    public void actionPerformed(final ActionEvent e) {
                        AVDialogManager.dm_AttributeTable.getInstanceFor(styledLayer, AtlasChartJPanel.this,
                                styledLayer, mapLegend);
                    }
                });
                toolBar.addSeparator();
                toolBar.add(openTable);
            }

            /*
             * Select/set data points button is activated by default
             */
            getSelectableChartPanel().setWindowSelectionMode(WindowSelectionMode.SELECT_SET);
            setSelectionButton.setSelected(true);

        }
        return toolBar;
    }

    /**
     * Create the simple GUI - buttons to the top, the chart into the center.
     */
    private void initGUI() {
        setLayout(new BorderLayout());

        add(getToolBar(), BorderLayout.NORTH);
        add(getSelectableChartPanel(), BorderLayout.CENTER);

    }

    /**
     * Reacts with an {@link SelectableChartPanel#refresh()} on every selection
     * change.
     */
    @Override
    public void selectionChanged(DatasetSelectionChangeEvent e) {
        if (!e.getSource().getValueIsAdjusting())
            getSelectableChartPanel().refresh();
    }

    /**
     * Remove the listeners...
     */
    @Override
    public void dispose() {
        List<FeatureDatasetSelectionModel<?, ?, ?>> datasetSelectionModelFor = FeatureChartUtil
                .getFeatureDatasetSelectionModelFor(getSelectableChartPanel().getChart());

        for (final FeatureDatasetSelectionModel selModel : datasetSelectionModelFor) {
            for (DatasetSelectionListener d : insertedListeners) {
                selModel.removeSelectionListener(d);
            }
        }
        insertedListeners.clear();
    }

    /**
     * If {@link #previewMapPane} and {@link #mapLegend} are both not <code>null</code>
     * , this method adds a {@link JButton}
     * 
     * @param atlasChartPanel
     */
    public void addZoomToFeatureExtends(final SelectableXMapPane myMapPane, final MapLegend mapLegend,
            final StyledFeaturesInterface<?> styledFeatures, AtlasChartJPanel atlasChartPanel) {
        if (myMapPane != null && mapLegend != null) {

            /**
             * Add a normal Button to zoom to the BBOX of the selected objects.
             */
            final SmallButton zoomToSelectionButton = new SmallButton(
                    new AbstractAction("", SelectableChartPanel.ICON_ZOOM_TO_SELECTED) {

                        @Override
                        public void actionPerformed(final ActionEvent e) {

                            final StyledLayerSelectionModel<?> anySelectionModel = myMapPane != null
                                    ? mapLegend.getRememberSelection(styledFeatures.getId())
                                    : null;

                            if ((anySelectionModel instanceof StyledFeatureLayerSelectionModel)) {
                                final StyledFeatureLayerSelectionModel selectionModel = (StyledFeatureLayerSelectionModel) anySelectionModel;

                                final Vector<String> selectionIDs = selectionModel.getSelection();

                                try {

                                    /*
                                     * Creating a set of FeatureIdImpl which can
                                     * be used for a FidFilter
                                     */
                                    final HashSet<Identifier> setOfIdentifiers = new HashSet<Identifier>();
                                    for (final String idString : selectionIDs) {
                                        setOfIdentifiers.add(new FeatureIdImpl(idString));
                                    }

                                    final FeatureCollection<SimpleFeatureType, SimpleFeature> selectedFeatures = styledFeatures
                                            .getFeatureSource()
                                            .getFeatures(FeatureUtil.FILTER_FACTORY2.id(setOfIdentifiers));
                                    myMapPane.zoomTo(selectedFeatures);
                                    myMapPane.refresh();

                                } catch (final IOException e1) {
                                    throw new RuntimeException("While zooming to the selected features.", e1);
                                }

                            }

                        }

                    });
            // zoomToSelectionButton.setBorder(BorderFactory
            // .createRaisedBevelBorder());
            zoomToSelectionButton.setToolTipText(GeotoolsGUIUtil
                    .R("schmitzm.geotools.gui.SelectableFeatureTablePane.button.zoomToSelection.tt"));
            final JToolBar toolBar = atlasChartPanel.getToolBar();
            toolBar.add(zoomToSelectionButton, 6);

            {
                // Add listeners to the selection model, so we know when to
                // disable/enable the button

                // get the selectionmodel(s) of the chart
                List<FeatureDatasetSelectionModel<?, ?, ?>> datasetSelectionModelFor = FeatureChartUtil
                        .getFeatureDatasetSelectionModelFor(atlasChartPanel.getChart());
                for (final FeatureDatasetSelectionModel selModel : datasetSelectionModelFor) {

                    DatasetSelectionListener listener_ZoomToSelectionButtonEnbled = new DatasetSelectionListener() {

                        @Override
                        public void selectionChanged(DatasetSelectionChangeEvent e) {
                            if (!e.getSource().getValueIsAdjusting()) {

                                // Update the clearSelectionButton
                                zoomToSelectionButton.setEnabled(selModel.getSelectedFeatures().size() > 0);
                            }
                        }
                    };
                    insertedListeners.add(listener_ZoomToSelectionButtonEnbled);
                    selModel.addSelectionListener(listener_ZoomToSelectionButtonEnbled);

                    zoomToSelectionButton.setEnabled(selModel.getSelectedFeatures().size() > 0);
                }
            }
        }
    }
}