| /******************************************************************************* |
| * 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; |
| } |
| |
| } |