/******************************************************************************* * 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.chartwizard; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.HashMap; import java.util.Vector; import javax.swing.DefaultComboBoxModel; import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import net.miginfocom.swing.MigLayout; import org.apache.log4j.Logger; import org.geopublishing.atlasStyler.swing.AttributesJComboBox; import org.geopublishing.geopublisher.swing.GeopublisherGUI; import org.geotools.data.FeatureSource; import org.netbeans.spi.wizard.WizardPage; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import de.schmitzm.geotools.data.amd.AttributeMetadataMap; import de.schmitzm.geotools.feature.FeatureUtil; import de.schmitzm.jfree.chart.style.ChartType; public class AttributeSelectionWizardPanel extends WizardPage { final static protected Logger LOGGER = Logger .getLogger(AttributeSelectionWizardPanel.class); private JLabel descriptionPanel; private final HashMap<Integer, AttributesJComboBox> attributJComboBoxes = new HashMap<Integer, AttributesJComboBox>(); // private List<String> numericalAttNames; private final HashMap<Integer, JCheckBox> normalizeJCheckboxs = new HashMap<Integer, JCheckBox>(); private final HashMap<Integer, JLabel> lables = new HashMap<Integer, JLabel>(); private final HashMap<Integer, JPanel> settingsPanels = new HashMap<Integer, JPanel>(); private ChartType lastChartType; /* * The short description label that appears on the left side of the wizard */ static String desc = GeopublisherGUI .R("AttributeSelectionWizardPanel.Title"); @Override protected String validateContents(Component component, Object event) { ChartType chartType = (ChartType) getWizardData(ChartWizard.CHARTTYPE); for (int idx = 0; idx < chartType.getMinDimensions(); idx++) { if (getAttribJComboBoxFor(idx).getSelectedIndex() == -1) return GeopublisherGUI .R("AttributeSelectionWizardPanel.ValidationFailed.NeedAtLeastXAttributes", chartType.getMinDimensions()); } return null; } public static String getDescription() { return desc; } private void initGUI() { removeAll(); setLayout(new MigLayout("wrap 3, w " + ChartWizard.WIDTH_DEFAULT)); add(getDescriptionPanel(), "span 3"); ChartType chartType = (ChartType) getWizardData(ChartWizard.CHARTTYPE); int maxDimensions = chartType.getMaxDimensions(); if (maxDimensions == -1) maxDimensions = 4; int minDimensions = chartType.getMinDimensions(); for (Integer index = 0; index < maxDimensions; index++) { boolean enabled = (index < minDimensions); add(getLabelFor(index), "top, , gapy u"); getLabelFor(index).setEnabled(enabled); add(getAttribJComboBoxFor(index), "top, gapy u"); getAttribJComboBoxFor(index).setEnabled(enabled); add(getSettingsPanel(index), "top, gapy u"); getSettingsPanel(index).setEnabled(enabled); } } private JLabel getLabelFor(Integer index) { if (lables.get(index) == null) { JLabel label = new JLabel(GeopublisherGUI.R( "AttributeSelectionWizardPanel.NthAttribute", index + 1)); lables.put(index, label); } return lables.get(index); } /** * A {@link JPanel} containing the GUI with options that define the handling * of the domain axis data. */ private JPanel getSettingsPanel(int idx) { if (settingsPanels.get(idx) == null) { ChartType chartType = (ChartType) getWizardData(ChartWizard.CHARTTYPE); JPanel settingsPanel; if (idx == 0) { settingsPanel = new JPanel(new MigLayout("wrap 1, insets 0")); // settingsPanel.add(getNormalizeJCheckboxFor(idx)); // For scatter plots they makes no sense: if (!(chartType == ChartType.SCATTER)) { settingsPanel.add(getDomainSortedJCheckbox()); settingsPanel.add(getCategoryJCheckbox()); } } else { settingsPanel = new JPanel(new MigLayout("wrap 1, insets 0")); // settingsPanel.add(getNormalizeJCheckboxFor(idx)); } settingsPanels.put(idx, settingsPanel); } return settingsPanels.get(idx); } // /** // * Returns the normlizeCheckBox for idx // */ // private JCheckBox getNormalizeJCheckboxFor(int idx) { // if (normalizeJCheckboxs.get(idx) == null) { // JCheckBox cb = new JCheckBox(Geopublisher // .R("AttributeSelectionPanel.NormalizeCheckbox")); // cb.setToolTipText(Geopublisher // .R("AttributeSelectionPanel.NormalizeCheckbox.TT")); // // final ChartType chartType = // (ChartType)getWizardData(ChartWizard.CHARTTYPE); // if (chartType == ChartType.SCATTER) { // cb.setSelected(true); // } else { // cb.setSelected(false); // } // // cb.setName(ChartWizard.NORMALIZE_ + idx); // normalizeJCheckboxs.put(idx, cb); // // getAttribJComboBoxFor(0).addItemListener(new ItemListener() { // // @Override // public void itemStateChanged(ItemEvent e) { // // // LOGGER.debug(normalizeJCheckboxs.get(0)); // // if (e.getSource() != normalizeJCheckboxs.get(0)) // // return; // // if (getAttribJComboBoxFor(0).isNumericalAttribSelected()) { // /* A numerical attribute */ // normalizeJCheckboxs.get(0).setEnabled(true); // } else { // /* A numerical attribute */ // normalizeJCheckboxs.get(0).setEnabled(false); // normalizeJCheckboxs.get(0).setSelected(false); // } // } // }); // } // return normalizeJCheckboxs.get(idx); // } /** * This checkbox defines whether the the domain axis will treat numerical * data as category data */ private Component getCategoryJCheckbox() { final JCheckBox cb = new JCheckBox( GeopublisherGUI .R("AttributeSelectionPanel.DomainForceCategoryCheckbox")); cb.setToolTipText(GeopublisherGUI .R("AttributeSelectionPanel.DomainForceCategoryCheckbox")); cb.setName(ChartWizard.DOMAIN_FORCE_CATEGORY); // cb // .setSelected((Boolean) // getWizardData(ChartWizard.DOMAIN_FORCE_CATEGORY)); getAttribJComboBoxFor(0).addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() != ItemEvent.SELECTED) return; if (getAttribJComboBoxFor(0).isNumericalAttribSelected()) { /* A numerical attribute */ cb.setEnabled(true); } else { /* A numerical attribute */ cb.setEnabled(false); cb.setSelected(true); } } }); return cb; } // // /** // * Caches the List of numerical attributes because it can be expensive // with // * network datastores. // * // * @param featureSource // * @return // */ // private List<String> getNumericaAttribs(FeatureSource featureSource) { // if (numericalAttNames == null) // numericalAttNames = FeatureUtil.getNumericalFieldNames(featureSource); // return numericalAttNames; // } private JCheckBox getDomainSortedJCheckbox() { JCheckBox cb = new JCheckBox( GeopublisherGUI.R("AttributeSelectionPanel.DomainSortCheckbox")); cb.setToolTipText(GeopublisherGUI .R("AttributeSelectionPanel.DomainSortCheckbox.TT")); cb.setName(ChartWizard.SORT_DOMAIN_AXIS); /* * Initialize with the value from the map */ // cb.setSelected((Boolean)getWizardData(ChartWizard.SORT_DOMAIN_AXIS)); return cb; } public JLabel getDescriptionPanel() { if (descriptionPanel == null) { ChartType chartType = (ChartType) getWizardData(ChartWizard.CHARTTYPE); descriptionPanel = new JLabel( GeopublisherGUI.R("AttributeSelectionPanel.Explanation", chartType.getTitle())); } return descriptionPanel; } /** * Somewhat ugly, we can only access the WizardData, once the Panel has been * displayed. So we have to make all changes that depend on earlier * decisions here: */ @Override protected void renderingPage() { if (lastChartType != getWizardData(ChartWizard.CHARTTYPE)) { /* * We have to clean all cahced Components then, because otherwise * the listerners... */ attributJComboBoxes.clear(); normalizeJCheckboxs.clear(); settingsPanels.clear(); lastChartType = (ChartType) getWizardData(ChartWizard.CHARTTYPE); // LOGGER.debug("CHART TYPE CHANGED CLEARED"); initGUI(); } else { // LOGGER.debug("CHART TYPE CHANGED NOT CLEARED"); } }; /** * Creates the {@link AttributesJComboBox} for the second and more * attributes * * @param idx * @return */ public AttributesJComboBox getAttribJComboBoxFor(final int idx) { if (attributJComboBoxes.get(idx) == null) { /* * Extract values from the wizardDataMap */ final FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = (FeatureSource<SimpleFeatureType, SimpleFeature>) getWizardData(ChartWizard.FEATURESOURCE); AttributeMetadataMap attributeMetaDataMap = (AttributeMetadataMap) getWizardData(ChartWizard.ATTRIBUTEMETADATAMAP); Vector<String> dataArray; /* * Does the ChartType allow non-numerical values on the domain axis? */ final ChartType chartType = (ChartType) getWizardData(ChartWizard.CHARTTYPE); if (idx == 0 && chartType.isCategoryAllowedForDomainAxis()) { dataArray = FeatureUtil.getValueFieldNames(featureSource .getSchema()); } else { dataArray = FeatureUtil.getNumericalFieldNames(featureSource .getSchema()); } /* Add the null as an item to the optional drop down lists only */ if (idx > 0 && idx > chartType.getMinDimensions() - 1) dataArray.add(0, null); final AttributesJComboBox jcombo = new AttributesJComboBox( featureSource.getSchema(), attributeMetaDataMap, new DefaultComboBoxModel(dataArray)); jcombo.setName(ChartWizard.ATTRIBUTE_ + idx); /* * Add a Listener that activates or de-activates the JComboBoxes */ jcombo.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() != ItemEvent.SELECTED) return; String selection = null; Object[] selectedObjects = e.getItemSelectable() .getSelectedObjects(); if (selectedObjects != null && selectedObjects.length > 0) selection = (String) selectedObjects[0]; /* * When setting it to something, we remove the NULL from the * previous JComoBox */ if (selection != null && idx > 1) { // LOGGER.debug("sel != null && idx-1=" + (idx - 1)); // LOGGER.debug("removing the null from " + (idx - 1)); Object backupSelection = getAttribJComboBoxFor(idx - 1) .getSelectedItem(); getAttribJComboBoxFor(idx - 1).setModel( new DefaultComboBoxModel(FeatureUtil .getValueFieldNames(featureSource .getSchema()))); getAttribJComboBoxFor(idx - 1).setSelectedItem( backupSelection); } else if (selection == null && idx - 1 > chartType.getMinDimensions() - 1) { // LOGGER.debug("adding the null to " + (idx - 1)); Object backupSelection = getAttribJComboBoxFor(idx - 1) .getSelectedItem(); Vector<String> dataArray = FeatureUtil .getValueFieldNames(featureSource.getSchema()); dataArray.insertElementAt(null, 0); getAttribJComboBoxFor(idx - 1).setModel( new DefaultComboBoxModel(dataArray)); getAttribJComboBoxFor(idx - 1).setSelectedItem( backupSelection); // LOGGER.debug("adding the null "); } if (attributJComboBoxes.containsKey(idx + 1)) { // LOGGER.debug(idx + 1 + " exists."); /* If a next JComboBox exists */ if (selection != null) { // LOGGER.debug("sel != null. setting it to enabled."); getAttribJComboBoxFor(idx + 1).setEnabled(true); getLabelFor(idx + 1).setEnabled(true); // getNormalizeJCheckboxFor(idx + // 1).setEnabled(true); } else { // LOGGER // .debug("sel == null. setting it to disabled."); getAttribJComboBoxFor(idx + 1).setEnabled(false); getLabelFor(idx + 1).setEnabled(false); // getNormalizeJCheckboxFor(idx + // 1).setEnabled(false); getAttribJComboBoxFor(idx + 1).setSelectedItem( (Object) null); } } } }); jcombo.setSelectedItem(null); attributJComboBoxes.put(idx, jcombo); } return attributJComboBoxes.get(idx); } public static void main(String[] args) { JDialog d = new JDialog(); d.setContentPane(new AttributeSelectionWizardPanel()); d.pack(); d.setVisible(true); } @Override protected CustomComponentListener createCustomComponentListener() { return new CCL(); } private static final class CCL extends CustomComponentListener implements ActionListener { private CustomComponentNotifier notifier; @Override public boolean accept(Component c) { return c instanceof AttributesJComboBox; } @Override public void startListeningTo(Component c, CustomComponentNotifier n) { notifier = n; ((AttributesJComboBox) c).addActionListener(this); } @Override public void stopListeningTo(Component c) { ((AttributesJComboBox) c).removeActionListener(this); } @Override public Object valueFor(Component c) { return ((AttributesJComboBox) c).getSelectedItem(); } public void actionPerformed(ActionEvent e) { notifier.userInputReceived((Component) e.getSource(), e); } } }