package org.freehep.util.parameterdatabase;
import java.awt.BorderLayout;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Constructor;
import java.util.Iterator;
import java.util.LinkedList;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import org.freehep.swing.CellOrientatedTable;
import org.freehep.util.parameterdatabase.editor.DoubleRangeEditor;
import org.freehep.util.parameterdatabase.editor.SelectorEditor;
import org.freehep.util.parameterdatabase.selector.Selector;
import org.freehep.util.parameterdatabase.types.DoubleRange;
public class DatabaseTable implements TableModel, DatabaseListener {
private JComponent table;
/**
* The object used as the key into the database. Actually here this will be
* used to generate a ClassIterator which will be used to search the
* database.
*/
private Object key = null;
/**
* The flag indicating whether or not the local column is shown. The two
* forms of the table are obtained with a trick--we just add one to the
* column index if there is no local column.
*/
private boolean local;
/**
* The ClassIterator derived from the key object.
*/
private ClassIterator classIterator = null;
/**
* An array containing a sorted list of names.
*/
private String[] names = null;
/**
* The database which will be searched for parameters.
*/
ParameterDatabase database;
/**
* The list of TableModelListeners.
*/
protected LinkedList tableModelListeners = new LinkedList();
/**
* Create a new table to view the parameters in the database.
*/
public DatabaseTable(ParameterDatabase database) {
this(database, true);
}
/**
* Create a new table to view the parameters in the database. If local is
* true, then this table will show a "local variable" column. If it is
* false, then the "local variable" column is omitted.
*/
public DatabaseTable(ParameterDatabase database, boolean local) {
if (database == null)
throw new IllegalArgumentException();
this.local = local;
this.database = database;
table = makeForm();
}
/**
* Return a reference to the JComponent which contains the table.
*/
public JComponent getForm() {
return table;
}
/**
* Set the object used to search the parameter database.
*/
public void setKeyObject(Object key) {
if (this.key != key) {
this.key = key;
if (key != null) {
// Make the ClassIterator for this object.
classIterator = new ClassIterator(key);
// Now we must remake the list of names.
names = database.getCurrentParameterSet(classIterator);
} else {
classIterator = null;
names = null;
}
fireTableChanged();
}
}
/**
* This is called when any parameter of the database is changed. It is
* important when a parameter is updated programatically so that the user
* interface reflects the current state of the database.
*/
public void databaseUpdated() {
fireTableChanged();
}
public void fireTableChanged() {
// Create the table change event.
TableModelEvent event = new TableModelEvent(this);
// Notify all of the listeners.
Iterator iterator = tableModelListeners.iterator();
while (iterator.hasNext()) {
TableModelListener listener = (TableModelListener) iterator.next();
listener.tableChanged(event);
}
}
private JComponent makeForm() {
// Make an overall JPanel to hold everything.
JPanel main = new JPanel();
main.setLayout(new BorderLayout());
// Make a table with this as its table model.
JTable table = new CellOrientatedTable(this);
table.setDefaultEditor(Selector.class, new SelectorEditor());
table.setDefaultEditor(DoubleRange.class, new DoubleRangeEditor());
JScrollPane scroll = new JScrollPane(table);
main.add(scroll, BorderLayout.CENTER);
return main;
}
public void addTableModelListener(TableModelListener listener) {
if (listener != null)
tableModelListeners.add(listener);
}
public void removeTableModelListener(TableModelListener listener) {
tableModelListeners.remove(listener);
}
public Class getColumnClass(int columnIndex) {
if (!local)
columnIndex++;
Class columnClass;
switch (columnIndex) {
case (0):
columnClass = Boolean.class;
break;
case (1):
columnClass = String.class;
break;
case (2):
columnClass = Object.class;
break;
default:
columnClass = null;
break;
}
return columnClass;
}
public int getColumnCount() {
return (local) ? 3 : 2;
}
public String getColumnName(int columnIndex) {
if (!local)
columnIndex++;
String columnName;
switch (columnIndex) {
case (0):
columnName = "Local";
break;
case (1):
columnName = "Parameter";
break;
case (2):
columnName = "Value";
break;
default:
columnName = null;
break;
}
return columnName;
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
if (local) {
return (columnIndex == 0 || columnIndex == 2) ? true : false;
} else {
return (columnIndex == 1);
}
}
public int getRowCount() {
// The number of rows is just equal to the number of parameter names
// in the list.
return (names != null) ? names.length : 0;
}
public Object getValueAt(int rowIndex, int columnIndex) {
if (!local)
columnIndex++;
if (columnIndex == 0) {
classIterator.reset();
String name = names[rowIndex];
if (database.isParameterLocal(name, classIterator)) {
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
} else if (columnIndex == 1) {
return names[rowIndex];
} else if (columnIndex == 2) {
classIterator.reset();
String name = names[rowIndex];
return database.getParameter(name, classIterator);
} else {
return null;
}
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
// We need to be a bit careful with this "local" column trick here. We
// reuse the column index to pass back into getValueAt(), so we need
// to keep a local copy of columnIndex.
int cIndex = columnIndex;
if (!local)
cIndex++;
if (cIndex == 0 && (aValue instanceof Boolean)) {
boolean makeLocal = ((Boolean) aValue).booleanValue();
if (makeLocal) {
String name = names[rowIndex];
Object value = getValueAt(rowIndex, 2);
if (value != null) {
Object firstObject = null;
classIterator.reset();
if (classIterator.hasNext()) {
firstObject = classIterator.next();
}
PropertyChangeListener listener = null;
if (firstObject instanceof PropertyChangeListener) {
listener = (PropertyChangeListener) firstObject;
}
classIterator.reset();
database.addParameter(name, value, classIterator, listener);
}
} else {
String name = names[rowIndex];
classIterator.reset();
database.removeParameter(name, classIterator);
}
}
if (cIndex == 2) {
String name = names[rowIndex];
Object object = getValueAt(rowIndex, columnIndex);
Class c = object.getClass();
if (c.equals(aValue.getClass())) {
// Check to see if the new value is of the same type as the
// old value. If so, just set the parameter in the database.
classIterator.reset();
database.setParameter(name, aValue, classIterator);
} else if (aValue instanceof String) {
// Here we try to reconstruct the object itself from a
// constructor which takes a String.
String value = (String) aValue;
if (object != null) {
Object[] parameters = new Object[1];
parameters[0] = value;
Class[] parameterTypes = new Class[1];
parameterTypes[0] = String.class;
try {
Class objectClass = object.getClass();
Constructor constructor = objectClass
.getConstructor(parameterTypes);
Object newValue = constructor.newInstance(parameters);
classIterator.reset();
database.setParameter(name, newValue, classIterator);
} catch (NoSuchMethodException nsme) {
nsme.printStackTrace();
} catch (InstantiationException ie) {
ie.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}