/*
* 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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.swing.event.TableModelEvent;
import javax.swing.table.TableModel;
import com.vividsolutions.jump.I18N;
import com.vividsolutions.jump.feature.FeatureSchema;
import com.vividsolutions.jump.util.Block;
import com.vividsolutions.jump.util.CollectionUtil;
import com.vividsolutions.jump.util.ImmutableFirstElementList;
import com.vividsolutions.jump.workbench.ui.ColumnBasedTableModel;
public class ColorThemingTableModel extends ColumnBasedTableModel {
BasicStyle defaultStyle;
public ColorThemingTableModel(
BasicStyle defaultStyle,
String attributeName,
Map attributeValueToBasicStyleMap,
Map attributeValueToLabelMap,
FeatureSchema schema) {
//Value doesn't matter. [Jon Aquino]
this.defaultStyle = defaultStyle;
attributeMappings =
new ImmutableFirstElementList(
new AttributeMapping(null, defaultStyle, null));
this.attributeName = attributeName;
setMaps(attributeValueToBasicStyleMap, attributeValueToLabelMap);
setColumns(createColumns(schema));
}
public static final int COLOR_COLUMN = 0;
public static final int ATTRIBUTE_COLUMN = 1;
public static final int LABEL_COLUMN = 2;
public void setMaps(Map attributeValueToBasicStyleMap, Map attributeValueToLabelMap) {
attributeMappings.clear();
for (Iterator i = attributeValueToBasicStyleMap.keySet().iterator(); i.hasNext();) {
Object attributeValue = i.next();
attributeMappings.add(
new AttributeMapping(
attributeValue,
(BasicStyle) attributeValueToBasicStyleMap.get(attributeValue),
(String) attributeValueToLabelMap.get(attributeValue)));
}
fireTableChanged(new TableModelEvent(this));
}
protected static class AttributeMapping implements Comparable {
private String label;
public AttributeMapping(Object attributeValue, BasicStyle basicStyle, String label) {
this.attributeValue = attributeValue;
this.basicStyle = basicStyle;
this.label = label;
}
private Object attributeValue;
private BasicStyle basicStyle;
public Object getAttributeValue() {
return attributeValue;
}
public BasicStyle getBasicStyle() {
return basicStyle;
}
public int compareTo(Object o) {
AttributeMapping other = (AttributeMapping) o;
if (attributeValue == null) {
return -1;
}
if (other.attributeValue == null) {
return 1;
}
return ((Comparable) attributeValue).compareTo(
(Comparable) other.attributeValue);
}
public void setAttributeValue(Object object) {
attributeValue = object;
}
public void setBasicStyle(BasicStyle style) {
basicStyle = style;
}
protected String getLabel() {
return label;
}
protected void setLabel(String label) {
this.label = label;
}
}
public void clear() {
attributeMappings.clear();
fireTableChanged(new TableModelEvent(this));
}
public boolean containsNullAttributeValues() {
for (Iterator i = nonDefaultAttributeMappings().iterator();
i.hasNext();
) {
AttributeMapping attributeMapping = (AttributeMapping) i.next();
if (attributeMapping.getAttributeValue() == null) {
return true;
}
}
return false;
}
protected AttributeMapping attributeMapping(int i) {
return (AttributeMapping) attributeMappings.get(i);
}
public BasicStyle getDefaultStyle() {
return attributeMapping(0).getBasicStyle();
}
public Object findDuplicateAttributeValue() {
TreeSet set = new TreeSet();
for (Iterator i = nonDefaultAttributeMappings().iterator();
i.hasNext();
) {
AttributeMapping attributeMapping = (AttributeMapping) i.next();
if (attributeMapping.getAttributeValue() == null) {
//Check nulls elsewhere. TreeSet won't accept nulls. [Jon Aquino]
continue;
}
if (set.contains(attributeMapping.getAttributeValue())) {
return attributeMapping.getAttributeValue();
}
set.add(attributeMapping.getAttributeValue());
}
return null;
}
//Can't use TreeMap because attributes may not be unique (this is
//an invalid state of course and we won't let the user hit OK until he
//resolves it). Can't use HashMap because Geometry doesn't implement
//#hash. [Jon Aquino]
protected List attributeMappings;
protected List createColumns(final FeatureSchema schema) {
ArrayList columns = new ArrayList();
columns.add(new Column(I18N.get("ui.renderer.style.ColorThemingTableModel.attribute-value"), BasicStyle.class) {
public Object getValueAt(int rowIndex) {
return attributeMapping(rowIndex).getBasicStyle();
}
public void setValueAt(Object value, int rowIndex) {
attributeMapping(rowIndex).setBasicStyle((BasicStyle) value);
fireTableChanged(
new TableModelEvent(ColorThemingTableModel.this, rowIndex));
}
});
columns.add(new Column(I18N.get("ui.renderer.style.ColorThemingTableModel.attribute-value"), null) {
public Class getDataClass() {
//attributeName will be null if layer has no non-spatial attributes
//[Jon Aquino]
//attributeName will not be present in the schema if the user
//has deleted this attribute. [Jon Aquino]
return attributeName == null
|| !schema.hasAttribute(attributeName)
? Object.class
: schema.getAttributeType(attributeName).toJavaClass();
}
public Object getValueAt(int rowIndex) {
return attributeMapping(rowIndex).getAttributeValue();
}
public void setValueAt(Object value, int rowIndex) {
attributeMapping(rowIndex).setAttributeValue(value);
//The validators need to know that the table has changed. [Jon Aquino]
fireTableChanged(
new AttributeValueTableModelEvent(
ColorThemingTableModel.this,
rowIndex));
}
});
columns.add(new Column("Label", String.class) {
public Object getValueAt(int rowIndex) {
return attributeMapping(rowIndex).getLabel();
}
public void setValueAt(Object value, int rowIndex) {
attributeMapping(rowIndex).setLabel((String) value);
fireTableChanged(
new AttributeValueTableModelEvent(
ColorThemingTableModel.this,
rowIndex));
}
});
return columns;
}
public static class AttributeValueTableModelEvent extends TableModelEvent {
public AttributeValueTableModelEvent(TableModel source, int row) {
super(source, row);
}
}
public void apply(
ColorScheme colorScheme,
boolean skipDefaultAttributeMapping) {
//Leave the first element out of the sort, because it's the "(All other values)"
//element. [Jon Aquino]
for (Iterator i =
(skipDefaultAttributeMapping
? nonDefaultAttributeMappings()
: attributeMappings)
.iterator();
i.hasNext();
) {
AttributeMapping attributeMapping = (AttributeMapping) i.next();
BasicStyle newBasicStyle = new BasicStyle(colorScheme.next());
newBasicStyle.setLineWidth(defaultStyle.getLineWidth());
newBasicStyle.setRenderingLine(defaultStyle.isRenderingLine());
newBasicStyle.setLinePattern(defaultStyle.getLinePattern());
newBasicStyle.setRenderingFill(defaultStyle.isRenderingFill());
newBasicStyle.setFillPattern(defaultStyle.getFillPattern());
//newBasicStyle.setRenderingVertices(defaultStyle.getRenderingVertices());
attributeMapping.setBasicStyle(/*new BasicStyle(colorScheme.next())*/newBasicStyle);
}
fireTableChanged(new TableModelEvent(this));
}
public int getRowCount() {
return attributeMappings.size();
}
public void setAttributeName(String attributeName) {
this.attributeName = attributeName;
}
public Map getAttributeValueToBasicStyleMap() {
return attributeValueToObjectMap(new Block(){
public Object yield(Object attributeMapping) {
return ((AttributeMapping)attributeMapping).getBasicStyle();
}
});
}
public Map getAttributeValueToLabelMap() {
return attributeValueToObjectMap(new Block(){
public Object yield(Object attributeMapping) {
return ((AttributeMapping)attributeMapping).getLabel();
}
});
}
private Map attributeValueToObjectMap(Block getter) {
TreeMap attributeValueToObjectMap = new TreeMap();
//Skip the first element, which is the default style. [Jon Aquino]
for (Iterator i = nonDefaultAttributeMappings().iterator();
i.hasNext();
) {
AttributeMapping attributeMapping = (AttributeMapping) i.next();
attributeValueToObjectMap.put(
attributeMapping.getAttributeValue(),
getter.yield(attributeMapping));
}
return attributeValueToObjectMap;
}
private boolean lastSortAscending = true;
public boolean wasLastSortAscending() {
return lastSortAscending;
}
public void sort() {
sort(!lastSortAscending);
}
public void sort(boolean ascending) {
//Leave the first element out of the sort, because it's the "(All other values)"
//element. [Jon Aquino]
if (ascending) {
Collections.sort(nonDefaultAttributeMappings());
} else {
Collections.sort(
nonDefaultAttributeMappings(),
Collections.reverseOrder());
}
lastSortAscending = ascending;
fireTableChanged(new TableModelEvent(this));
}
public void removeAttributeValues(int[] rows) {
for (Iterator i = CollectionUtil.reverseSortedSet(rows).iterator();
i.hasNext();
) {
Integer row = (Integer) i.next();
attributeMappings.remove(row.intValue());
fireTableChanged(
new TableModelEvent(
this,
row.intValue(),
row.intValue(),
TableModelEvent.ALL_COLUMNS,
TableModelEvent.DELETE));
}
}
/**
* @return row
*/
public int insertAttributeValue(int row, ColorScheme colorScheme) {
BasicStyle newBasicStyle = new BasicStyle(colorScheme.next());
newBasicStyle.setLineWidth(defaultStyle.getLineWidth());
newBasicStyle.setRenderingLine(defaultStyle.isRenderingLine());
newBasicStyle.setLinePattern(defaultStyle.getLinePattern());
newBasicStyle.setRenderingFill(defaultStyle.isRenderingFill());
newBasicStyle.setFillPattern(defaultStyle.getFillPattern());
//newBasicStyle.setRenderingVertices(defaultStyle.getRenderingVertices());
attributeMappings.add(
row,
new AttributeMapping(null, /*new BasicStyle(colorScheme.next())*/newBasicStyle, ""));
fireTableChanged(
new TableModelEvent(
this,
row,
row,
TableModelEvent.ALL_COLUMNS,
TableModelEvent.INSERT));
return row;
}
protected String attributeName;
public boolean isCellEditable(int rowIndex, int columnIndex) {
//Any cell except the one that says "(All other values)" [Jon Aquino]
if (rowIndex == 0 && columnIndex == ATTRIBUTE_COLUMN) { return false;}
if (rowIndex == 0 && columnIndex == LABEL_COLUMN) { return false;}
return true;
}
protected List nonDefaultAttributeMappings() {
return attributeMappings.subList(1, attributeMappings.size());
}
}