/******************************************************************************* * Copyright (c) 2010 Stefan A. Tzeggai. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v2.0 * 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.geopublisher.gui; import java.awt.Checkbox; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Random; import java.util.Vector; import java.util.WeakHashMap; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JTabbedPane; import javax.swing.JTextField; import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import net.miginfocom.swing.MigLayout; import org.apache.log4j.Logger; import org.geopublishing.atlasStyler.swing.AttributesJComboBox; import org.geopublishing.atlasViewer.GpCoreUtil; import org.geopublishing.atlasViewer.dp.layer.DpLayerVectorFeatureSource; import org.geopublishing.atlasViewer.swing.AVDialogManager; import org.geopublishing.atlasViewer.swing.AVSwingUtil; import org.geopublishing.atlasViewer.swing.AtlasChartJDialog; import org.geopublishing.atlasViewer.swing.AtlasChartJPanel; import org.geopublishing.atlasViewer.swing.AtlasMapLegend; import org.geopublishing.atlasViewer.swing.Icons; import org.geopublishing.atlasViewer.swing.MapLegend; import org.geopublishing.geopublisher.AtlasConfigEditable; import org.geopublishing.geopublisher.chart.GeneralChartSettingsJPanel; import org.geopublishing.geopublisher.gui.internal.GPDialogManager; import org.geopublishing.geopublisher.swing.GeopublisherGUI; import org.geotools.feature.FeatureCollection; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.opengis.feature.simple.SimpleFeatureType; import de.schmitzm.geotools.data.amd.AttributeMetadataImpl; import de.schmitzm.geotools.feature.FeatureUtil; import de.schmitzm.geotools.gui.SelectableXMapPane; import de.schmitzm.geotools.gui.XMapPane; 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.i18n.Translation; import de.schmitzm.jfree.chart.selection.DatasetSelectionModel; import de.schmitzm.jfree.chart.style.ChartAxisStyle; import de.schmitzm.jfree.chart.style.ChartPlotStyle; import de.schmitzm.jfree.chart.style.ChartStyle; import de.schmitzm.jfree.chart.style.ChartType; import de.schmitzm.jfree.feature.FeatureDatasetSelectionModel; import de.schmitzm.jfree.feature.style.FeatureChartStyle; import de.schmitzm.jfree.feature.style.FeatureChartUtil; import de.schmitzm.jfree.table.AggregationFunction; import de.schmitzm.jfree.table.AggregationFunctionJComboBox; import de.schmitzm.jfree.table.style.TableChartAxisStyle; import de.schmitzm.swing.CancellableDialogAdapter; import de.schmitzm.swing.ColorButton; import de.schmitzm.swing.ExceptionDialog; import de.schmitzm.swing.JPanel; import de.schmitzm.swing.SwingUtil; import de.schmitzm.swing.TranslationEditJPanel; import de.schmitzm.swing.swingworker.AtlasStatusDialog; import de.schmitzm.swing.swingworker.AtlasSwingWorker; /** * This {@link JDialog} allows to interactively edit a {@link FeatureChartStyle} * . The preview window automatically reflects the changes. * * @author Stefan A. Tzeggai * */ public class DesignAtlasChartJDialog extends CancellableDialogAdapter { final static Logger LOGGER = Logger .getLogger(DesignAtlasChartJDialog.class); /** * The atlas configuration this chart belongs to. */ private final AtlasConfigEditable atlasConfigEditable; private JTabbedPane jTabbedPane; private JPanel generalSettingsJPanel; private HashMap<Integer, JPanel> legendTitleTranslationEditPanels = new HashMap<Integer, JPanel>(); private HashMap<Integer, JButton> seriesColorButtons = new HashMap<Integer, JButton>(); /** * Remembers the position of panels in the {@link JTabbedPane} created by * {@link #getTabbedPane()}. The key is calculated by * <code>renderIdx * 1000 + seriesIdx</code> **/ private HashMap<Integer, Integer> rememberTabPos = new HashMap<Integer, Integer>(); /** Automatically apply any changes to the {@link ChartStyle} to the chart? */ private boolean autoUpdateMode = false; /** * If set to <code>true</code>, the next update includes a reapplying the * {@link ChartStyle} to the {@link FeatureCollection} */ private boolean reapplyChartStyleToFeatureCollection = false; /** A button to manually update the chart **/ private JButton updateChartJButton; /** A {@link Checkbox} to switch between automatic or manual update mode **/ private JCheckBox updateModeJCheckbox; private JCheckBox categoryDomainAxisJCheckBox; private HashMap<Integer, JCheckBox> shapesVisibleJCheckBoxes = new HashMap<Integer, JCheckBox>(); /** * The {@link FeatureChartStyle} that is being edited here. The GUI is * changing the object directly. **/ private final FeatureChartStyle chartStyle; /** * A backup of the original chartStyle created with * {@link FeatureChartStyle#copyTo(ChartStyle)} **/ private FeatureChartStyle backupChartStyle; /** * A reference to the {@link MapLegend} of the {@link XMapPane} that shows * the geometries for the data-points. **/ private final AtlasMapLegend mapLegend; /** * A reference to the {@link SelectableXMapPane} that shows the geometries * for the data-points. **/ private SelectableXMapPane mapPane; /** * The {@link StyledFeaturesInterface} this {@link FeatureChartStyle} is * based on **/ private final StyledFeaturesInterface<?> styledLayer; /** * This {@link AtlasChartJPanel} shows previews of the chart. */ private AtlasChartJPanel chartPanel; /** * Creates a GUI that can change properties of a {@link FeatureChartStyle}. * The GUI is automatically visible. * * @param owner * A {@link Component} that this GUI is related to. * @param chartStyle * An instance of {@link FeatureChartStyle} to edit * @param mapLegend * A reference to a {@link MapLegend}. If <code>null</code>, the * selection will not be synchronized with any {@link XMapPane}. * @param styledFeatures * The features to calculate the chart on * @param atlasConfigEditable * The atlas configuration this chart is being created for. */ public DesignAtlasChartJDialog(final Component owner, final FeatureChartStyle chartStyle, final AtlasMapLegend mapLegend, final StyledFeaturesInterface<?> styledFeatures, AtlasConfigEditable atlasConfigEditable) { super(owner); this.chartStyle = chartStyle; this.mapLegend = mapLegend; this.styledLayer = styledFeatures; this.mapPane = mapLegend != null ? (mapLegend.getGeoMapPane() != null ? mapLegend .getGeoMapPane().getMapPane() : null) : null; // GPDialogManager.dm_MapComposer.getInstanceFor(mapLegend.getm, // factory) this.atlasConfigEditable = atlasConfigEditable; backup(); try { initGUI(); SwingUtil.setRelativeFramePosition(this, owner, SwingUtil.BOUNDS_OUTER, SwingUtil.NORTHEAST); setVisible(true); } catch (RuntimeException e) { cancel(); throw (e); } } /** * Stores a copy of {@link FeatureChartStyle} in * {@link DesignAtlasChartJDialog#backupChartStyle}. */ private void backup() { backupChartStyle = (FeatureChartStyle) chartStyle.copy(); } /** * Copies all values of the {@link DesignAtlasChartJDialog#backupChartStyle} * to the original {@link FeatureChartStyle} without replacing the object. */ @Override public void cancel() { backupChartStyle.copyTo(chartStyle); } protected void initGUI() { setTitle(chartStyle.getTitleStyle().getLabel()); JPanel contentPane = new JPanel(new MigLayout("wrap 1")); contentPane.add(getChartPanel(mapLegend, styledLayer)); // Adds an ACTION button to zoom to the full extent of the chart chartPanel.getToolBar().add( AtlasChartJDialog.createZoomToFullChartExtentButton(chartPanel, chartStyle), 0); contentPane.add(getTabbedPane()); getChartPanel(mapLegend, styledLayer).addZoomToFeatureExtends(mapPane, mapLegend, styledLayer, getChartPanel(mapLegend, styledLayer)); contentPane.add(getButtonsPane()); setContentPane(contentPane); // super.addZoomToFeatureExtends(); SwingUtil.setPreferredWidth(this, ChartPanel.DEFAULT_WIDTH); pack(); } /** * Creates the buttons */ private Component getButtonsPane() { JPanel buttons = new JPanel(new MigLayout()); buttons.add(getUpdateModeJCheckbox()); buttons.add(getUpdateChartJButton()); JButton attributes = new JButton(new AbstractAction( GpCoreUtil.R("LayerToolMenu.table"), Icons.ICON_TABLE) { @Override public void actionPerformed(ActionEvent e) { AVDialogManager.dm_AttributeTable.getInstanceFor(styledLayer, DesignAtlasChartJDialog.this, styledLayer, mapLegend); } }); buttons.add(attributes); buttons.add(getOkButton(), "right, tag ok"); buttons.add(getCancelButton(), "right, tag cancel"); return buttons; } /** * Returns a labeled {@link JCheckBox} that controls the auto/manual preview * mode. */ private Component getUpdateModeJCheckbox() { if (updateModeJCheckbox == null) { updateModeJCheckbox = new JCheckBox( new AbstractAction( GeopublisherGUI .R("DesignAtlasChartJDialog.previewModeCheckboxLabel")) { @Override public void actionPerformed(ActionEvent e) { setAutoUpdateMode(!isAutoUpdateMode()); getUpdateChartJButton().setEnabled( !isAutoUpdateMode()); /* * If it has just been switched on, trigger an * update */ if (autoUpdateMode) { updateChart(); } } }); updateModeJCheckbox.setToolTipText(GeopublisherGUI .R("DesignAtlasChartJDialog.previewModeCheckboxLabel.TT")); } return updateModeJCheckbox; } /** * This {@link JButton} can be used to manually apply the {@link ChartStyle} * to the {@link JFreeChart} */ private JButton getUpdateChartJButton() { if (updateChartJButton == null) { updateChartJButton = new JButton(new AbstractAction( GeopublisherGUI .R("DesignAtlasChartJDialog.previewChartButton")) { @Override public void actionPerformed(ActionEvent e) { updateChart(); } }); updateChartJButton.setEnabled(!isAutoUpdateMode()); } return updateChartJButton; } /** * The {@link JTabbedPane} that manages the different types of * chartStyle-settings. */ private JTabbedPane getTabbedPane() { if (jTabbedPane == null) { jTabbedPane = new JTabbedPane(); int countTabsPos = 0; jTabbedPane.add(new JScrollPane(getGeneralSettingsPanel(), ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)); jTabbedPane.setTitleAt(countTabsPos++, GeopublisherGUI .R("DesignAtlasChartJDialog.Tabs.General.Title")); jTabbedPane.add(new JScrollPane(getChartPlotStylePanel(), ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)); jTabbedPane.setTitleAt(countTabsPos++, GeopublisherGUI .R("DesignAtlasChartJDialog.Tabs.ChartPlotStyle.Title")); jTabbedPane.add(new JScrollPane( getAxisPanel(ChartStyle.DOMAIN_AXIS), ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)); jTabbedPane.setTitleAt(countTabsPos++, GeopublisherGUI .R("DesignAtlasChartJDialog.Tabs.DomainAxis.Title")); jTabbedPane.add(new JScrollPane( getAxisPanel(ChartStyle.RANGE_AXIS), ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)); jTabbedPane.setTitleAt(countTabsPos++, GeopublisherGUI .R("DesignAtlasChartJDialog.Tabs.RangeAxis1.Title")); int renderIdx = 0; // if (chartStyle.getType() != ChartType.SCATTER) { for (int seriesIdx = 0; seriesIdx < chartStyle.getRendererStyle( renderIdx).getSeriesCount(); seriesIdx++) { jTabbedPane.add(new JScrollPane(getRendererSettingsPanel( renderIdx, seriesIdx), ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)); jTabbedPane.setTitleAt(countTabsPos, chartStyle.getType() .getObjectName()); rememberTabPos .put(renderIdx * 1000 + seriesIdx, countTabsPos++); updateTabIcon(renderIdx, seriesIdx); } } return jTabbedPane; } private JPanel getChartPlotStylePanel() { JPanel panel = new JPanel(new MigLayout("w " + (ChartPanel.DEFAULT_WIDTH - 40) + ", wrap 1")); // Initialize with non-nulls if (chartStyle.getPlotStyle() == null) chartStyle.setPlotStyle(new ChartPlotStyle()); if (chartStyle.getPlotStyle().isDomainGridlineVisible() == null) chartStyle.getPlotStyle().setDomainGridlineVisible(true); if (chartStyle.getPlotStyle().isRangeGridlineVisible() == null) chartStyle.getPlotStyle().setRangeGridlineVisible(true); JPanel grids = new JPanel( new MigLayout(), GeopublisherGUI .R("DesignAtlasChartJDialog.Tabs.ChartPlotStyle.Grid.Border")); { // Domain Axis JCheckBox cb = new JCheckBox( GeopublisherGUI .R("DesignAtlasChartJDialog.Tabs.ChartPlotStyle.Grid.Domain.visible")); cb.setSelected(chartStyle.getPlotStyle().isDomainGridlineVisible()); cb.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { chartStyle.getPlotStyle().setDomainGridlineVisible( e.getStateChange() == ItemEvent.SELECTED); fireChartChangedEvent(); } }); grids.add(cb); } { JCheckBox cb = new JCheckBox( GeopublisherGUI .R("DesignAtlasChartJDialog.Tabs.ChartPlotStyle.Grid.Range.visible")); cb.setSelected(chartStyle.getPlotStyle().isRangeGridlineVisible()); cb.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { chartStyle.getPlotStyle().setRangeGridlineVisible( e.getStateChange() == ItemEvent.SELECTED); fireChartChangedEvent(); } }); grids.add(cb); } JPanel axisCross = new JPanel( new MigLayout(), GeopublisherGUI .R("DesignAtlasChartJDialog.Tabs.ChartPlotStyle.ZeroAxis.Border")); // For BAR charts drawing the cross of axis or choosing its color has no // function if (chartStyle.getType() != ChartType.BAR) { // Fill empty values with defaults if (chartStyle.getPlotStyle().isCrosshairVisible() == null) chartStyle.getPlotStyle().setCrosshairVisible(false); if (chartStyle.getPlotStyle().getCrosshairPaint() == null) chartStyle.getPlotStyle().setCrosshairPaint(Color.BLACK); // Draw cross of axis / Crosshair line JCheckBox cb = new JCheckBox( GeopublisherGUI .R("DesignAtlasChartJDialog.Tabs.ChartPlotStyle.ZeroAxis.visible")); cb.setSelected(chartStyle.getPlotStyle().isCrosshairVisible()); cb.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { chartStyle.getPlotStyle().setCrosshairVisible( e.getStateChange() == ItemEvent.SELECTED); fireChartChangedEvent(); } }); axisCross.add(cb); // Color Button for ZeroAxis cross-hair final ColorButton colorButton = new ColorButton(chartStyle .getPlotStyle().getCrosshairPaint()); colorButton .setAction(new AbstractAction( GeopublisherGUI .R("DesignAtlasChartJDialog.Tabs.ChartPlotStyle.ZeroAxis.Color")) { @Override public void actionPerformed(final ActionEvent e) { chartStyle .getPlotStyle() .setCrosshairPaint( AVSwingUtil .showColorChooser( DesignAtlasChartJDialog.this, GeopublisherGUI .R("DesignAtlasChartJDialog.Tabs.ChartPlotStyle.ZeroAxis.ColorDialog.Title"), chartStyle .getPlotStyle() .getCrosshairPaint())); colorButton.setColor(chartStyle.getPlotStyle() .getCrosshairPaint()); fireChartChangedEvent(); } }); axisCross.add(colorButton); } { JCheckBox cb = new JCheckBox( GeopublisherGUI .R("DesignAtlasChartJDialog.Tabs.ChartPlotStyle.ZeroAxis.Center")); cb.setSelected(chartStyle.getPlotStyle() .isCenterOriginSymetrically()); cb.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { chartStyle.getPlotStyle().setCenterOriginSymetrically( e.getStateChange() == ItemEvent.SELECTED); fireChartChangedEvent(); } }); axisCross.add(cb); } panel.add(grids, "growx, sgx"); panel.add(axisCross, "growx, sgx"); if (chartStyle instanceof FeatureChartStyle) panel.add(getNormalizationPanel(), "growx, sgx"); return panel; } /** * A listener to update the chart when the label is changed while typing. We * need a reference to this listener as the listeners of {@link Translation} * are kept in a {@link WeakHashMap}. */ private ActionListener listenToDomainLabelChangesAndUpdateChart = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { fireChartChangedEvent(); } }; private HashMap<Integer, JTextField> unitTextFields = new HashMap<Integer, JTextField>(); /** * A {@link JPanel} which allows the user to configure the appearance of the * domain axis */ private JPanel getAxisPanel(int axisNr) { final JPanel axisPane = new JPanel(new MigLayout("w " + (ChartPanel.DEFAULT_WIDTH - 40) + ",wrap 2", "[grow]")); /* * Ensure that there are no NULLs */ if (chartStyle.getAxisStyle(axisNr) == null) { chartStyle .setAxisStyle(axisNr, new TableChartAxisStyle(chartStyle)); fireChartChangedEvent(); } final ChartAxisStyle axisStyle = chartStyle.getAxisStyle(axisNr); if (axisStyle.getLabelTranslation() == null) { axisStyle.setLabelTranslation(new Translation(atlasConfigEditable .getLanguages(), "")); fireChartChangedEvent(); } if (axisStyle.getLabelAngle() == null) { axisStyle.setLabelAngle(0.); fireChartChangedEvent(); } /* * If this is the DOMAIN axis, allow to change the 0. Attribute/Variable */ if (axisNr == ChartStyle.DOMAIN_AXIS) { SimpleFeatureType schema = styledLayer.getFeatureSource() .getSchema(); final List<String> fieldNames; if (chartStyle.getType().isCategoryAllowedForDomainAxis()) { fieldNames = FeatureUtil.getValueFieldNames(schema); } else fieldNames = FeatureUtil.getNumericalFieldNames(schema); final AttributesJComboBox attribComboBox = new AttributesJComboBox( schema, styledLayer.getAttributeMetaDataMap(), fieldNames); final String domainAxisAttributeLocalName = chartStyle .getAttributeName(ChartStyle.DOMAIN_AXIS); attribComboBox.setSelectedItem(domainAxisAttributeLocalName); /** build GUI... */ final JPanel attPanel = new JPanel(new MigLayout("wrap 1")); attPanel.setBorder(BorderFactory.createTitledBorder(GeopublisherGUI .R("DesignAtlasChartJDialog.SeriesDataBorderTitle"))); attPanel.add(attribComboBox); // A JPanel showing the NODATA values for the selected attribute final NoDataPanel noDataPanel = new NoDataPanel( styledLayer.getAttributeMetaDataMap(), domainAxisAttributeLocalName, styledLayer.getSchema()); // Update the chart whenever the NODATA values changes noDataPanel.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals( NoDataPanel.PROPERTY_NODATAVALUES)) fireChartChangedEvent(true); } }); attPanel.add(noDataPanel); if (chartStyle.getType() != ChartType.SCATTER) { attPanel.add(getDomainSortedJCheckbox(), "growx, right"); attPanel.add(getCategoryJCheckbox(), "growx, right"); } /** * When the attribute is changed, a lot of things happen: */ attribComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() != ItemEvent.SELECTED) return; final String attLocalName = (String) attribComboBox .getSelectedItem(); chartStyle.setAttributeName(ChartStyle.DOMAIN_AXIS, attLocalName); // attribute Metadata for the new attribute AttributeMetadataImpl atm = styledLayer .getAttributeMetaDataMap().get(attLocalName); chartStyle.setNoDataValues(ChartStyle.DOMAIN_AXIS, atm.getNodataValues()); /** * Update the legend labeling with the AttributeMetaData * from the new newly selected attribute */ { GpCoreUtil.applyDefaultTitleAndTranslationToAxis( styledLayer, chartStyle, ChartStyle.DOMAIN_AXIS, 0, atlasConfigEditable.getLanguages()); } /* * You may only force categories, if a numeric att is * selected */ getCategoryJCheckbox().setEnabled( attribComboBox.isNumericalAttribSelected()); if (!attribComboBox.isNumericalAttribSelected()) { getCategoryJCheckbox().setSelected(true); } // Update the NODATA Panel noDataPanel.setAttribute(attLocalName); getUnitTextFieldForAxis(ChartStyle.DOMAIN_AXIS).setText( atm.getUnit()); fireChartChangedEvent(true); } }); axisPane.add(attPanel, "span 2, growx"); } /* * Axis label */ Translation domainLabelTranslation = axisStyle.getLabelTranslation(); final TranslationEditJPanel axisLabelTranslationJPanel = new TranslationEditJPanel( domainLabelTranslation, atlasConfigEditable.getLanguages()); domainLabelTranslation .addTranslationChangeListener(listenToDomainLabelChangesAndUpdateChart); axisLabelTranslationJPanel.setBorder(BorderFactory .createTitledBorder(GeopublisherGUI .R("DesignAtlasChartJDialog.AxisSettings.AxisLabel"))); axisPane.add(axisLabelTranslationJPanel, "span 2, growx"); /* * Now add a box to enter a unit string */ JPanel unitPanel = new JPanel(new MigLayout(), GeopublisherGUI.R("Unit")); /** A textfield that shows the unit (untranslatable). **/ final JTextField unitTextfield = getUnitTextFieldForAxis(axisNr); unitPanel.add( new JLabel(GeopublisherGUI .R("DesignChartDialog.Unit.Explanation")), "wrap"); unitPanel.add(unitTextfield); axisPane.add(unitPanel, "sgy"); /* * Now add a ANGLE slider or radio buttons */ JPanel anglePanel = new JPanel(new MigLayout()); anglePanel .add(new JLabel( GeopublisherGUI .R("DesignAtlasChartJDialog.AxisSettings.ValueLabelAngle")), "wrap"); boolean isANumberAxis = true; try { isANumberAxis = Number.class.isAssignableFrom(styledLayer .getSchema() .getDescriptor(chartStyle.getAttributeName(axisNr)) .getType().getBinding()); } catch (Exception e) { LOGGER.warn("Could not determine wherther this is a number axis", e); } if (isANumberAxis) { JRadioButton horiz = new JRadioButton(new AbstractAction( GeopublisherGUI.R("horizontal")) { @Override public void actionPerformed(ActionEvent e) { axisStyle.setValuesAngle(0.); fireChartChangedEvent(); } }); horiz.setSelected(axisStyle.getValuesAngle() == 0.); JRadioButton vertical = new JRadioButton(new AbstractAction( GeopublisherGUI.R("vertical")) { @Override public void actionPerformed(ActionEvent e) { axisStyle.setValuesAngle(90.); fireChartChangedEvent(); } }); vertical.setSelected(axisStyle.getValuesAngle() == 90.); ButtonGroup bg = new ButtonGroup(); bg.add(horiz); bg.add(vertical); anglePanel.add(horiz, "wrap"); anglePanel.add(vertical, "wrap"); } else { final JSlider angleSlider = new JSlider(0, 90, axisStyle .getValuesAngle().intValue()); /* * A numerical axis may only define angle 0 or 90 */ Hashtable<Integer, JComponent> labelTable = new Hashtable<Integer, JComponent>(); labelTable.put(new Integer(0), new JLabel("0\u00b0")); labelTable.put(new Integer(90), new JLabel("90\u00b0")); angleSlider.setLabelTable(labelTable); angleSlider.setPaintLabels(true); angleSlider.setMajorTickSpacing(15); angleSlider.setPaintTicks(true); angleSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { final Double newAngle = new Double(angleSlider.getValue()); axisStyle.setValuesAngle(newAngle); // LOGGER.debug("Setting angle to "+newAngle); fireChartChangedEvent(); } }); anglePanel.add(angleSlider); } axisPane.add(anglePanel, "sgy, growx 2000"); return axisPane; } private JTextField getUnitTextFieldForAxis(int axisNr) { if (unitTextFields.get(axisNr) == null) { final JTextField unitTextField = new JTextField(15); final ChartAxisStyle axisStyle = chartStyle.getAxisStyle(axisNr); unitTextField.setText(axisStyle.getUnitString()); unitTextField.getDocument().addDocumentListener( new DocumentListener() { @Override public void changedUpdate(DocumentEvent e) { react(); } void react() { axisStyle.setUnitString(unitTextField.getText()); fireChartChangedEvent(); } @Override public void insertUpdate(DocumentEvent e) { react(); } @Override public void removeUpdate(DocumentEvent e) { react(); } }); unitTextFields.put(axisNr, unitTextField); } return unitTextFields.get(axisNr); } /** * This checkbox defines whether the the domain axis will treat numerical * data as category data */ private JCheckBox getCategoryJCheckbox() { if (categoryDomainAxisJCheckBox == null) { categoryDomainAxisJCheckBox = new JCheckBox( GeopublisherGUI .R("AttributeSelectionPanel.DomainForceCategoryCheckbox")); categoryDomainAxisJCheckBox.setToolTipText(GeopublisherGUI .R("AttributeSelectionPanel.DomainForceCategoryCheckbox")); categoryDomainAxisJCheckBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { chartStyle.setForceCategories(categoryDomainAxisJCheckBox .isSelected()); fireChartChangedEvent(true); } }); categoryDomainAxisJCheckBox.setSelected(chartStyle .isForceCategories()); } return categoryDomainAxisJCheckBox; } private JCheckBox getDomainSortedJCheckbox() { JCheckBox cb = new JCheckBox( GeopublisherGUI.R("AttributeSelectionPanel.DomainSortCheckbox")); cb.setToolTipText(GeopublisherGUI .R("AttributeSelectionPanel.DomainSortCheckbox.TT")); cb.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { chartStyle.setSortDomainAxis(e.getStateChange() == ItemEvent.SELECTED); fireChartChangedEvent(true); } }); cb.setSelected(chartStyle.isSortDomainAxis()); return cb; } private void updateTabIcon(int rendererIdx, int seriesIdx) { Integer countTabsPos = rememberTabPos.get(rendererIdx * 1000 + seriesIdx); if (countTabsPos == null) { return; // throw new RuntimeException("No tab known for renderer " // + rendererIdx + " and series " + seriesIdx); } if (countTabsPos >= jTabbedPane.getTabCount()) { return; } Color seriesColor = chartStyle.getRendererStyle(rendererIdx) .getSeriesPaint(seriesIdx); if (seriesColor == null) { chartStyle.getRendererStyle(rendererIdx).setSeriesPaint(seriesIdx, getRandomColor()); fireChartChangedEvent(); } BufferedImage seriesImage = new BufferedImage(12, 12, BufferedImage.TYPE_INT_RGB); final Graphics graphics = seriesImage.getGraphics(); graphics.setColor(seriesColor); graphics.fillRect(0, 0, 11, 11); ImageIcon seriesColorIcon = new ImageIcon(seriesImage); jTabbedPane.setIconAt(countTabsPos, seriesColorIcon); } /** * Returns a Renderer panel. A listener to propagate PropertyChanges of type * "chartStyle" is registered. * * @param rendererIndex * @return */ private JPanel getRendererSettingsPanel(int rendererIndex, int seriesIdx) { JPanel rendererSettingsPanel = new JPanel(new MigLayout("w " + (ChartPanel.DEFAULT_WIDTH - 40) + ",wrap 2")); /* * Color... */ rendererSettingsPanel .add(getSeriesColorButton(rendererIndex, seriesIdx)); // The possibility to show/hide shapes is only given for non point // layers. otherwise set true! if (chartStyle.getType() != ChartType.POINT && chartStyle.getType() != ChartType.SCATTER && chartStyle.getType() != ChartType.BAR) { rendererSettingsPanel.add(getShapesVisibleJCheckBoxFor( rendererIndex, seriesIdx)); } else { chartStyle.getRendererStyle(rendererIndex).setSeriesShapesVisible( seriesIdx, true); rendererSettingsPanel.add(new JLabel()); } rendererSettingsPanel.add( getSeriesDataSelectionJPanel(rendererIndex, seriesIdx), "span 2, growx"); /* * Legend... */ rendererSettingsPanel.add( getLegendTitleTranslationEditPanel(rendererIndex, seriesIdx), "span 2, growx"); rendererSettingsPanel .addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals("chartStyle")) { fireChartChangedEvent(); } } }); return rendererSettingsPanel; } /** * Returns or creates a {@link JCheckBox} that controlls the shapeVisible * attribute. * * @param rendererIndex * @param seriesIdx * @return */ private JCheckBox getShapesVisibleJCheckBoxFor(final int rendererIndex, final int seriesIdx) { if (shapesVisibleJCheckBoxes.get(rendererIndex * 1000 + seriesIdx) == null) { final JCheckBox cb = new JCheckBox(); /* */ final Boolean preset = chartStyle.getRendererStyle(rendererIndex) .isSeriesShapesVisible(seriesIdx); cb.setSelected(preset != null ? preset : false); cb.setText("Show shapes"); // i8n cb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { chartStyle.getRendererStyle(rendererIndex) .setSeriesShapesVisible(seriesIdx, cb.isSelected()); fireChartChangedEvent(); } }); shapesVisibleJCheckBoxes.put(rendererIndex * 1000 + seriesIdx, cb); } return shapesVisibleJCheckBoxes.get(rendererIndex * 1000 + seriesIdx); } /** * A small {@link JPanel} describing the attribute that is used here. */ private JPanel getSeriesDataSelectionJPanel(final int rendererIndex, final int seriesIdx) { SimpleFeatureType schema = styledLayer.getFeatureSource().getSchema(); final AttributesJComboBox attribComboBox = new AttributesJComboBox( schema, styledLayer.getAttributeMetaDataMap(), FeatureUtil.getNumericalFieldNames(schema)); final String attributeName = chartStyle.getAttributeName(seriesIdx + 1); attribComboBox.setSelectedItem(attributeName); /** build a panel... */ final JPanel attPanel = new JPanel(new MigLayout("flowy, wrap 2"), GeopublisherGUI .R("DesignAtlasChartJDialog.SeriesDataBorderTitle")); attPanel.add(attribComboBox); // A Panel that will list all NODATA-Value final NoDataPanel noDataPanel = new NoDataPanel( styledLayer.getAttributeMetaDataMap(), attributeName, styledLayer.getSchema()); // Update the chart whenever the NODATA values changes noDataPanel.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals( NoDataPanel.PROPERTY_NODATAVALUES)) fireChartChangedEvent(true); } }); attPanel.add(noDataPanel); final JPanel panelAggregationWeight = new JPanel(new MigLayout()); if (chartStyle.getType() == ChartType.BAR) { // bei pie auch, wenn wir das mal haben final AggregationFunctionJComboBox aggregationFunctionJComboBox = new AggregationFunctionJComboBox(); aggregationFunctionJComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { int idx = seriesIdx + 1; AggregationFunction aggFunc = (AggregationFunction) aggregationFunctionJComboBox .getSelectedItem(); // System.out.println(idx+"="+aggFunc); chartStyle.setAttributeAggregation(idx, aggFunc); if (idx != ChartStyle.DOMAIN_AXIS) { // Grey-out the weighting attribute if the aggregation // method doesn't support it. panelAggregationWeight.setEnabled(aggFunc != null && aggFunc.isWeighted()); } // AGgregation funktion kann auch auf die axsen UNIT wirken if (idx == ChartStyle.RANGE_AXIS) { String unit = styledLayer.getAttributeMetaDataMap() .get(attributeName).getUnit(); getUnitTextFieldForAxis(ChartStyle.RANGE_AXIS).setText( unit); } fireChartChangedEvent(true); } }); aggregationFunctionJComboBox.setSelectedItem(chartStyle .getAttributeAggregation(seriesIdx + 1)); JPanel panelAggregationMethod = new JPanel(new MigLayout()); JLabel aggMethodlabel = new JLabel( GeopublisherGUI .R("DesignAtlasChartJDialog.SeriesData.Aggregation.Label")); aggMethodlabel.setToolTipText(GeopublisherGUI .R("DesignAtlasChartJDialog.SeriesData.Aggregation.TT")); panelAggregationMethod.add(aggMethodlabel, "gap unrel, w 150"); panelAggregationMethod.add(aggregationFunctionJComboBox); attPanel.add(panelAggregationMethod); panelAggregationWeight .add(new JLabel( GeopublisherGUI .R("DesignAtlasChartJDialog.SeriesData.Aggregation.WeightLabel")), "gap unrel, w 150"); final AttributesJComboBox weightFunctionAttributeComboBox = new AttributesJComboBox( schema, styledLayer.getAttributeMetaDataMap(), FeatureUtil.getNumericalFieldNames(schema)); // Initialize weight combobox String attributeAggregationWeightAttributeName_InChartStyle = chartStyle .getAttributeAggregationWeightAttributeName(seriesIdx + 1); if (attributeAggregationWeightAttributeName_InChartStyle == null) { attributeAggregationWeightAttributeName_InChartStyle = (String) weightFunctionAttributeComboBox .getItemAt(0); chartStyle.setAttributeAggregationWeightAttributeName( seriesIdx + 1, attributeAggregationWeightAttributeName_InChartStyle); } weightFunctionAttributeComboBox .setSelectedItem(attributeAggregationWeightAttributeName_InChartStyle); weightFunctionAttributeComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { String weightAttName = (String) weightFunctionAttributeComboBox .getSelectedItem(); chartStyle.setAttributeAggregationWeightAttributeName( seriesIdx + 1, weightAttName); AttributeMetadataImpl atm = styledLayer .getAttributeMetaDataMap().get(weightAttName); chartStyle.setWeightAttributeNoDataValues(seriesIdx - 1, atm.getNodataValues()); fireChartChangedEvent(true); } }); panelAggregationWeight.add(weightFunctionAttributeComboBox); // Initialize the correct enabled/disabled state AggregationFunction aggFunc = chartStyle .getAttributeAggregation(seriesIdx + 1); panelAggregationWeight.setEnabled(aggFunc != null && aggFunc.isWeighted()); attPanel.add(panelAggregationWeight); } // When the attribute is changed, a lot of things happen: attribComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() != ItemEvent.SELECTED) return; String attLocalName = (String) attribComboBox.getSelectedItem(); chartStyle.setAttributeName(seriesIdx + 1, attLocalName); AttributeMetadataImpl atm = styledLayer .getAttributeMetaDataMap().get(attLocalName); chartStyle.setNoDataValues(seriesIdx + 1, atm.getNodataValues()); // LOGGER.debug("Setting attribute " + seriesIdx + 1 + " to " // + chartStyle.getAttributeName(seriesIdx + 1)); /** * Update the legend labeling with the AttributeMetaData from * the new newly selected attribute */ { GpCoreUtil.applyDefaultTitleAndTranslationToLegend(styledLayer, chartStyle, rendererIndex, seriesIdx, atlasConfigEditable.getLanguages()); } noDataPanel.setAttribute(attLocalName); if (seriesIdx == 0) { String unit = atm.getUnit(); getUnitTextFieldForAxis(seriesIdx + 1).setText(unit); } fireChartChangedEvent(true); } }); return attPanel; } /** * A panel to control the normalization of all attributes at once * * @param featureChartStyle * @return */ private JPanel getNormalizationPanel() { JPanel normPanel = new JPanel(new MigLayout("wrap 1")); // An explaining text normPanel.add(new JLabel(GeopublisherGUI .R("Normalize.Chart.Explanation"))); // The check-box in the next line JCheckBox cb = new JCheckBox( GeopublisherGUI.R("AttributeSelectionPanel.NormalizeCheckbox")); cb.setToolTipText(GeopublisherGUI .R("AttributeSelectionPanel.NormalizeCheckbox.TT")); cb.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { // LOGGER.debug("\n\neventSource = " + e.getSource()); // LOGGER.debug("event = " + e); LOGGER.debug("event state= " + e.getStateChange()); final boolean normalize = e.getStateChange() == ItemEvent.SELECTED; for (int idx = 0; idx < chartStyle.getAttributeCount(); idx++) chartStyle.setAttributeNormalized(idx, normalize); // LOGGER.debug("Setting setAttributeNormalized for all attribs to " // + normalize); LOGGER.debug("0=" + chartStyle.isAttributeNormalized(0)); LOGGER.debug("1=" + chartStyle.isAttributeNormalized(1)); fireChartChangedEvent(true); } }); // If the first attribute is normalized, all are! cb.setSelected(chartStyle.isAttributeNormalized(0)); normPanel.add(cb); normPanel.setBorder(BorderFactory.createTitledBorder(GeopublisherGUI .R("Normalize.Border.title"))); return normPanel; } /** * Called when the {@link ChartStyle} has been changed. Might lead to an * update of the {@link JFreeChart}.<br/> * * @param forceReapplyToFC * if <code>true</code>, the {@link ChartStyle} will be * re-applied to the {@link FeatureCollection}. */ protected void fireChartChangedEvent(boolean forceReapplyToFC) { setReapplyChartStyleToFeatureCollection(forceReapplyToFC); fireChartChangedEvent(); } /** * A {@link JButton} allowing to change the color of the series. */ private JButton getSeriesColorButton(final int rendererIndex, final int seriesIndex) { if (seriesColorButtons.get(rendererIndex * 1000 + seriesIndex) == null) { final ColorButton colorButton = new ColorButton(); colorButton.setAction(new AbstractAction(GeopublisherGUI .R("DesignAtlasChartJDialog.SeriesColorButton")) { @Override public void actionPerformed(final ActionEvent e) { chartStyle.getRendererStyle(rendererIndex).setSeriesPaint( seriesIndex, AVSwingUtil.showColorChooser( DesignAtlasChartJDialog.this, "Zeichenfarbe des Balkendiagramms", // i8n chartStyle.getRendererStyle(rendererIndex) .getSeriesPaint(seriesIndex))); colorButton.setColor(chartStyle.getRendererStyle( rendererIndex).getSeriesPaint(seriesIndex)); fireChartChangedEvent(); } }); /* * Ensure that there are no NULLs */ if (chartStyle.getRendererStyle(rendererIndex).getSeriesPaint( seriesIndex) == null) { chartStyle.getRendererStyle(rendererIndex).setSeriesPaint( seriesIndex, getRandomColor()); fireChartChangedEvent(); } colorButton.setColor(chartStyle.getRendererStyle(rendererIndex) .getSeriesPaint(seriesIndex)); seriesColorButtons.put(rendererIndex * 1000 + seriesIndex, colorButton); } return seriesColorButtons.get(rendererIndex * 1000 + seriesIndex); } ActionListener actionListenerLegendTitleChanged = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { fireChartChangedEvent(); } }; ActionListener actionListenerLegendTooltipChanges = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { fireChartChangedEvent(); } }; /** * A private reference to the listeners. When nulled in dispose, the * WeakHashMap forgets about them */ private Vector<ChartSelectionSynchronizer> insertedListeners = new Vector<ChartSelectionSynchronizer>(); /** * Contains a {@link JCheckBox} to show/hide the series in the legend. Then * a {@link TranslationEditJPanel} for LabelTitle and LabelToolTip. */ public JPanel getLegendTitleTranslationEditPanel(final int rendererIndex, final int seriesIndex) { if (legendTitleTranslationEditPanels.get(rendererIndex * 1000 + seriesIndex) == null) { final JPanel legendSettingsJPanel = new JPanel(new MigLayout( "wrap 2", "[grow]")); Translation legendTitleTranslation = chartStyle .getRendererStyle(rendererIndex) .getSeriesLegendLabel(seriesIndex).getLabelTranslation(); final TranslationEditJPanel legendTitleTranslationJPanel = new TranslationEditJPanel( legendTitleTranslation, atlasConfigEditable.getLanguages()); Translation legendTooltipTranslation = chartStyle .getRendererStyle(rendererIndex) .getSeriesLegendTooltip(seriesIndex).getLabelTranslation(); final TranslationEditJPanel legendTooltipTranslationJPanel = new TranslationEditJPanel( legendTooltipTranslation, atlasConfigEditable.getLanguages()); /* * The checkbox */ final JCheckBox inLegendCB = new JCheckBox( new AbstractAction( GeopublisherGUI .R("DesignAtlasChartJDialog.SeriesInLegendCheckbox")) { @Override public void actionPerformed(ActionEvent e) { final boolean visible = !chartStyle .getRendererStyle(rendererIndex) .isSeriesLegendVisible(seriesIndex); chartStyle.getRendererStyle(rendererIndex) .setSeriesLegendVisible(seriesIndex, visible); /* * Enable/Disable the translation stuff */ legendTitleTranslationJPanel.setEnabled(visible); legendTooltipTranslationJPanel.setEnabled(visible); fireChartChangedEvent(); } }); inLegendCB.setSelected(chartStyle.getRendererStyle(rendererIndex) .isSeriesLegendVisible(seriesIndex)); legendTitleTranslationJPanel.setEnabled(chartStyle .getRendererStyle(rendererIndex).isSeriesLegendVisible( seriesIndex)); legendTooltipTranslationJPanel.setEnabled(chartStyle .getRendererStyle(rendererIndex).isSeriesLegendVisible( seriesIndex)); legendSettingsJPanel.add(inLegendCB, "span 2"); /* * The title */ legendTitleTranslation .addTranslationChangeListener(actionListenerLegendTitleChanged); legendTitleTranslationJPanel .setBorder(BorderFactory.createTitledBorder(GeopublisherGUI .R("DesignAtlasChartJDialog.SeriesLegendLabel.BorderTitle"))); legendSettingsJPanel.add(legendTitleTranslationJPanel, "span 2"); /* * the toolstip */ legendTooltipTranslation .addTranslationChangeListener(actionListenerLegendTooltipChanges); legendTooltipTranslationJPanel .setBorder(BorderFactory.createTitledBorder(GeopublisherGUI .R("DesignAtlasChartJDialog.SeriesLegendLabel.BorderTitle.TT"))); legendSettingsJPanel.add(legendTooltipTranslationJPanel, "span 2"); // /* // * Border // */ // legendSettingsJPanel.setBorder(BorderFactory // .createTitledBorder(Geopublisher // .R("DesignAtlasChartJDialog.LegendBorderTitle"))); legendTitleTranslationEditPanels.put(rendererIndex * 1000 + seriesIndex, legendSettingsJPanel); } return legendTitleTranslationEditPanels.get(rendererIndex * 1000 + seriesIndex); } /** * A {@link JPanel} containing the most general {@link ChartStyle} settings */ private JPanel getGeneralSettingsPanel() { if (generalSettingsJPanel == null) { generalSettingsJPanel = new GeneralChartSettingsJPanel(chartStyle, atlasConfigEditable); generalSettingsJPanel .addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName() .equals(GeneralChartSettingsJPanel.PROPERTYNAME_CHART_STYLE)) { fireChartChangedEvent(); } } }); } return generalSettingsJPanel; } /** * Called when the {@link ChartStyle} has been changed. Might lead to an * update of the {@link JFreeChart}. */ void fireChartChangedEvent() { if (isAutoUpdateMode()) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { updateChart(); } }); } } /** * Apply the settings to the chart-preview. If * {@link #isReapplyChartStyleToFeatureCollection()}, the {@link ChartStyle} * is applied to the {@link FeatureCollection}. */ void updateChart() { AtlasChartJPanel panel = getChartPanel(mapLegend, styledLayer); setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { // Check if normalization is enabled, and then configure the // visualization of unit strings accordingly. // If the first attribute is normalized, all are! { boolean visible = !chartStyle.isAttributeNormalized(0); for (int axisIdx = 0; axisIdx < chartStyle.getAxisCount(); axisIdx++) { chartStyle.getAxisStyle(axisIdx).setUnitVisible(visible); } } if (isReapplyChartStyleToFeatureCollection()) { reapplyChartStyleToFeatureCollection = false; AtlasStatusDialog statusDialog = new AtlasStatusDialog( DesignAtlasChartJDialog.this, GpCoreUtil.R("dialog.title.wait"), GpCoreUtil.R("dialog.title.wait")); AtlasSwingWorker<JFreeChart> asw = new AtlasSwingWorker<JFreeChart>( statusDialog) { @Override protected JFreeChart doInBackground() throws Exception { return chartStyle.applyToFeatureCollection(styledLayer .getFeatureCollection()); } }; JFreeChart newChart = asw.executeModal(); panel.setChart(newChart); } else { chartStyle.applyToChart(panel.getChart()); } getOkButton().setEnabled(true); } catch (Exception e) { ExceptionDialog .show(DesignAtlasChartJDialog.this, e, null, "Failed to apply the chart style to the data. Please check data and settings."); getOkButton().setEnabled(false); } finally { setCursor(null); } /* * Update the icons of the JTabbedPane */ for (int renderIdx = 0; renderIdx < chartStyle.getRendererCount(); renderIdx++) { for (int seriesIdx = 0; seriesIdx < chartStyle.getRendererStyle( renderIdx).getSeriesCount(); seriesIdx++) { updateTabIcon(renderIdx, seriesIdx); } } } public static Color getRandomColor() { final Random random = new Random(); return new Color(100 + random.nextInt(100), 100 + random.nextInt(100), 100 + random.nextInt(100)); } /** * Shall changes to the {@link ChartStyle} automatically update the preview? */ public void setAutoUpdateMode(boolean autoUpdateMode) { this.autoUpdateMode = autoUpdateMode; } /** * Will changes to the {@link ChartStyle} automatically update the preview? */ public boolean isAutoUpdateMode() { return autoUpdateMode; } /** * Will the next call to {@link #updateChart()} apply the {@link ChartStyle} * to the {@link FeatureCollection}? This is needed when attributes have * changed. */ public void setReapplyChartStyleToFeatureCollection( boolean repplyChartStyleToFeatureCollection) { this.reapplyChartStyleToFeatureCollection = repplyChartStyleToFeatureCollection; } /** * Will the next call to {@link #updateChart()} apply the {@link ChartStyle} * to the {@link FeatureCollection}? */ public boolean isReapplyChartStyleToFeatureCollection() { return reapplyChartStyleToFeatureCollection; } /** * Lazily creates the {@link AtlasChartJPanel} */ protected AtlasChartJPanel getChartPanel(final AtlasMapLegend mapLegend, final StyledFeaturesInterface<?> styledLayer_) { if (chartPanel == null) { // Check if normalization is enabled, and then configure the // visualization of unit strings accordingly. // If the first attribute is normalized, all are! // This check is also done in updateChart method. { boolean visible = !chartStyle.isAttributeNormalized(0); for (int axisIdx = 0; axisIdx < chartStyle.getAxisCount(); axisIdx++) { chartStyle.getAxisStyle(axisIdx).setUnitVisible(visible); } } JFreeChart chart; chart = chartStyle.applyToFeatureCollection(styledLayer_ .getFeatureCollection()); chartPanel = new AtlasChartJPanel(chart, styledLayer_, mapLegend); // Connect to every chart selection model to refresh the // panel on selection changes for (final DatasetSelectionModel<?, ?, ?> selModel : FeatureChartUtil .getFeatureDatasetSelectionModelFor(chart)) { selModel.addSelectionListener(chartPanel); } final StyledLayerSelectionModel<?> anySelectionModel = mapLegend != null ? mapLegend .getRememberSelection(styledLayer.getId()) : null; if ((anySelectionModel instanceof StyledFeatureLayerSelectionModel)) { final StyledFeatureLayerSelectionModel selectionModel = (StyledFeatureLayerSelectionModel) anySelectionModel; // get the selectionmodel(s) of the chart final List<FeatureDatasetSelectionModel<?, ?, ?>> datasetSelectionModelFor = FeatureChartUtil .getFeatureDatasetSelectionModelFor(chart); for (final FeatureDatasetSelectionModel dsm : datasetSelectionModelFor) { // create a synchronizer final ChartSelectionSynchronizer synchronizer = new ChartSelectionSynchronizer( selectionModel, dsm); insertedListeners.add(synchronizer); selectionModel .addSelectionListener((StyledLayerSelectionModelSynchronizer) synchronizer); dsm.addSelectionListener(synchronizer); selectionModel.refreshSelection(); } } // addZoomToFeatureExtends(); } return chartPanel; } public static boolean isOpenForLayer(DpLayerVectorFeatureSource dpl) { for (FeatureChartStyle fcs : dpl.getCharts()) { if (GPDialogManager.dm_DesignCharts.isVisibleFor(fcs)) return true; } return false; } @Override public void dispose() { if (isDisposed) return; for (ChartSelectionSynchronizer d : insertedListeners) { d.setEnabled(false); d = null; } insertedListeners.clear(); if (chartPanel != null) chartPanel.dispose(); chartPanel = null; super.dispose(); } }