001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
003: * for visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions
024: * Suite #1A
025: * 2328 Government Street
026: * Victoria BC V8T 5G5
027: * Canada
028: *
029: * (250)385-6040
030: * www.vividsolutions.com
031: */
032:
033: package com.vividsolutions.jump.workbench.ui;
034:
035: import java.util.ArrayList;
036: import java.util.Collection;
037: import java.util.Collections;
038: import java.util.Iterator;
039: import java.util.List;
040:
041: import javax.swing.event.TableModelEvent;
042:
043: import com.vividsolutions.jump.I18N;
044: import com.vividsolutions.jump.feature.AttributeType;
045: import com.vividsolutions.jump.util.CollectionUtil;
046: import com.vividsolutions.jump.workbench.model.Layer;
047:
048: public class SchemaTableModel extends ColumnBasedTableModel {
049:
050: public static class Field {
051: //null name and type means that it's one of the blank fields. Blank fields are
052: //of course ignored when the changes are committed. [Jon Aquino]
053: private String name = null;
054: private AttributeType type = null;
055: private int originalIndex = -1;
056:
057: public void setName(String name) {
058: this .name = name;
059: }
060:
061: public String getName() {
062: return name;
063: }
064:
065: public void setType(AttributeType type) {
066: this .type = type;
067: }
068:
069: public AttributeType getType() {
070: return type;
071: }
072:
073: public void setOriginalIndex(int originalIndex) {
074: this .originalIndex = originalIndex;
075: }
076:
077: public int getOriginalIndex() {
078: return originalIndex;
079: }
080: }
081:
082: private ArrayList fields = new ArrayList();
083:
084: public int getRowCount() {
085: return fields.size();
086: }
087:
088: public List getFields() {
089: return Collections.unmodifiableList(fields);
090: }
091:
092: public Field get(int row) {
093: return (Field) fields.get(row);
094: }
095:
096: public final static String FIELD_NAME_COLUMN_NAME = I18N
097: .get("ui.SchemaTableModel.field-name");
098: public final static String DATA_TYPE_COLUMN_NAME = I18N
099: .get("ui.SchemaTableModel.data-type");
100:
101: public SchemaTableModel(Layer layer) {
102: this .layer = layer;
103: for (int i = 0; i < layer.getFeatureCollectionWrapper()
104: .getFeatureSchema().getAttributeCount(); i++) {
105: Field field = new Field();
106: field.setName(layer.getFeatureCollectionWrapper()
107: .getFeatureSchema().getAttributeName(i));
108: field.setType(layer.getFeatureCollectionWrapper()
109: .getFeatureSchema().getAttributeType(i));
110: field.setOriginalIndex(i);
111: fields.add(field);
112: }
113: addBlankRows();
114: ArrayList columns = new ArrayList();
115: columns.add(new Column(FIELD_NAME_COLUMN_NAME, String.class) {
116: public Object getValueAt(int row) {
117: return get(row).getName();
118: }
119:
120: public void setValueAt(Object value, int row) {
121: if ((value == null || ((String) value).length() == 0)
122: && get(row).getType() == null) {
123: //User double-clicked on the field but didn't enter anything.
124: //(Note that the above "if" checks that the type is null too).
125: //Don't set the name and especially don't set a default value for the type. [Jon Aquino]
126: return;
127: }
128: get(row).setName(((String) value).trim());
129: if (get(row).getType() == null) {
130: get(row).setType(AttributeType.STRING);
131: }
132: fieldsModified(new int[] { row });
133: }
134: });
135: columns.add(new Column(DATA_TYPE_COLUMN_NAME,
136: AttributeType.class) {
137: public Object getValueAt(int row) {
138: return get(row).getType();
139: }
140:
141: public void setValueAt(Object value, int row) {
142: if (value == null) {
143: //User clicked on the combobox, but not on any of the possible values.
144: //Don't set the type and especially don't set a default value for the name. [Jon Aquino]
145: return;
146: }
147: get(row).setType((AttributeType) value);
148: if (get(row).getName() == null) {
149: get(row).setName(createName());
150: }
151: fieldsModified(new int[] { row });
152: }
153: });
154: setColumns(columns);
155: }
156:
157: private void fieldsModified(int[] rows) {
158: for (int i = 0; i < rows.length; i++) {
159: fireTableChanged(new TableModelEvent(this , rows[i]));
160: addBlankRowsIfNecessary(rows[i]);
161: }
162: }
163:
164: private String createName() {
165: int i = 1;
166: while (hasFieldNamed(I18N.get("ui.SchemaTableModel.field") + i)) {
167: i++;
168: }
169: return I18N.get("ui.SchemaTableModel.field") + i;
170: }
171:
172: private boolean hasFieldNamed(String name) {
173: //Existing fields are already trimmed. [Jon Aquino]
174: for (int i = 0; i < getRowCount(); i++) {
175: if (get(i).getName() == null) {
176: //One of the blank rows. [Jon Aquino]
177: continue;
178: }
179: if (get(i).getName().equalsIgnoreCase(name.trim())) {
180: return true;
181: }
182: }
183: return false;
184: }
185:
186: private void addBlankRowsIfNecessary(int indexOfModifiedField) {
187: if (fields.size() - indexOfModifiedField < BLANK_ROWS) {
188: int firstRow = fields.size();
189: addBlankRows();
190: fireTableChanged(new TableModelEvent(this , firstRow, fields
191: .size() - 1));
192: }
193: }
194:
195: private void addBlankRows() {
196: for (int i = 0; i < BLANK_ROWS; i++) {
197: fields.add(new Field());
198: }
199: }
200:
201: private final static int BLANK_ROWS = 30;
202:
203: private Layer layer;
204:
205: public boolean isCellEditable(int row, int column) {
206: return layer.isEditable();
207: }
208:
209: private void removeField(int row) {
210: removeFields(new int[] { row });
211: }
212:
213: public void removeFields(int[] rows) {
214: for (Iterator i = CollectionUtil.reverseSortedSet(rows)
215: .iterator(); i.hasNext();) {
216: Integer row = (Integer) i.next();
217: fields.remove(row.intValue());
218: fieldsModified(rows);
219: fireTableChanged(new TableModelEvent(this , row.intValue(),
220: row.intValue(), TableModelEvent.ALL_COLUMNS,
221: TableModelEvent.DELETE));
222: }
223: }
224:
225: public void removeBlankRows() {
226: for (Iterator i = fields.iterator(); i.hasNext();) {
227: Field field = (Field) i.next();
228: if (field.getName() == null) {
229: //Can't use #removeField because we don't want #addBlankRowsIfNecessary
230: //to be called. [Jon Aquino]
231: i.remove();
232: }
233: }
234: }
235:
236: public void insertBlankRow(int location) {
237: insertField(location, new Field());
238: }
239:
240: private void insertField(int location, Field field) {
241: fields.add(location, field);
242: fireTableChanged(new TableModelEvent(this , location, location,
243: TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
244: fieldsModified(new int[] { location });
245: }
246:
247: public void move(Collection fieldsToMove, int displacement) {
248: for (Iterator i = fieldsToMove.iterator(); i.hasNext();) {
249: Field field = (Field) i.next();
250: int index = fields.indexOf(field);
251: removeField(index);
252: insertField(index + displacement, field);
253: }
254: }
255:
256: public int indexOf(Field field) {
257: return fields.indexOf(field);
258: }
259:
260: }
|