package jadex.bpmn.runtime.task; import jadex.bpmn.model.MActivity; import jadex.bpmn.model.MParameter; import jadex.bpmn.runtime.BpmnInterpreter; import jadex.bpmn.runtime.ITask; import jadex.bpmn.runtime.ITaskContext; import jadex.bridge.IComponentListener; import jadex.bridge.IComponentStep; import jadex.bridge.IInternalAccess; import jadex.commons.ChangeEvent; import jadex.commons.Future; import jadex.commons.IFuture; import jadex.commons.SReflect; import jadex.javaparser.IParsedExpression; import jadex.javaparser.javaccimpl.JavaCCExpressionParser; import java.awt.BorderLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Iterator; import java.util.Map; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingUtilities; /** * Opens a dialog for the task and lets the user enter * result parameters. */ public class UserInteractionTask implements ITask { //-------- attributes -------- /** The dialog. */ protected JDialog dialog; //-------- ITask interface -------- /** * Execute the task. * @param context The accessible values. * @param instance The process instance executing the task. * @listener To be notified, when the task has completed. */ public IFuture execute(final ITaskContext context, final BpmnInterpreter instance) { final Future ret = new Future(); final IComponentListener lis = new IComponentListener() { public void componentTerminating(ChangeEvent ce) { } public void componentTerminated(ChangeEvent ce) { SwingUtilities.invokeLater(new Runnable() { public void run() { if(dialog!=null) { dialog.setVisible(false); } } }); } }; instance.addComponentListener(lis); SwingUtilities.invokeLater(new Runnable() { public void run() { final JOptionPane pane; JComponent message; MActivity task = context.getModelElement(); Map parameters = task.getParameters(); if(parameters!=null && !parameters.isEmpty()) { Insets insets = new Insets(2,2,2,2); message = new JPanel(new GridBagLayout()); message.add(new JLabel("Please enter values for task "+context.getModelElement().getName()), new GridBagConstraints(0, 0, GridBagConstraints.REMAINDER, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.BOTH, insets, 0, 0)); pane = new JOptionPane(message, JOptionPane.INFORMATION_MESSAGE, JOptionPane.OK_CANCEL_OPTION); pane.setValue(JOptionPane.UNINITIALIZED_VALUE); int i=0; for(Iterator it=parameters.values().iterator(); it.hasNext(); i++) { final MParameter param = (MParameter)it.next(); Object value = context.getParameterValue(param.getName()); JComponent comp; if(SReflect.getWrappedType(param.getClazz()).equals(Boolean.class)) { final JCheckBox cb = new JCheckBox(); cb.setSelected(value instanceof Boolean && ((Boolean)value).booleanValue()); if(param.getDirection().equals(MParameter.DIRECTION_IN)) { cb.setEnabled(false); } else { pane.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { if(pane.getValue()!=JOptionPane.UNINITIALIZED_VALUE) { context.setParameterValue(param.getName(), new Boolean(cb.isSelected())); } } }); } comp = cb; } else { final JTextField tf = new JTextField(value!=null ? ""+value : ""); if(param.getDirection().equals(MParameter.DIRECTION_IN)) { tf.setEditable(false); } else { pane.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { if(pane.getValue()!=JOptionPane.UNINITIALIZED_VALUE) { String text = tf.getText(); try { // Todo: access thread context for imports etc.!? IParsedExpression pex = new JavaCCExpressionParser().parseExpression(text, null, null, null); context.setParameterValue(param.getName(), pex.getValue(null)); } catch(Exception ex) { // Hack!!! Fallback: if no expression entered for string, use value directly. if(param.getClazz().equals(String.class)) { context.setParameterValue(param.getName(), text); } else { ex.printStackTrace(); } } } } }); } comp = tf; } message.add(new JLabel(param.getName()), new GridBagConstraints(0, i+1, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.BOTH, insets, 0, 0)); message.add(comp, new GridBagConstraints(1, i+1, GridBagConstraints.REMAINDER, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.BOTH, insets, 0, 0)); } } else { message = new JLabel("Please perform task "+context.getModelElement().getName()); pane = new JOptionPane(message, JOptionPane.INFORMATION_MESSAGE, JOptionPane.OK_CANCEL_OPTION); pane.setValue(JOptionPane.UNINITIALIZED_VALUE); } dialog = new JDialog((JFrame)null, context.getModelElement().getName()); dialog.getContentPane().setLayout(new BorderLayout()); dialog.getContentPane().add(pane, BorderLayout.CENTER); dialog.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { pane.setValue(null); instance.scheduleStep(new IComponentStep() { public Object execute(IInternalAccess ia) { ia.removeComponentListener(lis); return null; } }); } }); pane.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { if(pane.getValue()!=JOptionPane.UNINITIALIZED_VALUE) { // Close window, if button was pressed. if(pane.getValue()!=null) { dialog.setVisible(false); } if(pane.getValue()==null || ((Integer)pane.getValue()).intValue()==JOptionPane.CANCEL_OPTION) { Exception e = new RuntimeException("Task not completed"); e.fillInStackTrace(); // listener.exceptionOccurred(UserInteractionTask.this, e); ret.setException(e); } else { ret.setResult(null); // listener.resultAvailable(UserInteractionTask.this, null); } } } }); dialog.pack(); dialog.setLocationRelativeTo(null); dialog.setVisible(true); } }); return ret; } //-------- static methods -------- /** * Get the meta information about the agent. */ public static TaskMetaInfo getMetaInfo() { String desc = "The user interaction task can be used for fetching in parameter values " + "via an interactive user interface dialog. The task automatically uses all declared" + "in parameters."; return new TaskMetaInfo(desc, null); } }