/*
* Beryl - A web platform based on XML, XSLT and Java
* This file is part of the Beryl XML GUI
*
* Copyright (C) 2004 Wenzel Jakob <wazlaf@tigris.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-3107 USA
*/
package org.beryl.gui.model;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.beryl.gui.GUIException;
import org.beryl.gui.View;
/**
* Special type of data model which refers to columns using keys instead of indices
*/
public class TableDataModel extends AbstractDataModel implements Serializable {
private ArrayList rows = null;
private RowChangeNotifier notifier = null;
/**
* Since examining a value object using reflection is
* a relatively expensive task, we have a static cache here
* which will store references to the field names and their getters
*/
private static HashMap reflectionInfo = new HashMap();
public static class ReflectionInfo {
public List fieldNames = new ArrayList();
public List fieldMethods = new ArrayList();
};
private class RowChangeNotifier implements ModelChangeListener {
public void modelChanged(ModelChangeEvent e) throws GUIException {
MapChangeEvent event = (MapChangeEvent) e;
int row = rows.indexOf(event.getModel());
if (row != -1) {
TableChangeEvent tce = new TableChangeEvent(e.getSource(), TableDataModel.this, TableChangeEvent.INTERVAL_CHANGED, row, row, event.getKey());
fireModelEvent(tce);
}
}
};
public TableDataModel() {
rows = new ArrayList();
notifier = new RowChangeNotifier();
}
public ReflectionInfo getReflectionInfo(Object object) {
Class objectClass = object.getClass();
ReflectionInfo result = (ReflectionInfo) reflectionInfo.get(objectClass);
if (result == null) {
result = new ReflectionInfo();
Method methods[] = objectClass.getDeclaredMethods();
for (int i=0; i<methods.length; i++) {
String name = methods[i].getName();
if (name.startsWith("get")) {
name = name.substring(3,4).toLowerCase()+name.substring(4);
result.fieldNames.add(name);
result.fieldMethods.add(methods[i]);
}
}
reflectionInfo.put(objectClass, result);
}
return result;
}
public TableDataModel(Set valueObjects) throws GUIException {
this();
addValueObjects(valueObjects);
}
/**
* Clears the data model
*/
public void clear() throws GUIException {
TableChangeEvent event = new TableChangeEvent(null, this, TableChangeEvent.INTERVAL_INSERTED, 0, rows.size(), null);
rows.clear();
fireModelEvent(event);
}
/**
* Add a set of value objects to the table data model
*/
public void addValueObjects(Set valueObjects) throws GUIException {
insertValueObjects(rows.size(), valueObjects);
}
/**
* Insert a set of value objects into the table data model
*/
public void insertValueObjects(int index, Set valueObjects) throws GUIException {
Iterator iterator = valueObjects.iterator();
if (iterator.hasNext()) {
Object valueObject = iterator.next();
ReflectionInfo info = getReflectionInfo(valueObject);
Set valueRows = new LinkedHashSet();
valueRows.add(new ValueObjectTableRow(info, valueObject));
while (iterator.hasNext()) {
valueRows.add(new ValueObjectTableRow(info, iterator.next()));
}
insertRows(null, index, valueRows);
}
}
/**
* Remove a single value object from the table data model
*/
public void removeValueObject(Object valueObject) throws GUIException {
for (int i=0; i<rows.size(); i++) {
Object row = rows.get(i);
if (row instanceof ValueObjectTableRow) {
Object value = ((ValueObjectTableRow) row).getValueObject();
if (valueObject.equals(value)) {
removeRow((TableRow) row);
break;
}
}
}
}
/**
* Remove multiple value objects from the table data model
*/
public void removeValueObjects(Set valueObjects) throws GUIException {
Object objects[] = valueObjects.toArray();
for (int i=0; i<rows.size(); i++) {
Object row = rows.get(i);
if (row instanceof ValueObjectTableRow) {
Object value = ((ValueObjectTableRow) row).getValueObject();
for (int o=0; o<objects.length; o++) {
if (objects[o].equals(value)) {
removeRow((TableRow) row);
break;
}
}
}
}
}
/**
* Add a single value object to the table data model
*/
public void addValueObject(Object valueObject) throws GUIException {
insertValueObject(rows.size(), valueObject);
}
/**
* Create a value object table row
*/
public ValueObjectTableRow createValueObjectTableRow(Object valueObject) throws GUIException {
return new ValueObjectTableRow(getReflectionInfo(valueObject), valueObject);
}
/**
* Insert a single value object into the table data model
*/
public void insertValueObject(int index, Object valueObject) throws GUIException {
insertRow(index, createValueObjectTableRow(valueObject));
}
public Object getValue(int row, String key) {
return ((TableRow)rows.get(row)).getValue(key);
}
public void setValue(int row, String key, Object value) throws GUIException {
((TableRow)rows.get(row)).setValue(key, value);
}
public boolean isEditable(int row, String key) {
return ((TableRow)rows.get(row)).isEditable(key);
}
public void addRow(TableRow tableRow) throws GUIException {
insertRow(null, rows.size(), tableRow);
}
public void addRow(View view, TableRow tableRow) throws GUIException {
insertRow(view, rows.size(), tableRow);
}
public void addRows(View view, Set tableRows) throws GUIException {
insertRows(view, rows.size(), tableRows);
}
public void insertRow(int index, TableRow tableRow) throws GUIException {
insertRow(null, index, tableRow);
}
public void insertRow(View view, int index, TableRow tableRow) throws GUIException {
TableChangeEvent event = new TableChangeEvent(view, this, TableChangeEvent.INTERVAL_INSERTED, index, index, null);
tableRow.addModelChangeListener(notifier);
rows.add(index, tableRow);
fireModelEvent(event);
}
public void insertRows(View view, int index, Set tableRows) throws GUIException {
TableChangeEvent event = new TableChangeEvent(view, this, TableChangeEvent.INTERVAL_INSERTED, index, index+tableRows.size(), null);
for (Iterator i=tableRows.iterator(); i.hasNext();)
((TableRow) i.next()).addModelChangeListener(notifier);
rows.addAll(index, tableRows);
fireModelEvent(event);
}
public void removeRow(int index) throws GUIException {
removeRow(null, index);
}
public void removeRow(View view, int index) throws GUIException {
TableRow tableRow = (TableRow) rows.get(index);
TableChangeEvent event = new TableChangeEvent(view, this, TableChangeEvent.INTERVAL_REMOVED, index, index, null);
tableRow.removeModelChangeListener(notifier);
rows.remove(index);
fireModelEvent(event);
}
public void removeRow(TableRow tableRow) throws GUIException {
removeRow(null, tableRow);
}
public void removeRow(View view, TableRow tableRow) throws GUIException {
int index = rows.indexOf(tableRow);
if (index != -1) {
TableChangeEvent event = new TableChangeEvent(view, this, TableChangeEvent.INTERVAL_REMOVED, index, index, null);
tableRow.removeModelChangeListener(notifier);
rows.remove(index);
fireModelEvent(event);
} else {
throw new GUIException("Row could not be found");
}
}
public ArrayList getRows() {
return rows;
}
public int getRowCount() {
return rows.size();
}
public int getRowIndex(TableRow row) {
return rows.indexOf(row);
}
public TableRow getTableRow(int row) {
return (TableRow) rows.get(row);
}
public int indexOf(TableRow tableRow) {
return rows.indexOf(tableRow);
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("org.beryl.gui.TableDataModel [\n");
for (int i=0; i<rows.size(); i++) {
TableRow row = (TableRow) rows.get(i);
buf.append(" ").append(i).append(" : ");
buf.append(row.toString()).append("\n");
}
buf.append("]");
return buf.toString();
}
}