/*
* 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.dialog;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import com.rapidminer.gui.RapidMinerGUI;
import com.rapidminer.gui.operatortree.OperatorTree;
import com.rapidminer.gui.tools.ExtendedJScrollPane;
import com.rapidminer.gui.tools.OperatorList;
import com.rapidminer.gui.tools.SwingTools;
import com.rapidminer.operator.Operator;
import com.rapidminer.operator.OperatorCreationException;
import com.rapidminer.operator.OperatorDescription;
import com.rapidminer.operator.learner.Learner;
import com.rapidminer.operator.learner.LearnerCapability;
import com.rapidminer.tools.GroupTree;
import com.rapidminer.tools.OperatorService;
/**
* A dialog for adding new operators to the currently selected operator chain of
* the operator tree. The new operator can be searched by name, by groups, by
* input types, and by output types (or combinations). A short description of
* the operator is also shown. Therefore this dialog might be usefull for less
* experienced RapidMiner users. A shorter way for adding operators is to use the
* context menu in the tree view.
*
* @author Ingo Mierswa, Helge Homburg
* @version $Id: NewOperatorDialog.java,v 2.16 2006/04/05 08:57:23 ingomierswa
* Exp $
*/
public class NewOperatorDialog extends JDialog {
private static final long serialVersionUID = 390653805759799295L;
private OperatorTree operatorTree;
private transient OperatorDescription description = null;
private JPanel mainPanel = new JPanel();
private OperatorInfoPanel operatorInfo = null;
private JList operatorList = new OperatorList();
private String searchText = "";
private Class inputClass = null;
private Class outputClass = null;
private String group = null;
private transient LearnerCapability firstCapability = null;
private transient LearnerCapability secondCapability = null;
public NewOperatorDialog(OperatorTree tree) {
super(RapidMinerGUI.getMainFrame(), "New Operator", false);
this.operatorTree = tree;
// main
mainPanel.setLayout(new BorderLayout());
getContentPane().add(mainPanel, BorderLayout.CENTER);
// buttons
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
JButton okButton = new JButton("Add");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
add();
}
});
buttonPanel.add(okButton);
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cancel();
}
});
buttonPanel.add(cancelButton);
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
// search panel
JPanel searchPanel = new JPanel(new GridLayout(6, 2));
searchPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(10, 10, 5, 10), BorderFactory.createTitledBorder("Search Constraints")));
mainPanel.add(searchPanel, BorderLayout.NORTH);
// input objects (for in- and output classes)
final String[] ioObjects = convertSet2Strings(OperatorService.getIOObjectsNames());
String[] inputObjects = new String[ioObjects.length + 1];
inputObjects[0] = "Any";
System.arraycopy(ioObjects, 0, inputObjects, 1, ioObjects.length);
// search text
final JTextField searchField = new JTextField(searchText);
searchField.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {}
public void keyPressed(KeyEvent e) {}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
searchText = searchField.getText().trim();
updateOperatorList();
}
}
});
searchPanel.add(new JLabel("Search Text: "));
searchPanel.add(searchField);
// groups
java.util.List<String> allGroups = new LinkedList<String>();
allGroups.add("Any");
GroupTree groupTree = OperatorService.getGroups();
addGroups(groupTree, null, allGroups);
Collections.sort(allGroups);
final String[] groupArray = new String[allGroups.size()];
allGroups.toArray(groupArray);
final JComboBox groupComboBox = new JComboBox(groupArray);
groupComboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int selectedIndex = groupComboBox.getSelectedIndex();
if (selectedIndex <= 0) {
group = null;
} else {
group = groupArray[selectedIndex];
}
updateOperatorList();
}
});
searchPanel.add(new JLabel("Operator group: "));
searchPanel.add(groupComboBox);
// input
final JComboBox inputType = new JComboBox(inputObjects);
inputType.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int selectedIndex = inputType.getSelectedIndex();
if (selectedIndex <= 0) {
inputClass = null;
} else {
inputClass = OperatorService.getIOObjectClass(ioObjects[selectedIndex - 1]);
}
updateOperatorList();
}
});
searchPanel.add(new JLabel("Required Input: "));
searchPanel.add(inputType);
// output
final JComboBox outputType = new JComboBox(inputObjects);
outputType.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int selectedIndex = outputType.getSelectedIndex();
if (selectedIndex <= 0) {
outputClass = null;
} else {
outputClass = OperatorService.getIOObjectClass(ioObjects[selectedIndex - 1]);
}
updateOperatorList();
}
});
searchPanel.add(new JLabel("Delivered Output: "));
searchPanel.add(outputType);
// capabilities
List<LearnerCapability> caps = LearnerCapability.getAllCapabilities();
String[] capabilities = new String[caps.size() + 1];
capabilities[0] = "Any";
int k = 1;
Iterator<LearnerCapability> i = caps.iterator();
while (i.hasNext()) {
capabilities[k++] = i.next().getDescription();
}
final JComboBox firstCapabilityType = new JComboBox(capabilities);
firstCapabilityType.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int selectedIndex = firstCapabilityType.getSelectedIndex();
if (selectedIndex <= 0) {
firstCapability = null;
} else {
firstCapability = LearnerCapability.getCapability(selectedIndex - 1);
}
updateOperatorList();
}
});
searchPanel.add(new JLabel("First Capability: "));
searchPanel.add(firstCapabilityType);
final JComboBox secondCapabilityType = new JComboBox(capabilities);
secondCapabilityType.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int selectedIndex = secondCapabilityType.getSelectedIndex();
if (selectedIndex <= 0) {
secondCapability = null;
} else {
secondCapability = LearnerCapability.getCapability(selectedIndex - 1);
}
updateOperatorList();
}
});
searchPanel.add(new JLabel("Second Capability: "));
searchPanel.add(secondCapabilityType);
// list panel
operatorList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
OperatorDescription selection = (OperatorDescription) operatorList.getSelectedValue();
setSelectedOperator(selection);
}
}
});
operatorList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JScrollPane listScrollPane = new ExtendedJScrollPane(operatorList);
GridBagLayout layout = new GridBagLayout();
JPanel listPanel = new JPanel(layout);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.gridwidth = GridBagConstraints.REMAINDER;
c.weightx = 1;
c.weighty = 1;
listPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5, 10, 10, 5), BorderFactory.createTitledBorder("Matching Operators")));
layout.setConstraints(listScrollPane, c);
listPanel.add(listScrollPane);
mainPanel.add(listPanel, BorderLayout.WEST);
updateOperatorList();
setSize(780, 580);
setLocationRelativeTo(RapidMinerGUI.getMainFrame());
}
private void updateOperatorList() {
operatorList.removeAll();
Vector<OperatorDescription> operators = new Vector<OperatorDescription>();
Iterator<String> i = OperatorService.getOperatorNames().iterator();
while (i.hasNext()) {
String name = i.next();
OperatorDescription description = OperatorService.getOperatorDescription(name);
if ((searchText != null) && (searchText.length() > 0) && (description.getName().toLowerCase().indexOf(searchText.toLowerCase()) < 0))
continue;
if ((group != null) && (group.length() > 0) && (description.getGroup().indexOf(group) < 0))
continue;
try {
Operator operator = description.createOperatorInstance();
if ((inputClass != null) && !containsClass(operator.getInputClasses(), inputClass))
continue;
if ((outputClass != null) && !containsClass(operator.getOutputClasses(), outputClass))
continue;
if ((firstCapability != null) && (operator instanceof Learner) && (!((Learner)operator).supportsCapability(firstCapability)))
continue;
if ((secondCapability != null) && (operator instanceof Learner) && (!((Learner)operator).supportsCapability(secondCapability)))
continue;
} catch (Exception e) {}
operators.add(description);
}
Collections.sort(operators);
operatorList.setListData(operators);
if (operators.size() > 0)
operatorList.setSelectedIndex(0);
}
private boolean containsClass(Class<?>[] classes, Class<?> clazz) {
if (classes != null) {
for (int i = 0; i < classes.length; i++) {
if (clazz.isAssignableFrom(classes[i]))
return true;
}
}
return false;
}
private void addGroups(GroupTree tree, String parentName, Collection<String> names) {
Iterator<GroupTree> i = tree.getSubGroups().iterator();
while (i.hasNext()) {
GroupTree subGroup = i.next();
String name = parentName == null ? subGroup.getName() : parentName + "." + subGroup.getName();
names.add(name);
addGroups(subGroup, name, names);
}
}
private void setSelectedOperator(OperatorDescription descriptionName) {
if (operatorInfo != null)
mainPanel.remove(operatorInfo);
if (descriptionName != null) {
this.description = descriptionName;
operatorInfo = new OperatorInfoPanel(this.description);
} else {
operatorInfo = new OperatorInfoPanel(null);
}
if (this.description.getDeprecationInfo() != null)
operatorInfo.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5, 5, 10, 10), BorderFactory.createTitledBorder("Operator Info (Deprecated!)")));
else
operatorInfo.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5, 5, 10, 10), BorderFactory.createTitledBorder("Operator Info")));
mainPanel.add(operatorInfo, BorderLayout.CENTER);
operatorInfo.revalidate();
}
private String[] convertSet2Strings(Collection ioObjects) {
String[] objectArray = new String[ioObjects.size()];
Iterator i = ioObjects.iterator();
int index = 0;
while (i.hasNext()) {
objectArray[index++] = (String) i.next();
}
return objectArray;
}
private Operator getOperator() throws OperatorCreationException {
if (description != null) {
Operator operator = OperatorService.createOperator(description);
return operator;
} else {
return null;
}
}
private void add() {
try {
Operator operator = getOperator();
if (operator != null) {
operatorTree.insert(operator);
}
} catch (Exception ex) {
SwingTools.showSimpleErrorMessage("Cannot create operator:", ex);
}
}
private void cancel() {
dispose();
}
}