/*
* The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
* for visualizing and manipulating spatial features with geometry and attributes.
*
* Copyright (C) 2003 Vivid Solutions
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* For more information, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package com.vividsolutions.jump.workbench.ui.renderer.style.attributeclassifications;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import com.vividsolutions.jts.util.Assert;
import com.vividsolutions.jump.I18N;
import com.vividsolutions.jump.util.CollectionUtil;
import com.vividsolutions.jump.util.Range;
import com.vividsolutions.jump.workbench.ui.renderer.style.ColorScheme;
import com.vividsolutions.jump.workbench.ui.renderer.style.ColorThemingStylePanel;
import com.vividsolutions.jump.workbench.ui.renderer.style.ColorThemingTableModel;
import com.vividsolutions.jump.workbench.ui.renderer.style.ColorThemingStylePanel.State;
import com.vividsolutions.jump.workbench.ui.renderer.style.ColorThemingTableModel.AttributeValueTableModelEvent;
public class RangeColorThemingState implements ColorThemingStylePanel.State {
private ColorThemingStylePanel stylePanel;
private static final String RANGE_COUNT_KEY =
RangeColorThemingState.class.getName() + " - RANGE COUNT";
public String getAllOtherValuesDescription() {
return I18N.get("ui.renderer.style.RangeColorThemingState.values-below-these-values");
}
public String getAttributeValueColumnTitle() {
return I18N.get("ui.renderer.style.RangeColorThemingState.minimum-attribute-values");
}
private int getRangeCount() {
return ((Integer) comboBox.getSelectedItem()).intValue();
}
public Collection filterAttributeValues(SortedSet attributeValues) {
//-1 because one row in the table is reserved for "all other values". [Jon Aquino]
int maxFilteredSize = getRangeCount() - 1;
//Obtain even distribution. [Jon Aquino]
//disable attributeValueList (no more used in the method) - see below
//ArrayList attributeValueList = new ArrayList(attributeValues);
Set filteredValues = new TreeSet();
if (attributeValues.size() == 0) {
return filteredValues;
}
double min = ((Number)attributeValues.first()).doubleValue();
double max = ((Number)attributeValues.last()).doubleValue();
double range = max-min;
for (int i = 0 ; i < maxFilteredSize ; i++) {
double threshold = min + range*i/maxFilteredSize;
if (attributeValues.first() instanceof Double) {
filteredValues.add(attributeValues.tailSet(new Double(threshold)).first());
}
else if (attributeValues.first() instanceof Integer) {
filteredValues.add(attributeValues.tailSet(new Integer((int)threshold)).first());
}
else {}
}
//CollectionUtil.stretch(
// attributeValueList,
// filteredValues,
// maxFilteredSize);
return filteredValues;
}
private JPanel panel = new JPanel(new GridBagLayout()) {
public void setEnabled(boolean enabled) {
comboBox.setEnabled(enabled);
label.setEnabled(enabled);
reverseButton.setEnabled(enabled);
super.setEnabled(enabled);
}
};
public RangeColorThemingState(final ColorThemingStylePanel stylePanel) {
this.stylePanel = stylePanel;
addComboBoxItems();
comboBox.setSelectedItem(
stylePanel.getLayer().getLayerManager().getBlackboard().get(
RANGE_COUNT_KEY,
new Integer(5)));
//Don't add action listeners until items have been added to the
//combo box. [Jon Aquino]
comboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
stylePanel.populateTable();
stylePanel.getLayer().getLayerManager().getBlackboard().put(
RANGE_COUNT_KEY,
comboBox.getSelectedItem());
}
});
panel.add(
label,
new GridBagConstraints(
1,
0,
1,
1,
0,
0,
GridBagConstraints.WEST,
GridBagConstraints.NONE,
new Insets(2, 2, 2, 2),
0,
0));
panel.add(
comboBox,
new GridBagConstraints(
2,
0,
1,
1,
0,
0,
GridBagConstraints.WEST,
GridBagConstraints.NONE,
new Insets(2, 2, 2, 2),
0,
0));
panel.add(
reverseButton,
new GridBagConstraints(
3,
0,
1,
1,
0,
0,
GridBagConstraints.WEST,
GridBagConstraints.NONE,
new Insets(2, 2, 2, 2),
0,
0));
reverseButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
reversingColorScheme = !reversingColorScheme;
stylePanel.applyColorScheme();
}
});
}
private JButton reverseButton = new JButton(I18N.get("ui.renderer.style.RangeColorThemingState.reverse-colors"));
private void addComboBoxItems() {
int maxColorSchemeSize = -1;
for (Iterator i = ColorScheme.rangeColorSchemeNames().iterator();
i.hasNext();
) {
String rangeColorSchemeName = (String) i.next();
maxColorSchemeSize =
Math.max(
maxColorSchemeSize,
ColorScheme
.create(rangeColorSchemeName)
.getColors()
.size());
}
for (int i = 3; i <= maxColorSchemeSize; i++) {
comboBoxModel.addElement(new Integer(i));
}
}
private DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel();
private JComboBox comboBox = new JComboBox(comboBoxModel);
private JLabel label = new JLabel(I18N.get("ui.renderer.style.RangeColorThemingState.range-count"));
public JComponent getPanel() {
return panel;
}
public Map fromExternalFormat(Map attributeValueToObjectMap) {
//Table takes values, not ranges. [Jon Aquino]
TreeMap newMap = new TreeMap();
for (Iterator i = attributeValueToObjectMap.keySet().iterator();
i.hasNext();
) {
Range range = (Range) i.next();
newMap.put(
range.getMin(),
attributeValueToObjectMap.get(range));
}
return newMap;
}
public Map toExternalFormat(Map attributeValueToObjectMap) {
if (attributeValueToObjectMap.isEmpty()) {
return attributeValueToObjectMap;
}
//Turn the values into ranges. Validations have already ensured that
//the values are unique and contain no nulls. [Jon Aquino]
Assert.isTrue(attributeValueToObjectMap instanceof SortedMap);
TreeMap newMap = new Range.RangeTreeMap();
Object previousValue = null;
for (Iterator i = attributeValueToObjectMap.keySet().iterator();
i.hasNext();
) {
Object value = i.next();
try {
if (previousValue == null) {
//Let the default style handle values from negative infinity to
//the first value. [Jon Aquino]
continue;
}
//Make one side inclusive and the other exclusive to ensure no
//overlaps. [Jon Aquino]
newMap.put(
new Range(previousValue, true, value, false),
attributeValueToObjectMap.get(previousValue));
} finally {
previousValue = value;
}
}
newMap.put(
new Range(previousValue, true, new Range.PositiveInfinity(), false),
attributeValueToObjectMap.get(previousValue));
return newMap;
}
public void applyColorScheme(ColorScheme colorScheme) {
stylePanel.tableModel().apply(
new ColorScheme(
null,
CollectionUtil.stretch(
colorScheme.getColors(),
new ArrayList(),
stylePanel.tableModel().getRowCount())),
false);
}
public Collection getColorSchemeNames() {
return ColorScheme.rangeColorSchemeNames();
}
private TableModelListener tableModelListener = new TableModelListener() {
public void tableChanged(TableModelEvent e) {
if (e
instanceof ColorThemingTableModel.AttributeValueTableModelEvent) {
stylePanel.tableModel().sort(stylePanel.tableModel().wasLastSortAscending());
//I'd like to scroll to the row at this point, but the user probably
//finished the edit by clicking on another cell, so even if I scroll
//to the row, it scrolls back to where the user clicked. [Jon Aquino]
}
}
};
private int row(Object attributeValue) {
for (int i = 0; i < stylePanel.tableModel().getRowCount(); i++) {
Object otherAttributeValue =
stylePanel.tableModel().getValueAt(
i,
ColorThemingTableModel.ATTRIBUTE_COLUMN);
if (attributeValue == null && otherAttributeValue == null) {
return i;
}
if (attributeValue != null
&& attributeValue.equals(otherAttributeValue)) {
return i;
}
}
Assert.shouldNeverReachHere();
return -1;
}
public void activate() {
stylePanel.tableModel().addTableModelListener(tableModelListener);
}
public void deactivate() {
stylePanel.tableModel().removeTableModelListener(tableModelListener);
}
private boolean reversingColorScheme = false;
public ColorScheme filterColorScheme(ColorScheme colorScheme) {
if (!reversingColorScheme) {
return colorScheme;
}
List colors = new ArrayList(colorScheme.getColors());
Collections.reverse(colors);
return new ColorScheme(colorScheme.getName(), colors);
}
}