001: /*
002: * Beryl - A web platform based on XML, XSLT and Java
003: * This file is part of the Beryl XML GUI
004: *
005: * Copyright (C) 2004 Wenzel Jakob <wazlaf@tigris.org>
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 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 GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-3107 USA
020: */
021:
022: package org.beryl.gui.model;
023:
024: import java.io.Serializable;
025: import java.lang.reflect.Method;
026: import java.util.ArrayList;
027: import java.util.HashMap;
028: import java.util.Iterator;
029: import java.util.LinkedHashSet;
030: import java.util.List;
031: import java.util.Set;
032:
033: import org.beryl.gui.GUIException;
034: import org.beryl.gui.View;
035:
036: /**
037: * Special type of data model which refers to columns using keys instead of indices
038: */
039:
040: public class TableDataModel extends AbstractDataModel implements
041: Serializable {
042: private ArrayList rows = null;
043: private RowChangeNotifier notifier = null;
044:
045: /**
046: * Since examining a value object using reflection is
047: * a relatively expensive task, we have a static cache here
048: * which will store references to the field names and their getters
049: */
050: private static HashMap reflectionInfo = new HashMap();
051:
052: public static class ReflectionInfo {
053: public List fieldNames = new ArrayList();
054: public List fieldMethods = new ArrayList();
055: };
056:
057: private class RowChangeNotifier implements ModelChangeListener {
058: public void modelChanged(ModelChangeEvent e)
059: throws GUIException {
060: MapChangeEvent event = (MapChangeEvent) e;
061:
062: int row = rows.indexOf(event.getModel());
063: if (row != -1) {
064: TableChangeEvent tce = new TableChangeEvent(e
065: .getSource(), TableDataModel.this ,
066: TableChangeEvent.INTERVAL_CHANGED, row, row,
067: event.getKey());
068: fireModelEvent(tce);
069: }
070: }
071: };
072:
073: public TableDataModel() {
074: rows = new ArrayList();
075: notifier = new RowChangeNotifier();
076: }
077:
078: public ReflectionInfo getReflectionInfo(Object object) {
079: Class objectClass = object.getClass();
080: ReflectionInfo result = (ReflectionInfo) reflectionInfo
081: .get(objectClass);
082:
083: if (result == null) {
084: result = new ReflectionInfo();
085:
086: Method methods[] = objectClass.getDeclaredMethods();
087: for (int i = 0; i < methods.length; i++) {
088: String name = methods[i].getName();
089: if (name.startsWith("get")) {
090: name = name.substring(3, 4).toLowerCase()
091: + name.substring(4);
092: result.fieldNames.add(name);
093: result.fieldMethods.add(methods[i]);
094: }
095: }
096:
097: reflectionInfo.put(objectClass, result);
098: }
099:
100: return result;
101: }
102:
103: public TableDataModel(Set valueObjects) throws GUIException {
104: this ();
105: addValueObjects(valueObjects);
106: }
107:
108: /**
109: * Clears the data model
110: */
111: public void clear() throws GUIException {
112: TableChangeEvent event = new TableChangeEvent(null, this ,
113: TableChangeEvent.INTERVAL_INSERTED, 0, rows.size(),
114: null);
115: rows.clear();
116: fireModelEvent(event);
117: }
118:
119: /**
120: * Add a set of value objects to the table data model
121: */
122: public void addValueObjects(Set valueObjects) throws GUIException {
123: insertValueObjects(rows.size(), valueObjects);
124: }
125:
126: /**
127: * Insert a set of value objects into the table data model
128: */
129: public void insertValueObjects(int index, Set valueObjects)
130: throws GUIException {
131: Iterator iterator = valueObjects.iterator();
132: if (iterator.hasNext()) {
133: Object valueObject = iterator.next();
134: ReflectionInfo info = getReflectionInfo(valueObject);
135:
136: Set valueRows = new LinkedHashSet();
137: valueRows.add(new ValueObjectTableRow(info, valueObject));
138:
139: while (iterator.hasNext()) {
140: valueRows.add(new ValueObjectTableRow(info, iterator
141: .next()));
142: }
143:
144: insertRows(null, index, valueRows);
145: }
146: }
147:
148: /**
149: * Remove a single value object from the table data model
150: */
151: public void removeValueObject(Object valueObject)
152: throws GUIException {
153: for (int i = 0; i < rows.size(); i++) {
154: Object row = rows.get(i);
155: if (row instanceof ValueObjectTableRow) {
156: Object value = ((ValueObjectTableRow) row)
157: .getValueObject();
158:
159: if (valueObject.equals(value)) {
160: removeRow((TableRow) row);
161: break;
162: }
163: }
164: }
165: }
166:
167: /**
168: * Remove multiple value objects from the table data model
169: */
170: public void removeValueObjects(Set valueObjects)
171: throws GUIException {
172: Object objects[] = valueObjects.toArray();
173:
174: for (int i = 0; i < rows.size(); i++) {
175: Object row = rows.get(i);
176: if (row instanceof ValueObjectTableRow) {
177: Object value = ((ValueObjectTableRow) row)
178: .getValueObject();
179: for (int o = 0; o < objects.length; o++) {
180: if (objects[o].equals(value)) {
181: removeRow((TableRow) row);
182: break;
183: }
184: }
185: }
186: }
187: }
188:
189: /**
190: * Add a single value object to the table data model
191: */
192: public void addValueObject(Object valueObject) throws GUIException {
193: insertValueObject(rows.size(), valueObject);
194: }
195:
196: /**
197: * Create a value object table row
198: */
199: public ValueObjectTableRow createValueObjectTableRow(
200: Object valueObject) throws GUIException {
201: return new ValueObjectTableRow(getReflectionInfo(valueObject),
202: valueObject);
203: }
204:
205: /**
206: * Insert a single value object into the table data model
207: */
208: public void insertValueObject(int index, Object valueObject)
209: throws GUIException {
210: insertRow(index, createValueObjectTableRow(valueObject));
211: }
212:
213: public Object getValue(int row, String key) {
214: return ((TableRow) rows.get(row)).getValue(key);
215: }
216:
217: public void setValue(int row, String key, Object value)
218: throws GUIException {
219: ((TableRow) rows.get(row)).setValue(key, value);
220: }
221:
222: public boolean isEditable(int row, String key) {
223: return ((TableRow) rows.get(row)).isEditable(key);
224: }
225:
226: public void addRow(TableRow tableRow) throws GUIException {
227: insertRow(null, rows.size(), tableRow);
228: }
229:
230: public void addRow(View view, TableRow tableRow)
231: throws GUIException {
232: insertRow(view, rows.size(), tableRow);
233: }
234:
235: public void addRows(View view, Set tableRows) throws GUIException {
236: insertRows(view, rows.size(), tableRows);
237: }
238:
239: public void insertRow(int index, TableRow tableRow)
240: throws GUIException {
241: insertRow(null, index, tableRow);
242: }
243:
244: public void insertRow(View view, int index, TableRow tableRow)
245: throws GUIException {
246: TableChangeEvent event = new TableChangeEvent(view, this ,
247: TableChangeEvent.INTERVAL_INSERTED, index, index, null);
248: tableRow.addModelChangeListener(notifier);
249: rows.add(index, tableRow);
250: fireModelEvent(event);
251: }
252:
253: public void insertRows(View view, int index, Set tableRows)
254: throws GUIException {
255: TableChangeEvent event = new TableChangeEvent(view, this ,
256: TableChangeEvent.INTERVAL_INSERTED, index, index
257: + tableRows.size(), null);
258: for (Iterator i = tableRows.iterator(); i.hasNext();)
259: ((TableRow) i.next()).addModelChangeListener(notifier);
260: rows.addAll(index, tableRows);
261: fireModelEvent(event);
262: }
263:
264: public void removeRow(int index) throws GUIException {
265: removeRow(null, index);
266: }
267:
268: public void removeRow(View view, int index) throws GUIException {
269: TableRow tableRow = (TableRow) rows.get(index);
270: TableChangeEvent event = new TableChangeEvent(view, this ,
271: TableChangeEvent.INTERVAL_REMOVED, index, index, null);
272: tableRow.removeModelChangeListener(notifier);
273: rows.remove(index);
274: fireModelEvent(event);
275: }
276:
277: public void removeRow(TableRow tableRow) throws GUIException {
278: removeRow(null, tableRow);
279: }
280:
281: public void removeRow(View view, TableRow tableRow)
282: throws GUIException {
283: int index = rows.indexOf(tableRow);
284:
285: if (index != -1) {
286: TableChangeEvent event = new TableChangeEvent(view, this ,
287: TableChangeEvent.INTERVAL_REMOVED, index, index,
288: null);
289: tableRow.removeModelChangeListener(notifier);
290: rows.remove(index);
291: fireModelEvent(event);
292: } else {
293: throw new GUIException("Row could not be found");
294: }
295: }
296:
297: public ArrayList getRows() {
298: return rows;
299: }
300:
301: public int getRowCount() {
302: return rows.size();
303: }
304:
305: public int getRowIndex(TableRow row) {
306: return rows.indexOf(row);
307: }
308:
309: public TableRow getTableRow(int row) {
310: return (TableRow) rows.get(row);
311: }
312:
313: public int indexOf(TableRow tableRow) {
314: return rows.indexOf(tableRow);
315: }
316:
317: public String toString() {
318: StringBuffer buf = new StringBuffer();
319: buf.append("org.beryl.gui.TableDataModel [\n");
320: for (int i = 0; i < rows.size(); i++) {
321: TableRow row = (TableRow) rows.get(i);
322: buf.append(" ").append(i).append(" : ");
323: buf.append(row.toString()).append("\n");
324: }
325: buf.append("]");
326: return buf.toString();
327: }
328: }
|