/*
* RapidMiner
*
* Copyright (C) 2001-2008 by Rapid-I and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapid-i.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.gui.properties;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import com.rapidminer.gui.tools.ExtendedJTable;
import com.rapidminer.gui.tools.SwingTools;
import com.rapidminer.operator.Operator;
import com.rapidminer.parameter.ParameterType;
import com.rapidminer.parameter.ParameterTypeAttributeFile;
import com.rapidminer.parameter.ParameterTypeBoolean;
import com.rapidminer.parameter.ParameterTypeCategory;
import com.rapidminer.parameter.ParameterTypeColor;
import com.rapidminer.parameter.ParameterTypeConfiguration;
import com.rapidminer.parameter.ParameterTypeDouble;
import com.rapidminer.parameter.ParameterTypeFile;
import com.rapidminer.parameter.ParameterTypeInnerOperator;
import com.rapidminer.parameter.ParameterTypeInt;
import com.rapidminer.parameter.ParameterTypeList;
import com.rapidminer.parameter.ParameterTypeMatrix;
import com.rapidminer.parameter.ParameterTypeParameterValue;
import com.rapidminer.parameter.ParameterTypePassword;
import com.rapidminer.parameter.ParameterTypePreview;
import com.rapidminer.parameter.ParameterTypeStringCategory;
import com.rapidminer.parameter.ParameterTypeText;
import com.rapidminer.parameter.ParameterTypeValue;
import com.rapidminer.tools.LogService;
import de.tud.inf.gui.properties.SimpleFilesCellEditor;
import de.tud.inf.parameters.ParameterTypeFiles;
/**
* A property table is a table for editing parameters of operators or other
* properties (like program settings). Hence, it has two columns, one for the
* key and one for the value. This class does not do very much, but as we want
* such tables to appear at several places, we use this superclass for
* formatting and as a factory for CellEditors.
*
* @author Ingo Mierswa, Simon Fischer
* @version $Id: PropertyTable.java,v 1.12 2008/07/31 17:43:41 ingomierswa Exp $
*/
public abstract class PropertyTable extends ExtendedJTable {
/**
*
*/
private static final long serialVersionUID = -8510884721529372231L;
private static Map<Class<? extends ParameterType>, Class<? extends PropertyValueCellEditor>> knownValueEditors =
new HashMap<Class<? extends ParameterType>, Class<? extends PropertyValueCellEditor>>();
private static Map<Class<? extends ParameterType>, Class<? extends PropertyKeyCellEditor>> knownKeyEditors =
new HashMap<Class<? extends ParameterType>, Class<? extends PropertyKeyCellEditor>>();
// do not register ParameterTypeString because no constructor for this type exists
// --> simply use Default editor for non-registered types (including String)
// the type ParameterTypeDirectory will also be handled by the simple file case
static {
// register known value editors
registerPropertyValueCellEditor(ParameterTypePassword.class, DefaultPropertyValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeConfiguration.class, ConfigurationWizardValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypePreview.class, PreviewValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeColor.class, ColorValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeCategory.class, DefaultPropertyValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeStringCategory.class, DefaultPropertyValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeBoolean.class, DefaultPropertyValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeInt.class, DefaultPropertyValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeDouble.class, DefaultPropertyValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeAttributeFile.class, AttributeFileCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeFile.class, SimpleFileValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeValue.class, OperatorValueValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeInnerOperator.class, InnerOperatorValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeList.class, ListValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeMatrix.class, MatrixValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeText.class, TextValueCellEditor.class);
registerPropertyValueCellEditor(ParameterTypeFiles.class, SimpleFilesCellEditor.class);
// register known key editors
registerPropertyKeyCellEditor(ParameterTypeParameterValue.class, ParameterValueKeyCellEditor.class);
}
private DefaultTableModel model;
private List<PropertyValueCellEditor> valueEditors = new ArrayList<PropertyValueCellEditor>();
private List<PropertyKeyCellEditor> keyEditors = new ArrayList<PropertyKeyCellEditor>();
private List<String> toolTips = new ArrayList<String>();
private String[] columnNames = new String[] { "Key", "Value" };
private PropertyTableParameterChangeListener changeListener = new PropertyTableParameterChangeListener(this);
public PropertyTable() {
this(new String[] { "Key", "Value" });
}
public PropertyTable(String[] columnNames) {
super(null, false, false);
this.columnNames = columnNames;
setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
getTableHeader().setReorderingAllowed(false);
// allow only row selections
setRowSelectionAllowed(true);
setColumnSelectionAllowed(false);
// use bigger rows since some of the GUI elements need more space
setRowHeight(getRowHeight() + SwingTools.TABLE_WITH_COMPONENTS_ROW_EXTRA_HEIGHT);
}
public abstract ParameterType getParameterType(int row);
public abstract Operator getOperator(int row);
public DefaultTableModel getDefaultModel() {
return model;
}
protected static void updateEditorsAndRenderers(PropertyTable propertyTable) {
propertyTable.valueEditors.clear();
propertyTable.keyEditors.clear();
propertyTable.toolTips.clear();
int numberOfRows = propertyTable.getModel().getRowCount();
for (int i = 0; i < numberOfRows; i++) {
ParameterType type = propertyTable.getParameterType(i);
propertyTable.valueEditors.add(createPropertyValueCellEditor(type, propertyTable.getOperator(i)));
PropertyKeyCellEditor keyEditor = createPropertyKeyCellEditor(propertyTable, type, propertyTable.getOperator(i), propertyTable.changeListener);
propertyTable.keyEditors.add(keyEditor);
StringBuffer toolTip = new StringBuffer(type.getDescription());
if ((!(type instanceof ParameterTypeCategory)) && (!(type instanceof ParameterTypeStringCategory))) {
String range = type.getRange();
if ((range != null) && (range.trim().length() > 0)) {
toolTip.append(" (");
toolTip.append(type.getRange());
toolTip.append(")");
}
}
propertyTable.toolTips.add(SwingTools.transformToolTipText(toolTip.toString()));
}
}
public int getNumberOfKeyEditors() {
return this.keyEditors.size();
}
protected PropertyKeyCellEditor getKeyEditor(int index) {
if (keyEditors.size() == 0) {
return null;
} else {
return keyEditors.get(index);
}
}
protected void updateTableData(int rows) {
model = new DefaultTableModel(columnNames, rows);
setModel(model);
}
public int getNumberOfValueEditors() {
return valueEditors.size();
}
public PropertyValueCellEditor getValueEditor(int index) {
return valueEditors.get(index);
}
public TableCellEditor getCellEditor(int row, int column) {
if (column == 1) {
return valueEditors.get(row);
} else {
TableCellRenderer renderer = keyEditors.get(row);
if (renderer instanceof TableCellEditor) {
return (TableCellEditor)renderer;
} else {
return super.getCellEditor(row, column);
}
}
}
public TableCellRenderer getCellRenderer(int row, int column) {
if (column == 1) {
PropertyValueCellEditor editor = valueEditors.get(row);
if (!editor.useEditorAsRenderer()) {
return super.getCellRenderer(row, column);
} else {
return editor;
}
} else {
if (keyEditors.size() == 0) {
return null;
} else {
return keyEditors.get(row);
}
}
}
private String getToolTipText(int row) {
if ((row >= 0) && (row < toolTips.size()))
return toolTips.get(row);
else
return null;
}
/** This method ensures that the correct tool tip for the current table cell is delivered. */
public String getToolTipText(MouseEvent e) {
Point p = e.getPoint();
int row = rowAtPoint(p);
return getToolTipText(row);
}
/** This method ensures that the correct tool tip for the current column is delivered. */
protected JTableHeader createDefaultTableHeader() {
return new JTableHeader(columnModel) {
private static final long serialVersionUID = 1L;
public String getToolTipText(MouseEvent e) {
java.awt.Point p = e.getPoint();
int index = columnModel.getColumnIndexAtX(p.x);
int realColumnIndex = convertColumnIndexToModel(index);
if (realColumnIndex == 0)
return "The names of the parameters.";
else
return "The values of the parameters.";
}
};
}
public static void registerPropertyValueCellEditor(Class<? extends ParameterType> typeClass, Class<? extends PropertyValueCellEditor> editor) {
knownValueEditors.put(typeClass, editor);
}
public static void registerPropertyKeyCellEditor(Class<? extends ParameterType> typeClass, Class<? extends PropertyKeyCellEditor> editor) {
knownKeyEditors.put(typeClass, editor);
}
private static PropertyValueCellEditor createPropertyValueCellEditor(ParameterType type, Operator operator) {
Class<? extends PropertyValueCellEditor> clazz = knownValueEditors.get(type.getClass());
Class usedClass = type.getClass();
if (clazz == null) {
while (clazz == null) {
usedClass = usedClass.getSuperclass();
if (!(ParameterType.class.isAssignableFrom(usedClass)))
break;
clazz = knownValueEditors.get(usedClass);
}
}
if (clazz != null) {
try {
Constructor<? extends PropertyValueCellEditor> constructor = clazz.getConstructor(new Class[] { usedClass });
PropertyValueCellEditor editor = constructor.newInstance(new Object[] { type });
editor.setOperator(operator);
return editor;
} catch (InstantiationException e) {
LogService.getGlobal().log("Cannot construct property editor: " + e, LogService.ERROR);
} catch (IllegalAccessException e) {
LogService.getGlobal().log("Cannot construct property editor: " + e, LogService.ERROR);
} catch (SecurityException e) {
LogService.getGlobal().log("Cannot construct property editor: " + e, LogService.ERROR);
} catch (NoSuchMethodException e) {
LogService.getGlobal().log("Cannot construct property editor: " + e, LogService.ERROR);
} catch (IllegalArgumentException e) {
LogService.getGlobal().log("Cannot construct property editor: " + e, LogService.ERROR);
} catch (InvocationTargetException e) {
LogService.getGlobal().log("Cannot construct property editor: " + e, LogService.ERROR);
}
// no proper editor found --> return default editor
PropertyValueCellEditor editor = new DefaultPropertyValueCellEditor(type);
editor.setOperator(operator);
return editor;
} else {
// no proper editor found --> return default editor
PropertyValueCellEditor editor = new DefaultPropertyValueCellEditor(type);
editor.setOperator(operator);
return editor;
}
}
private static PropertyKeyCellEditor createPropertyKeyCellEditor(PropertyTable table, ParameterType type, Operator operator, PropertyTableParameterChangeListener changeListener) {
Class<? extends PropertyKeyCellEditor> clazz = knownKeyEditors.get(type.getClass());
Class usedClass = type.getClass();
if (clazz == null) {
while (clazz == null) {
usedClass = usedClass.getSuperclass();
if (!(ParameterType.class.isAssignableFrom(usedClass)))
break;
clazz = knownKeyEditors.get(usedClass);
}
}
if (clazz != null) {
try {
Constructor<? extends PropertyKeyCellEditor> constructor = clazz.getConstructor(new Class[] { usedClass });
PropertyKeyCellEditor editor = constructor.newInstance(new Object[] { type });
if (editor instanceof ParameterValueKeyCellEditor) {
((ParameterValueKeyCellEditor)editor).setParameterChangeListener(changeListener);
}
editor.setOperator(operator, table);
return editor;
} catch (InstantiationException e) {
LogService.getGlobal().log("Cannot construct property editor: " + e, LogService.ERROR);
} catch (IllegalAccessException e) {
LogService.getGlobal().log("Cannot construct property editor: " + e, LogService.ERROR);
} catch (SecurityException e) {
LogService.getGlobal().log("Cannot construct property editor: " + e, LogService.ERROR);
} catch (NoSuchMethodException e) {
LogService.getGlobal().log("Cannot construct property editor: " + e, LogService.ERROR);
} catch (IllegalArgumentException e) {
LogService.getGlobal().log("Cannot construct property editor: " + e, LogService.ERROR);
} catch (InvocationTargetException e) {
LogService.getGlobal().log("Cannot construct property editor: " + e, LogService.ERROR);
}
// no proper editor found --> return default editor
PropertyKeyCellEditor editor = new DefaultPropertyKeyRenderer(type);
editor.setOperator(operator, table);
return editor;
} else {
// no proper editor found --> return default editor
PropertyKeyCellEditor editor = new DefaultPropertyKeyRenderer(type);
editor.setOperator(operator, table);
return editor;
}
}
}