blob: d27a2f81567b48cee697ece3bb91dd60afb07144 [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2007 The University of Manchester
*
* Modifications to the initial code base are copyright of their
* respective authors, or their employers as appropriate.
*
* 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-1307
******************************************************************************/
package net.sf.taverna.t2.activities.beanshell.views;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.help.CSH;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter;
import net.sf.taverna.raven.repository.BasicArtifact;
import net.sf.taverna.t2.activities.beanshell.BeanshellActivity;
import net.sf.taverna.t2.activities.beanshell.BeanshellActivityConfigurationBean;
import net.sf.taverna.t2.activities.dependencyactivity.AbstractAsynchronousDependencyActivity;
import net.sf.taverna.t2.activities.dependencyactivity.AbstractAsynchronousDependencyActivity.ClassLoaderSharing;
import net.sf.taverna.t2.lang.ui.FileTools;
import net.sf.taverna.t2.reference.ExternalReferenceSPI;
import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ActivityConfigurationPanel;
import net.sf.taverna.t2.workflowmodel.OutputPort;
import net.sf.taverna.t2.workflowmodel.Port;
import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityInputPort;
import net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean;
import net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean;
import org.apache.log4j.Logger;
import org.syntax.jedit.JEditTextArea;
import org.syntax.jedit.tokenmarker.JavaTokenMarker;
/**
* Provides the configurable view for a {@link BeanshellActivity} through it's
* {@link BeanshellActivityConfigurationBean}. Has 3 main tabs - Script, Ports &
* Dependencies. The {@link #inputViewList} contains the
* {@link BeanshellInputViewer}s describing the input ports and
* {@link #outputViewList} has the {@link BeanshellOutputViewer}s
*
* @author Ian Dunlop
* @author Alex Nenadic
* @author Alan R Williams
*
*/
@SuppressWarnings("serial")
public class BeanshellConfigView extends ActivityConfigurationPanel<BeanshellActivity, BeanshellActivityConfigurationBean> {
private static final String VALID_NAME_REGEX = "[\\p{L}\\p{Digit}_]+";
private static Logger logger = Logger.getLogger(BeanshellConfigView.class);
/** The activity which this view describes */
protected BeanshellActivity activity;
/** The configuration bean used to configure the activity */
private BeanshellActivityConfigurationBean configuration;
///////// Beanshell properties that can be configured ////////
/** The beanshell script */
private JEditTextArea scriptText;
/** A list of views over the input ports */
private List<BeanshellInputViewer> inputViewList;
/** A list of views over the output ports */
private List<BeanshellOutputViewer> outputViewList;
/** Classloader sharing policy */
private ClassLoaderSharing classLoaderSharing;
/** A list of local dependencies (JAR files) this activity depends on */
private LinkedHashSet<String> localDependencies = new LinkedHashSet<String>();
///////// End of beanshell properties that can be configured //
/** Remembers where the next input should be placed in the view */
private int inputGridy;
/**
* An incremental name of newInputPort + this number is used to name new
* ports
*/
private int newInputPortNumber = 0;
/**
* An incremental name of newOutputPort + this number is used to name new
* ports
*/
private int newOutputPortNumber = 0;
/** Remembers where the next output should be placed in the view */
private int outputGridy;
/** Parent panel for the outputs */
private JPanel outerOutputPanel;
/** Have output ports been changed */
private boolean outputsChanged = false;
/** Parent panel for the inputs */
private JPanel outerInputPanel;
/** Have input ports been changed */
private boolean inputsChanged = false;
private JTabbedPane tabbedPane = null;
private File currentDirectory = null;
/**
* Stores the {@link BeanshellActivity}, gets its
* {@link BeanshellActivityConfigurationBean}, sets the layout and calls
* {@link #initialise()} to get the view going
*
* @param activity
* the {@link BeanshellActivity} that the view is over
*/
public BeanshellConfigView(BeanshellActivity activity) {
this.activity = activity;
setLayout(new GridBagLayout());
initialise();
}
public void noteConfiguration() {
// Set the new configuration
List<ActivityInputPortDefinitionBean> inputBeanList = new ArrayList<ActivityInputPortDefinitionBean>();
for (BeanshellInputViewer inputView : inputViewList) {
ActivityInputPortDefinitionBean activityInputPortDefinitionBean = new ActivityInputPortDefinitionBean();
activityInputPortDefinitionBean
.setHandledReferenceSchemes(inputView.getBean()
.getHandledReferenceSchemes());
activityInputPortDefinitionBean.setMimeTypes(inputView
.getBean().getMimeTypes());
activityInputPortDefinitionBean
.setTranslatedElementType(inputView.getBean()
.getTranslatedElementType());
activityInputPortDefinitionBean
.setAllowsLiteralValues((Boolean) inputView
.getLiteralSelector().getSelectedItem());
activityInputPortDefinitionBean
.setDepth((Integer) inputView.getDepthSpinner()
.getValue());
activityInputPortDefinitionBean.setName(inputView
.getNameField().getText());
inputBeanList.add(activityInputPortDefinitionBean);
}
List<ActivityOutputPortDefinitionBean> outputBeanList = new ArrayList<ActivityOutputPortDefinitionBean>();
for (BeanshellOutputViewer outputView : outputViewList) {
ActivityOutputPortDefinitionBean activityOutputPortDefinitionBean = new ActivityOutputPortDefinitionBean();
activityOutputPortDefinitionBean
.setDepth((Integer) outputView.getDepthSpinner()
.getValue());
// activityOutputPortDefinitionBean
// .setGranularDepth((Integer) outputView
// .getGranularDepthSpinner().getValue());
// NOTE: Granular depth must match output depth because we return
// the full lists right away
activityOutputPortDefinitionBean
.setGranularDepth(activityOutputPortDefinitionBean
.getDepth());
activityOutputPortDefinitionBean.setName(outputView
.getNameField().getText());
activityOutputPortDefinitionBean.setMimeTypes(new ArrayList<String>());
outputBeanList.add(activityOutputPortDefinitionBean);
}
BeanshellActivityConfigurationBean newConfiguration =
(BeanshellActivityConfigurationBean) cloneBean (configuration);
newConfiguration.setScript(scriptText
.getText());
newConfiguration
.setInputPortDefinitions(inputBeanList);
newConfiguration
.setOutputPortDefinitions(outputBeanList);
newConfiguration.setClassLoaderSharing(classLoaderSharing);
newConfiguration.setLocalDependencies(localDependencies);
newConfiguration.setArtifactDependencies(new LinkedHashSet<BasicArtifact>());
configuration = newConfiguration;
inputsChanged = false;
outputsChanged = false;
}
public boolean isConfigurationChanged() {
String newScriptText = scriptText.getText();
String configText = configuration.getScript();
return !((!inputsChanged)
&& (!outputsChanged)
&& scriptText.getText().equals(configuration.getScript())
&& classLoaderSharing.equals(configuration.getClassLoaderSharing())
&& localDependencies.equals(configuration.getLocalDependencies()));
}
/**
* Adds a {@link JButton} which handles the reconfiguring of the
* {@link BeanshellActivity} through the altered
* {@link BeanshellActivityConfigurationBean}. Sets up the initial tabs -
* Script (also sets the initial value), Ports & Dependencies and their
* initial values through {@link #setDependencies()},
* {@link #getPortPanel()}
*/
private void initialise() {
CSH
.setHelpIDString(
this,
"net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.BeanshellConfigView");
configuration = activity.getConfiguration();
inputViewList = new ArrayList<BeanshellInputViewer>();
outputViewList = new ArrayList<BeanshellOutputViewer>();
classLoaderSharing = configuration.getClassLoaderSharing();
localDependencies.addAll(configuration.getLocalDependencies());
setBorder(javax.swing.BorderFactory.createTitledBorder(null, null,
javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION,
javax.swing.border.TitledBorder.DEFAULT_POSITION,
new java.awt.Font("Lucida Grande", 1, 12)));
final BeanshellActivityConfigurationBean configBean = activity
.getConfiguration();
JPanel scriptEditPanel = new JPanel(new BorderLayout());
tabbedPane = new JTabbedPane();
tabbedPane.addTab("Script", scriptEditPanel);
tabbedPane.addTab("Input ports", new JScrollPane(getInputPanel()));
tabbedPane.addTab("Output ports", new JScrollPane(getOutputPanel()));
tabbedPane.addTab("Dependencies", getDependenciesPanel());
GridBagConstraints outerConstraint = new GridBagConstraints();
outerConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
outerConstraint.gridx = 0;
outerConstraint.gridy = 0;
outerConstraint.fill = GridBagConstraints.BOTH;
outerConstraint.weighty = 0.1;
outerConstraint.weightx = 0.1;
add(tabbedPane, outerConstraint);
scriptText = new JEditTextArea();
scriptText.setText(configBean.getScript());
scriptText.setTokenMarker(new JavaTokenMarker());
scriptText.setCaretPosition(0);
scriptText.setPreferredSize(new Dimension(0, 0));
scriptEditPanel.add(new JScrollPane(scriptText), BorderLayout.CENTER);
JButton loadScriptButton = new JButton("Load script");
loadScriptButton.setToolTipText("Load a beanshell script from a file");
loadScriptButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String newScript = FileTools.readStringFromFile(BeanshellConfigView.this);
if (newScript != null) {
scriptText.setText(newScript);
}
}
});
JButton saveRScriptButton = new JButton("Save script");
saveRScriptButton.setToolTipText("Save the Beanshell script to a file");
saveRScriptButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
FileTools.saveStringToFile(BeanshellConfigView.this, "Save Beanshell script", ".bsh", scriptText.getText());
}
});
JButton clearScriptButton = new JButton("Clear script");
clearScriptButton
.setToolTipText("Clear current script from the edit area");
clearScriptButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
clearScript();
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout());
buttonPanel.add(loadScriptButton);
buttonPanel.add(saveRScriptButton);
buttonPanel.add(clearScriptButton);
scriptEditPanel.add(buttonPanel, BorderLayout.SOUTH);
setPreferredSize(new Dimension(500,500));
inputsChanged = false;
outputsChanged = false;
this.validate();
}
/**
* Returns a panel where local and artifact dependencies and classloading policy can be set.
*/
private JPanel getDependenciesPanel(){
JPanel dependenciesPanel = new JPanel();
dependenciesPanel.setLayout(new BoxLayout(dependenciesPanel, BoxLayout.PAGE_AXIS));
// Create panel with classloading options
JPanel classloadingPanel = new ClassloadingPanel();
// Create panel for selecting jar files
JPanel jarFilesPanel = new JarFilesPanel();
dependenciesPanel.add(classloadingPanel);
dependenciesPanel.add(Box.createRigidArea(new Dimension(0,10)));
dependenciesPanel.add(jarFilesPanel);
dependenciesPanel.add(Box.createRigidArea(new Dimension(0,10)));
return dependenciesPanel;
}
// Panel containing classloading options
private class ClassloadingPanel extends JPanel {
// Classloading option 'workflow'
private static final String WORKFLOW = "Shared for whole workflow";
// Classloading option 'system'
private static final String SYSTEM = "System classloader";
// Combobox with classloading options
private JComboBox jcbClassloadingOption;
// Classloading option descriptions
private HashMap<String, String> classloadingDescriptions;
// JLabel with classloading option description
private JLabel jlClassloadingDescription;
// Panel containing a list of possible classloading options which users can select from
private ClassloadingPanel(){
super(new GridBagLayout());
jcbClassloadingOption = new JComboBox(
new String[] {WORKFLOW,SYSTEM});
// Set the current classlaoding option based on the configuration bean
if (configuration.getClassLoaderSharing() == (AbstractAsynchronousDependencyActivity.ClassLoaderSharing.workflow)){
jcbClassloadingOption.setSelectedItem(WORKFLOW);
}
else if (configuration.getClassLoaderSharing() == (AbstractAsynchronousDependencyActivity.ClassLoaderSharing.system)){
jcbClassloadingOption.setSelectedItem(SYSTEM);
}
jcbClassloadingOption.addActionListener(new ActionListener(){
// Fires up when combobox selection changes
public void actionPerformed(ActionEvent e) {
jlClassloadingDescription.setText(classloadingDescriptions
.get(((JComboBox) e.getSource()).getSelectedItem()));
if (((JComboBox) e.getSource()).getSelectedItem().equals(
WORKFLOW)) {
classLoaderSharing = AbstractAsynchronousDependencyActivity.ClassLoaderSharing.workflow;
}
else if (((JComboBox) e.getSource()).getSelectedItem().equals(
SYSTEM)) {
classLoaderSharing = AbstractAsynchronousDependencyActivity.ClassLoaderSharing.system;
}
}
});
//jcbClassloadingOption.setEnabled(false);
classloadingDescriptions = new HashMap<String, String>();
classloadingDescriptions.put(WORKFLOW, "<html><small>"
+ "Classes are shared across the whole workflow (with any service<br>"
+ "also selecting this option), but are reinitialised for each workflow run.<br>"
+ "This might be needed if a service passes objects to another, or <br>"
+ "state is shared within static members of loaded classes."
+ "</small></html>");
classloadingDescriptions.put(SYSTEM, "<html><small><p>"
+ "The (global) system classloader is used, any dependencies defined here are<br>"
+ "made available globally on the first run. Note that if you are NOT using<br>"
+ "the defaulf Taverna BootstrapClassLoader, any settings here will be disregarded."
+ "</p><p>"
+ "This is mainly useful if you are using JNI-based libraries. Note that <br>"
+ "for JNI you also have to specify <code>-Djava.library.path</code> and <br>"
+ "probably your operating system's dynamic library search path<br>"
+ "<code>LD_LIBRARY_PATH</code> / <code>DYLD_LIBRARY_PATH</code> / <code>PATH</code> </p></small></html>");
// Set the current classlaoding description based on the item selected in the combobox
jlClassloadingDescription = new JLabel(classloadingDescriptions
.get(jcbClassloadingOption.getSelectedItem()));
// Add components to the ClassloadingPanel
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.insets = new Insets(10,0,0,0);
add(new JLabel("Classloader persistence"), c);
c.insets = new Insets(0,0,0,0);
add(jcbClassloadingOption, c);
c.insets = new Insets(0,30,0,0);
add(jlClassloadingDescription, c);
}
}
// Panel for users to add local JAR dependencies (contains a list of jar files which users can select from)
private class JarFilesPanel extends JPanel {
private JLabel warning =
new JLabel(
"<html><center<font color='red'>"
+ "Warning: Depending on local libraries makes this workflow<br>"
+ "difficult or impossible to run for other users. Try depending<br>"
+ "on artifacts from a public repository if possible.</font></center></html>");
private JarFilesPanel() {
super();
setMinimumSize(new Dimension(400, 150));
setLayout(new BorderLayout());
setBorder(new EmptyBorder(0,10,0,10));
JPanel labelPanel = new JPanel();
labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.PAGE_AXIS));
JLabel label = new JLabel("Local JAR files");
if (!BeanshellActivity.libDir.exists())
BeanshellActivity.libDir.mkdir();
JLabel libLabel = new JLabel("<html><small>" + BeanshellActivity.libDir.getAbsolutePath()
+ "</small></html>");
labelPanel.add(label);
labelPanel.add(libLabel);
add(labelPanel, BorderLayout.NORTH);
add(new JScrollPane(jarFiles(),
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
warning.setVisible(false);
// We'll skip the warning until we actually have support
// for artifacts
//add(warning);
updateWarning();
}
private void updateWarning() {
// Show warning if there is any local dependencies
warning.setVisible(!configuration.getLocalDependencies().isEmpty());
}
public JPanel jarFiles() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
// Make so it's there so the user can add stuff to it
// List of all jar files in the lib directory
List<String> jarFiles =
Arrays.asList(BeanshellActivity.libDir.list(new BeanshellActivity.FileExtFilter(".jar")));
// We also add the list of jars that may have been configured sometime before
// but are now not present in the lib directory for some reason
Set<String> missingLocalDeps =
new HashSet<String>(configuration.getLocalDependencies());
missingLocalDeps.removeAll(jarFiles);
// jarFiles and missingLocalDeps now contain two sets of files that do not intersect
List<String> jarFilesList = new ArrayList<String>();
// Put them all together
jarFilesList.addAll(jarFiles);
jarFilesList.addAll(missingLocalDeps);
Collections.sort(jarFilesList);
if (jarFilesList.isEmpty()) {
panel.add(new JLabel("<html><small>To depend on a JAR file, "
+ "copy it to the above-mentioned folder.</small></html>"));
return panel;
}
for (String jarFile : jarFilesList) {
JCheckBox checkBox = new JCheckBox(jarFile);
// Has it already been selected in some previous configuring?
checkBox.setSelected(configuration.getLocalDependencies().contains(jarFile));
checkBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
JCheckBox box = (JCheckBox) e.getSource();
if (e.getStateChange() == ItemEvent.SELECTED) {
localDependencies.add(box.getText());
} else if (e.getStateChange() == ItemEvent.DESELECTED) {
localDependencies.remove(box.getText());
}
updateWarning();
}
});
panel.add(checkBox);
// The jar may not be in the lib directory, so warn the user
if (!new File(BeanshellActivity.libDir, jarFile).exists()) {
checkBox.setForeground(Color.RED);
checkBox.setText(checkBox.getText() + " (missing file!)");
}
}
return panel;
}
}
/**
* Loops through the {@link ActivityInputPortDefinitionBean} in the
* {@link BeanshellActivityConfigurationBean} and creates a
* {@link BeanshellInputViewer} for each one. Displays the name and a
* {@link JSpinner} to change the depth for each one and a {@link JButton}
* to remove it. Currently the individual components from a
* {@link BeanshellInputViewer} are added rather than the
* {@link BeanshellInputViewer} itself
*
* @return panel containing the view over the input ports
*/
private JPanel getInputPanel() {
final JPanel inputEditPanel = new JPanel(new GridBagLayout());
inputEditPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory
.createEtchedBorder(), "Inputs"));
final GridBagConstraints inputConstraint = new GridBagConstraints();
inputConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
inputConstraint.gridx = 0;
inputConstraint.gridy = 0;
inputConstraint.weightx = 0.1;
inputConstraint.fill = GridBagConstraints.BOTH;
inputEditPanel.add(new JLabel("Name"), inputConstraint);
inputConstraint.gridx = 1;
inputEditPanel.add(new JLabel("Depth"), inputConstraint);
inputGridy = 1;
inputConstraint.gridx = 0;
for (ActivityInputPortDefinitionBean inputBean : configuration
.getInputPortDefinitions()) {
// FIXME refactor this into a method
inputConstraint.gridy = inputGridy;
final BeanshellInputViewer beanshellInputViewer = new BeanshellInputViewer(
inputBean, true);
inputViewList.add(beanshellInputViewer);
inputConstraint.gridx = 0;
final JTextField nameField = beanshellInputViewer.getNameField();
nameField.getDocument().addDocumentListener(new DocumentListener(){
public void changedUpdate(DocumentEvent e) {
//Plain text components don't fire these events.
}
public void insertUpdate(DocumentEvent e) {
inputsChanged = true;
}
public void removeUpdate(DocumentEvent e) {
inputsChanged = true;
}
});
inputConstraint.weightx = 0.1;
inputEditPanel.add(nameField, inputConstraint);
inputConstraint.weightx = 0.0;
inputConstraint.gridx = 1;
final JSpinner depthSpinner = beanshellInputViewer
.getDepthSpinner();
depthSpinner.addChangeListener(new ChangeListener(){
public void stateChanged(ChangeEvent e) {
inputsChanged = true;
}
});
inputEditPanel.add(depthSpinner, inputConstraint);
inputConstraint.gridx = 2;
final JButton removeButton = new JButton("Remove");
removeButton.addActionListener(new AbstractAction() {
public void actionPerformed(ActionEvent e) {
inputsChanged = true;
inputViewList.remove(beanshellInputViewer);
inputEditPanel.remove(nameField);
inputEditPanel.remove(depthSpinner);
inputEditPanel.remove(removeButton);
inputEditPanel.revalidate();
inputEditPanel.repaint();
outerInputPanel.revalidate();
outerInputPanel.repaint();
}
});
inputEditPanel.add(removeButton, inputConstraint);
inputGridy++;
}
outerInputPanel = new JPanel();
outerInputPanel.setLayout(new GridBagLayout());
GridBagConstraints outerPanelConstraint = new GridBagConstraints();
outerPanelConstraint.gridx = 0;
outerPanelConstraint.gridy = 0;
outerPanelConstraint.weightx = 0.1;
outerPanelConstraint.weighty = 0.1;
outerPanelConstraint.fill = GridBagConstraints.BOTH;
outerInputPanel.add(new JScrollPane(inputEditPanel),
outerPanelConstraint);
outerPanelConstraint.weighty = 0;
JButton addInputPortButton = new JButton(new AbstractAction() {
// FIXME refactor this into a method
public void actionPerformed(ActionEvent e) {
inputsChanged = true;
ActivityInputPortDefinitionBean bean = new ActivityInputPortDefinitionBean();
bean.setAllowsLiteralValues(true);
bean.setDepth(0);
List<Class<? extends ExternalReferenceSPI>> handledReferenceSchemes = new ArrayList<Class<? extends ExternalReferenceSPI>>();
// handledReferenceSchemes.add(FileReference.class);
bean.setHandledReferenceSchemes(handledReferenceSchemes);
List<String> mimeTypes = new ArrayList<String>();
mimeTypes.add("text/plain");
bean.setMimeTypes(mimeTypes);
String name2 = "in" + newInputPortNumber;
boolean nameExists = true;
while (nameExists == true) {
nameExists = inputPortNameExists(name2, activity
.getInputPorts());
if (nameExists) {
newInputPortNumber++;
name2 = "in" + newInputPortNumber;
}
}
bean.setName(name2);
newInputPortNumber++;
bean.setTranslatedElementType(String.class);
inputConstraint.gridy = inputGridy;
final BeanshellInputViewer beanshellInputViewer = new BeanshellInputViewer(
bean, true);
inputViewList.add(beanshellInputViewer);
inputConstraint.weightx = 0.1;
inputConstraint.gridx = 0;
final JTextField nameField = beanshellInputViewer
.getNameField();
inputEditPanel.add(nameField, inputConstraint);
inputConstraint.weightx = 0;
inputConstraint.gridx = 1;
final JSpinner depthSpinner = beanshellInputViewer
.getDepthSpinner();
inputEditPanel.add(depthSpinner, inputConstraint);
inputConstraint.gridx = 2;
final JButton removeButton = new JButton("Remove");
removeButton.addActionListener(new AbstractAction() {
public void actionPerformed(ActionEvent e) {
inputViewList.remove(beanshellInputViewer);
inputEditPanel.remove(nameField);
inputEditPanel.remove(depthSpinner);
inputEditPanel.remove(removeButton);
inputEditPanel.revalidate();
inputEditPanel.repaint();
outerInputPanel.revalidate();
outerInputPanel.repaint();
}
});
inputEditPanel.add(removeButton, inputConstraint);
inputEditPanel.revalidate();
inputEditPanel.repaint();
inputGridy++;
}
});
addInputPortButton.setText("Add Port");
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridBagLayout());
JPanel filler = new JPanel();
outerPanelConstraint.weightx = 0.1;
outerPanelConstraint.weighty = 0;
outerPanelConstraint.gridx = 0;
outerPanelConstraint.gridy = 0;
buttonPanel.add(filler, outerPanelConstraint);
outerPanelConstraint.weightx = 0;
outerPanelConstraint.weighty = 0;
outerPanelConstraint.gridx = 1;
outerPanelConstraint.gridy = 0;
buttonPanel.add(addInputPortButton, outerPanelConstraint);
outerPanelConstraint.weightx = 0;
outerPanelConstraint.weighty = 0;
outerPanelConstraint.gridx = 0;
outerPanelConstraint.gridy = 1;
outerPanelConstraint.fill = GridBagConstraints.BOTH;
outerInputPanel.add(buttonPanel, outerPanelConstraint);
return outerInputPanel;
}
/**
* Loops through the {@link ActivityInputPortDefinitionBean} in the
* {@link BeanshellActivityConfigurationBean} and creates a
* {@link BeanshellOutputViewer} for each one. Displays the name and a
* {@link JSpinner} to change the depth and granular depth for each one and
* a {@link JButton} to remove it. Currently the individual components from
* a {@link BeanshellOutputViewer} are added rather than the
* {@link BeanshellOutputViewer} itself
*
* @return the panel containing the view of the output ports
*/
private JPanel getOutputPanel() {
// mimes = new JPanel();
final JPanel outputEditPanel = new JPanel(new GridBagLayout());
outputEditPanel.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(), "Outputs"));
final GridBagConstraints outputConstraint = new GridBagConstraints();
outputConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
outputConstraint.gridx = 0;
outputConstraint.gridy = 0;
outputConstraint.weightx = 0.1;
outputConstraint.weighty = 0.1;
outputConstraint.fill = GridBagConstraints.BOTH;
outputConstraint.weighty = 0;
outputEditPanel.add(new JLabel("Name"), outputConstraint);
outputConstraint.gridx = 1;
outputEditPanel.add(new JLabel("Depth"), outputConstraint);
// outputConstraint.gridx = 2;
// outputEditPanel.add(new JLabel("GranularDepth"), outputConstraint);
outputGridy = 1;
outputConstraint.gridx = 0;
for (ActivityOutputPortDefinitionBean outputBean : configuration
.getOutputPortDefinitions()) {
// FIXME refactor this into a method
outputConstraint.gridy = outputGridy;
final BeanshellOutputViewer beanshellOutputViewer = new BeanshellOutputViewer(
outputBean, true);
outputViewList.add(beanshellOutputViewer);
outputConstraint.gridx = 0;
outputConstraint.weightx = 0.1;
final JTextField nameField = beanshellOutputViewer.getNameField();
nameField.getDocument().addDocumentListener(new DocumentListener(){
public void changedUpdate(DocumentEvent e) {
//Plain text components don't fire these events.
}
public void insertUpdate(DocumentEvent e) {
outputsChanged = true;
}
public void removeUpdate(DocumentEvent e) {
outputsChanged = true;
}
});
outputEditPanel.add(nameField, outputConstraint);
outputConstraint.weightx = 0;
outputConstraint.gridx = 1;
final JSpinner depthSpinner = beanshellOutputViewer
.getDepthSpinner();
depthSpinner.addChangeListener(new ChangeListener(){
public void stateChanged(ChangeEvent e) {
outputsChanged = true;
}
});
outputEditPanel.add(depthSpinner, outputConstraint);
outputConstraint.gridx = 2;
final JButton removeButton = new JButton("Remove");
removeButton.addActionListener(new AbstractAction() {
public void actionPerformed(ActionEvent e) {
outputsChanged = true;
outputViewList.remove(beanshellOutputViewer);
outputEditPanel.remove(nameField);
outputEditPanel.remove(depthSpinner);
// outputEditPanel.remove(granularDepthSpinner);
// outputEditPanel.remove(addMimeButton);
outputEditPanel.remove(removeButton);
outputEditPanel.revalidate();
outputEditPanel.repaint();
outerOutputPanel.revalidate();
outerOutputPanel.repaint();
}
});
outputEditPanel.add(removeButton, outputConstraint);
outputGridy++;
}
outerOutputPanel = new JPanel();
outerOutputPanel.setLayout(new GridBagLayout());
GridBagConstraints outerPanelConstraint = new GridBagConstraints();
// outerPanelConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
outerPanelConstraint.fill = GridBagConstraints.BOTH;
outerPanelConstraint.gridx = 0;
outerPanelConstraint.gridy = 0;
outerPanelConstraint.weightx = 0.1;
outerPanelConstraint.weighty = 0.1;
outerOutputPanel.add(new JScrollPane(outputEditPanel),
outerPanelConstraint);
outerPanelConstraint.weighty = 0;
JButton addOutputPortButton = new JButton(new AbstractAction() {
// FIXME refactor this into a method
public void actionPerformed(ActionEvent e) {
try {
outputsChanged = true;
ActivityOutputPortDefinitionBean bean = new ActivityOutputPortDefinitionBean();
bean.setDepth(0);
bean.setGranularDepth(0);
List<String> mimeTypes = new ArrayList<String>();
mimeTypes.add("text/plain");
bean.setMimeTypes(mimeTypes);
String name2 = "out" + newOutputPortNumber;
boolean nameExists = true;
while (nameExists == true) {
nameExists = outputPortNameExists(name2, activity
.getOutputPorts());
if (nameExists) {
newOutputPortNumber++;
name2 = "out" + newOutputPortNumber;
}
}
bean.setName(name2);
final BeanshellOutputViewer beanshellOutputViewer = new BeanshellOutputViewer(
bean, true);
outputViewList.add(beanshellOutputViewer);
outputConstraint.gridy = outputGridy;
outputConstraint.gridx = 0;
final JTextField nameField = beanshellOutputViewer
.getNameField();
outputConstraint.weightx = 0.1;
outputEditPanel.add(nameField, outputConstraint);
outputConstraint.gridx = 1;
outputConstraint.weightx = 0;
final JSpinner depthSpinner = beanshellOutputViewer
.getDepthSpinner();
outputEditPanel.add(depthSpinner, outputConstraint);
outputConstraint.gridx = 2;
final JButton removeButton = new JButton("Remove");
removeButton.addActionListener(new AbstractAction() {
public void actionPerformed(ActionEvent e) {
outputViewList.remove(beanshellOutputViewer);
outputEditPanel.remove(nameField);
outputEditPanel.remove(depthSpinner);
// outputEditPanel.remove(granularDepthSpinner);
outputEditPanel.remove(removeButton);
// outputEditPanel.remove(addMimeButton);
outputEditPanel.revalidate();
outputEditPanel.repaint();
outerOutputPanel.revalidate();
outerOutputPanel.repaint();
}
});
outputEditPanel.add(removeButton, outputConstraint);
outputEditPanel.revalidate();
newOutputPortNumber++;
outputGridy++;
} catch (Exception e1) {
// throw it, log it??
}
}
});
addOutputPortButton.setText("Add Port");
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridBagLayout());
JPanel filler = new JPanel();
outerPanelConstraint.weightx = 0.1;
outerPanelConstraint.weighty = 0;
outerPanelConstraint.gridx = 0;
outerPanelConstraint.gridy = 0;
buttonPanel.add(filler, outerPanelConstraint);
outerPanelConstraint.weightx = 0;
outerPanelConstraint.weighty = 0;
outerPanelConstraint.gridx = 1;
outerPanelConstraint.gridy = 0;
buttonPanel.add(addOutputPortButton, outerPanelConstraint);
outerPanelConstraint.weightx = 0;
outerPanelConstraint.weighty = 0;
outerPanelConstraint.gridx = 0;
outerPanelConstraint.gridy = 1;
outerPanelConstraint.fill = GridBagConstraints.BOTH;
outerOutputPanel.add(buttonPanel, outerPanelConstraint);
outerPanelConstraint.gridx = 1;
outerPanelConstraint.gridy = 0;
return outerOutputPanel;
}
/**
* Check the proposed port name against the set of input ports that the
* activity has
*
* @param name
* @param set
* @return
*/
private boolean inputPortNameExists(String name, Set<ActivityInputPort> set) {
for (Port port : set) {
if (name.equals(port.getName())) {
return true;
}
}
return false;
}
/**
* Check the proposed port name against the set of output ports that the
* activity has
*
* @param name
* @param set
* @return
*/
private boolean outputPortNameExists(String name, Set<OutputPort> set) {
for (Port port : set) {
if (name.equals(port.getName())) {
return true;
}
}
return false;
}
/**
* Method for clearing the script
*
*/
private void clearScript() {
if (JOptionPane.showConfirmDialog(this,
"Do you really want to clear the script?",
"Clearing the script", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
scriptText.setText("");
}
}
@Override
public BeanshellActivityConfigurationBean getConfiguration() {
return configuration;
}
@Override
public void refreshConfiguration() {
int visibleTab = -1;
if (tabbedPane != null) {
visibleTab = tabbedPane.getSelectedIndex();
}
this.removeAll();
initialise();
if (visibleTab != -1) {
tabbedPane.setSelectedIndex(visibleTab);
}
}
@Override
public boolean checkValues() {
boolean result = true;
String text = "";
Set<String> inputPortNames = new HashSet<String>();
for (BeanshellInputViewer v : inputViewList) {
String name = v.getNameField().getText();
if (inputPortNames.contains(name)) {
text += "Two input ports have the name " + name + "\n";
result = false;
} else if (!name.matches(VALID_NAME_REGEX)){
text += "Input port name " + name + " is invalid\n";
result = false;
} else {
inputPortNames.add(name);
}
}
Set<String> outputPortNames = new HashSet<String>();
for (BeanshellOutputViewer v : outputViewList) {
String name = v.getNameField().getText();
if (outputPortNames.contains(name)) {
text += "Two output ports have the name " + name + "\n";
result = false;
} else if (!name.matches(VALID_NAME_REGEX)){
text += "Output port name " + name + " is invalid\n";
result = false;
} else {
outputPortNames.add(name);
}
}
if (!result) {
JOptionPane.showMessageDialog(this, text, "Port name problem", JOptionPane.ERROR_MESSAGE);
}
return result;
}
}