/**
* Copyright (C) 2001-2017 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.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.Component;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import com.rapidminer.gui.tools.SwingTools;
import com.rapidminer.operator.Operator;
import com.rapidminer.parameter.ParameterType;
import com.rapidminer.parameter.ParameterTypeCategory;
import com.rapidminer.parameter.ParameterTypeEnumeration;
import com.rapidminer.parameter.ParameterTypeList;
import com.rapidminer.parameter.ParameterTypeStringCategory;
/**
* Parameter table for list and enumeration types (GUI class).
*
* Note: This class uses a dedicated renderer/editor for each row. Actually, this is unnecessary.
* The only reason is that if we re-use the editors/renderers, one has to click into the cell once
* for starting editing and then again for opening a combo box, e.g. This may be related to
* editingStopped-events which are fired by the cells that loose focus.
*
* @author Simon Fischer, Marius Helf
*
*/
public class ListPropertyTable2 extends JTable {
private static final long serialVersionUID = 1L;
private List<TableCellRenderer[]> renderers = new LinkedList<>();
private List<TableCellEditor[]> editors = new LinkedList<>();
private ParameterType[] types;
private Operator operator;
public ListPropertyTable2(ParameterTypeList type, List<String[]> parameterList, Operator operator) {
this(new ParameterType[] { type.getKeyType(), type.getValueType() }, parameterList, operator);
}
public ListPropertyTable2(ParameterTypeEnumeration type, List<String> parameterList, Operator operator) {
this(new ParameterType[] { type.getValueType() }, to2DimList(parameterList), operator);
}
private List<String[]> createParameterListCopy(List<String[]> parameterList) {
List<String[]> copiedParameterList = new LinkedList<>();
for (String[] paramArray : parameterList) {
String[] copiedParamArray = new String[paramArray.length];
int i = 0;
for (String string : paramArray) {
copiedParamArray[i] = string;
i++;
}
copiedParameterList.add(copiedParamArray);
}
return copiedParameterList;
}
private ListPropertyTable2(ParameterType[] types, List<String[]> parameterList, Operator operator) {
this.types = types;
this.operator = operator;
setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
getTableHeader().setReorderingAllowed(false);
setRowSelectionAllowed(true);
setColumnSelectionAllowed(false);
setRowHeight(PropertyPanel.VALUE_CELL_EDITOR_HEIGHT);
setSurrendersFocusOnKeystroke(true);
setModel(new ListTableModel(types, createParameterListCopy(parameterList)));
fillEditors();
requestFocusForLastEditableCell();
}
private static List<String[]> to2DimList(List<String> parameterList) {
List<String[]> result = new LinkedList<>();
for (String v : parameterList) {
result.add(new String[] { v });
}
return result;
}
public void addRow() {
((ListTableModel) getModel()).addRow();
fillEditors();
// start editing the new row
requestFocusForLastEditableCell();
}
public boolean isEmpty() {
return renderers.isEmpty();
}
protected void fillEditors() {
while (editors.size() < getModel().getRowCount()) {
TableCellRenderer rowRenderers[] = new TableCellRenderer[types.length];
TableCellEditor rowEditors[] = new TableCellEditor[types.length];
for (int i = 0; i < types.length; i++) {
rowRenderers[i] = PropertyPanel.instantiateValueCellEditor(types[i], operator);
rowEditors[i] = PropertyPanel.instantiateValueCellEditor(types[i], operator);
}
renderers.add(rowRenderers);
editors.add(rowEditors);
}
}
@Override
public Component prepareEditor(TableCellEditor editor, int row, int column) {
changeSelection(row, column, false, false);
return super.prepareEditor(editor, row, column);
}
public boolean requestFocusForLastEditableCell() {
boolean foundCell = false;
for (int row = getRowCount() - 1; row >= 0; --row) {
for (int column = 0; column < getColumnCount(); ++column) {
if (!isCellEditable(row, column)) {
continue;
} else {
changeSelection(row, column, false, false);
foundCell = startCellEditingAndRequestFocus(row, column);
break;
}
}
if (foundCell) {
break;
}
}
return foundCell;
}
private boolean startCellEditingAndRequestFocus(int row, int column) {
if (isCellEditable(row, column)) {
editCellAt(row, column);
Component editorComponent = getEditorComponent();
if (editorComponent != null) {
if (editorComponent instanceof JComponent) {
JComponent jComponent = (JComponent) editorComponent;
if (!jComponent.hasFocus()) {
jComponent.requestFocusInWindow();
}
return true;
}
}
}
return false;
}
public void removeSelected() {
if (getSelectedRow() != -1) {
stopEditing();
((ListTableModel) getModel()).removeRow(getSelectedRow());
requestFocusForLastEditableCell();
}
}
public void storeParameterList(List<String[]> parameterList2) {
parameterList2.clear();
parameterList2.addAll(((ListTableModel) getModel()).getParameterList());
}
public void stopEditing() {
TableCellEditor editor = getCellEditor();
if (editor != null) {
editor.stopCellEditing();
}
}
public void storeParameterEnumeration(List<String> parameterList2) {
parameterList2.clear();
for (String[] values : ((ListTableModel) getModel()).getParameterList()) {
parameterList2.add(values[0]);
}
}
@Override
public TableCellRenderer getCellRenderer(int row, int column) {
return renderers.get(row)[column];
}
@Override
public TableCellEditor getCellEditor(int row, int column) {
return editors.get(row)[column];
}
/** This method ensures that the correct tool tip for the current table cell is delivered. */
@Override
public String getToolTipText(MouseEvent e) {
Point p = e.getPoint();
int column = columnAtPoint(p);
ParameterType type = types[column];
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(")");
}
}
String toolTipText = SwingTools.transformToolTipText(toolTip.toString());
return toolTipText;
}
/*
* DO NOT ENABLE THE LIST SELECTION CHANGE METHODS! If you do so and request the focus when
* changing selection this leads to strange side effects (like losing focus directly after
* clicking an a table cell).
*/
// /**
// * Row selection change listener
// */
// @Override
// public void valueChanged(ListSelectionEvent e) {
// super.valueChanged(e);
// int col = getSelectedColumn();
// int row = getSelectedRow();
// if (col >= 0 && row >= 0) {
// startCellEditingAndRequestFocus(row, col);
// }
// }
//
// /**
// * Column selection change listener
// */
// @Override
// public void columnSelectionChanged(ListSelectionEvent e) {
// super.columnSelectionChanged(e);
// int col = getSelectedColumn();
// int row = getSelectedRow();
// if (col >= 0 && row >= 0) {
// startCellEditingAndRequestFocus(row, col);
// }
// }
}