/*
* 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;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.swing.event.TableModelEvent;
import com.vividsolutions.jump.I18N;
import com.vividsolutions.jump.feature.AttributeType;
import com.vividsolutions.jump.util.CollectionUtil;
import com.vividsolutions.jump.workbench.model.Layer;
public class SchemaTableModel extends ColumnBasedTableModel {
public static class Field {
//null name and type means that it's one of the blank fields. Blank fields are
//of course ignored when the changes are committed. [Jon Aquino]
private String name = null;
private AttributeType type = null;
private int originalIndex = -1;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setType(AttributeType type) {
this.type = type;
}
public AttributeType getType() {
return type;
}
public void setOriginalIndex(int originalIndex) {
this.originalIndex = originalIndex;
}
public int getOriginalIndex() {
return originalIndex;
}
}
private ArrayList fields = new ArrayList();
public int getRowCount() {
return fields.size();
}
public List getFields() { return Collections.unmodifiableList(fields); }
public Field get(int row) {
return (Field) fields.get(row);
}
public final static String FIELD_NAME_COLUMN_NAME = I18N.get("ui.SchemaTableModel.field-name");
public final static String DATA_TYPE_COLUMN_NAME = I18N.get("ui.SchemaTableModel.data-type");
public SchemaTableModel(Layer layer) {
this.layer = layer;
for (int i = 0; i < layer.getFeatureCollectionWrapper().getFeatureSchema().getAttributeCount(); i++) {
Field field = new Field();
field.setName(layer.getFeatureCollectionWrapper().getFeatureSchema().getAttributeName(i));
field.setType(layer.getFeatureCollectionWrapper().getFeatureSchema().getAttributeType(i));
field.setOriginalIndex(i);
fields.add(field);
}
addBlankRows();
ArrayList columns = new ArrayList();
columns.add(new Column(FIELD_NAME_COLUMN_NAME, String.class) {
public Object getValueAt(int row) { return get(row).getName(); }
public void setValueAt(Object value, int row) {
if ((value == null || ((String)value).length() == 0) && get(row).getType() == null) {
//User double-clicked on the field but didn't enter anything.
//(Note that the above "if" checks that the type is null too).
//Don't set the name and especially don't set a default value for the type. [Jon Aquino]
return;
}
get(row).setName(((String) value).trim());
if (get(row).getType() == null) {
get(row).setType(AttributeType.STRING);
}
fieldsModified(new int[]{row});
}
});
columns.add(new Column(DATA_TYPE_COLUMN_NAME, AttributeType.class) {
public Object getValueAt(int row) { return get(row).getType(); }
public void setValueAt(Object value, int row) {
if (value == null) {
//User clicked on the combobox, but not on any of the possible values.
//Don't set the type and especially don't set a default value for the name. [Jon Aquino]
return;
}
get(row).setType((AttributeType) value);
if (get(row).getName() == null) {
get(row).setName(createName());
}
fieldsModified(new int[]{row});
}
});
setColumns(columns);
}
private void fieldsModified(int[] rows) {
for (int i = 0; i < rows.length; i++) {
fireTableChanged(new TableModelEvent(this, rows[i]));
addBlankRowsIfNecessary(rows[i]);
}
}
private String createName() {
int i = 1;
while (hasFieldNamed(I18N.get("ui.SchemaTableModel.field")+i)) {
i++;
}
return I18N.get("ui.SchemaTableModel.field")+i;
}
private boolean hasFieldNamed(String name) {
//Existing fields are already trimmed. [Jon Aquino]
for (int i = 0; i < getRowCount(); i++) {
if (get(i).getName() == null) {
//One of the blank rows. [Jon Aquino]
continue;
}
if (get(i).getName().equalsIgnoreCase(name.trim())) {
return true;
}
}
return false;
}
private void addBlankRowsIfNecessary(int indexOfModifiedField) {
if (fields.size() - indexOfModifiedField < BLANK_ROWS) {
int firstRow = fields.size();
addBlankRows();
fireTableChanged(new TableModelEvent(this, firstRow, fields.size()-1));
}
}
private void addBlankRows() {
for (int i = 0; i < BLANK_ROWS; i++) {
fields.add(new Field());
}
}
private final static int BLANK_ROWS = 30;
private Layer layer;
public boolean isCellEditable(int row, int column) {
return layer.isEditable();
}
private void removeField(int row) {
removeFields(new int[]{row});
}
public void removeFields(int[] rows) {
for (Iterator i = CollectionUtil.reverseSortedSet(rows).iterator(); i.hasNext(); ) {
Integer row = (Integer) i.next();
fields.remove(row.intValue());
fieldsModified(rows);
fireTableChanged(new TableModelEvent(this, row.intValue(), row.intValue(), TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE));
}
}
public void removeBlankRows() {
for (Iterator i = fields.iterator(); i.hasNext(); ) {
Field field = (Field) i.next();
if (field.getName() == null) {
//Can't use #removeField because we don't want #addBlankRowsIfNecessary
//to be called. [Jon Aquino]
i.remove();
}
}
}
public void insertBlankRow(int location) {
insertField(location, new Field());
}
private void insertField(int location, Field field) {
fields.add(location, field);
fireTableChanged(new TableModelEvent(this, location, location, TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
fieldsModified(new int[]{location});
}
public void move(Collection fieldsToMove, int displacement) {
for (Iterator i = fieldsToMove.iterator(); i.hasNext();) {
Field field = (Field) i.next();
int index = fields.indexOf(field);
removeField(index);
insertField(index + displacement, field);
}
}
public int indexOf(Field field) {
return fields.indexOf(field);
}
}