package jadex.tools.convcenter; import jadex.base.fipa.SFipa; import jadex.base.gui.ComponentSelectorDialog; import jadex.bridge.IComponentIdentifier; import jadex.commons.SGUI; import jadex.commons.SUtil; import jadex.commons.service.IServiceProvider; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.DateFormat; import java.text.ParseException; import java.util.HashMap; import java.util.Map; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.UIDefaults; import javax.swing.border.EtchedBorder; import javax.swing.border.TitledBorder; /** * A panel for displaying and editing a fipa message. */ public class FipaMessagePanel extends JPanel { //-------- static part -------- /** The image icons. */ protected static UIDefaults icons = new UIDefaults(new Object[] { // Tab icons. "edit", SGUI.makeIcon(FipaMessagePanel.class, "/jadex/tools/common/images/dots_small.png"), "delete", SGUI.makeIcon(FipaMessagePanel.class, "/jadex/tools/common/images/delete_small.png") }); /** Default textfield size (columns). */ protected static final int DEFCOLS = 20; //-------- attributes -------- /** The displayed message. */ protected Map message; /** Flag indicating if editing is allowed. */ protected boolean editable; protected JComboBox performative; protected JTextField tfsender; protected JButton setsender; protected JButton clearsender; protected JTextField tfreceivers; protected JButton editreceivers; protected JButton clearreceivers; protected JTextField tfreplyto; protected JButton setreplyto; protected JButton clearreplyto; protected JTextField encoding; protected JTextField language; protected JTextField ontology; protected JComboBox protocol; protected JTextField convid; protected JTextField inreplyto; protected JTextField replywith; protected JFormattedTextField replyby; protected JTextArea content; protected IComponentIdentifier sender; protected IComponentIdentifier replyto; protected IComponentIdentifier[] receivers; //-------- constructors -------- /** * Create the panel with an initial message. * @param message The message. * @param agent The agent. * @param comptree The comptree (if any) will be repainted when new receivers are set in the panel. */ public FipaMessagePanel(Map message, final IServiceProvider provider, final Component comptree) { super(new GridBagLayout()); this.editable = true; performative = new JComboBox((String[])SUtil.joinArrays(new String[]{""}, SFipa.PERFORMATIVES.toArray())); // performative.setEditable(true); // Todo: support arbitrary performatives? tfsender = new JTextField(DEFCOLS); tfsender.setEditable(false); setsender = new JButton(icons.getIcon("edit")); setsender.setMargin(new Insets(0,0,0,0)); setsender.setToolTipText("Set sender agent identifier"); clearsender = new JButton(icons.getIcon("delete")); clearsender.setMargin(new Insets(0,0,0,0)); clearsender.setToolTipText("Remove sender agent identifier"); tfreceivers = new JTextField(DEFCOLS); tfreceivers.setEditable(false); editreceivers = new JButton(icons.getIcon("edit")); editreceivers.setMargin(new Insets(0,0,0,0)); editreceivers.setToolTipText("Edit receiver agent identifiers"); clearreceivers = new JButton(icons.getIcon("delete")); clearreceivers.setMargin(new Insets(0,0,0,0)); clearreceivers.setToolTipText("Clear receiver agent identifiers"); tfreplyto = new JTextField(DEFCOLS); tfreplyto.setEditable(false); setreplyto = new JButton(icons.getIcon("edit")); setreplyto.setMargin(new Insets(0,0,0,0)); setreplyto.setToolTipText("Set reply-to agent identifier"); clearreplyto = new JButton(icons.getIcon("delete")); clearreplyto.setMargin(new Insets(0,0,0,0)); clearreplyto.setToolTipText("Remove reply-to agent identifier"); language = new JTextField(DEFCOLS); encoding = new JTextField(DEFCOLS); ontology = new JTextField(DEFCOLS); protocol = new JComboBox(SFipa.PROTOCOLS.toArray()); protocol.setEditable(true); convid = new JTextField(DEFCOLS); inreplyto = new JTextField(DEFCOLS); replywith = new JTextField(DEFCOLS); replyby = new JFormattedTextField(DateFormat.getDateInstance()); content = new JTextArea(3,DEFCOLS); JLabel label; Dimension labeldim = new JLabel("Conversation-id ").getPreferredSize(); // We use this gbc's as template for all groups (box), labels (left), components (right) and buttons (but). GridBagConstraints boxcons = new GridBagConstraints(0, 0, GridBagConstraints.REMAINDER, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0,0,0,0), 0, 0); GridBagConstraints leftcons = new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(1,1,1,1), 0, 0); GridBagConstraints rightcons = new GridBagConstraints(1, 0, GridBagConstraints.REMAINDER, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(1,1,1,1), 0, 0); GridBagConstraints butcons1 = new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(1,1,1,1), 0, 0); GridBagConstraints butcons2 = new GridBagConstraints(3, 0, GridBagConstraints.REMAINDER, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(1,1,1,1), 0, 0); // The row/box counters are used in the gbc's and incrementd to place the labels/components under each other. int box = 0; int row; // Conversation participants. boxcons.gridy = box++; JPanel participants = new JPanel(new GridBagLayout()); participants.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), " Message Properties ")); this.add(participants, boxcons); row = 0; // Performative leftcons.gridy = rightcons.gridy = row++; label = new JLabel("Performative"); label.setMinimumSize(labeldim); label.setPreferredSize(labeldim); participants.add(label, leftcons); participants.add(performative, rightcons); leftcons.gridy = rightcons.gridy = butcons1.gridy = butcons2.gridy = row++; label = new JLabel("Sender"); label.setMinimumSize(labeldim); label.setPreferredSize(labeldim); participants.add(label, leftcons); rightcons.gridwidth = 1; participants.add(tfsender, rightcons); rightcons.gridwidth = GridBagConstraints.REMAINDER; participants.add(setsender, butcons1); participants.add(clearsender, butcons2); leftcons.gridy = rightcons.gridy = butcons1.gridy = butcons2.gridy = row++; label = new JLabel("Receivers"); label.setMinimumSize(labeldim); label.setPreferredSize(labeldim); participants.add(label, leftcons); rightcons.gridwidth = 1; participants.add(tfreceivers, rightcons); rightcons.gridwidth = GridBagConstraints.REMAINDER; participants.add(editreceivers, butcons1); participants.add(clearreceivers, butcons2); leftcons.gridy = rightcons.gridy = butcons1.gridy = butcons2.gridy = row++; label = new JLabel("Reply_to"); label.setMinimumSize(labeldim); label.setPreferredSize(labeldim); participants.add(label, leftcons); rightcons.gridwidth = 1; participants.add(tfreplyto, rightcons); rightcons.gridwidth = GridBagConstraints.REMAINDER; participants.add(setreplyto, butcons1); participants.add(clearreplyto, butcons2); // Conversation control. boxcons.gridy = box++; JPanel convcontrol = new JPanel(new GridBagLayout()); convcontrol.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), " Conversation Control ")); this.add(convcontrol, boxcons); row = 0; leftcons.gridy = rightcons.gridy = row++; label = new JLabel("Protocol"); label.setMinimumSize(labeldim); label.setPreferredSize(labeldim); convcontrol.add(label, leftcons); convcontrol.add(protocol, rightcons); leftcons.gridy = rightcons.gridy = row++; label = new JLabel("Conversation_id"); label.setMinimumSize(labeldim); label.setPreferredSize(labeldim); convcontrol.add(label, leftcons); convcontrol.add(convid, rightcons); leftcons.gridy = rightcons.gridy = row++; label = new JLabel("Reply_with"); label.setMinimumSize(labeldim); label.setPreferredSize(labeldim); convcontrol.add(label, leftcons); convcontrol.add(replywith, rightcons); leftcons.gridy = rightcons.gridy = row++; label = new JLabel("In_reply_to"); label.setMinimumSize(labeldim); label.setPreferredSize(labeldim); convcontrol.add(label, leftcons); convcontrol.add(inreplyto, rightcons); leftcons.gridy = rightcons.gridy = row++; label = new JLabel("Reply_by"); label.setMinimumSize(labeldim); label.setPreferredSize(labeldim); convcontrol.add(label, leftcons); convcontrol.add(replyby, rightcons); // Content description. boxcons.gridy = box++; JPanel contentdesc = new JPanel(new GridBagLayout()); contentdesc.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), " Content Description ")); this.add(contentdesc, boxcons); row = 0; leftcons.gridy = rightcons.gridy = row++; label = new JLabel("Language"); label.setMinimumSize(labeldim); label.setPreferredSize(labeldim); contentdesc.add(label, leftcons); contentdesc.add(language, rightcons); leftcons.gridy = rightcons.gridy = row++; label = new JLabel("Encoding"); label.setMinimumSize(labeldim); label.setPreferredSize(labeldim); contentdesc.add(label, leftcons); contentdesc.add(encoding, rightcons); leftcons.gridy = rightcons.gridy = row++; label = new JLabel("Ontology"); label.setMinimumSize(labeldim); label.setPreferredSize(labeldim); contentdesc.add(label, leftcons); contentdesc.add(ontology, rightcons); // Content. JPanel cpane = new JPanel(new GridBagLayout()); cpane.add(new JScrollPane(content), new GridBagConstraints(0, 0, GridBagConstraints.REMAINDER, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(1,1,1,1), 0, 0)); cpane.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), " Content ")); this.add(cpane, new GridBagConstraints(0, box++, GridBagConstraints.REMAINDER, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0,0,0,0), 0, 0)); setMessage(message); // Actions for agent selection. final ComponentSelectorDialog agentselector = new ComponentSelectorDialog(this, provider); setsender.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { IComponentIdentifier aid = agentselector.selectAgent(sender); if(aid!=null) { sender = aid; tfsender.setText(aid.toString()); tfsender.setCaretPosition(0); } } }); clearsender.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { sender = null; tfsender.setText(""); } }); setreplyto.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { IComponentIdentifier aid = agentselector.selectAgent(replyto); if(aid!=null) { replyto = aid; tfreplyto.setText(aid.toString()); tfreplyto.setCaretPosition(0); } } }); clearreplyto.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { replyto = null; tfreplyto.setText(""); } }); editreceivers.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { IComponentIdentifier[] aids = agentselector.selectAgents(receivers); if(aids!=null) { if(aids.length>0) { receivers = aids; tfreceivers.setText(SUtil.arrayToString(receivers)); tfreceivers.setCaretPosition(0); } else { receivers = null; tfreceivers.setText(""); } } if(comptree!=null) comptree.repaint(); } }); clearreceivers.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { receivers = null; tfreceivers.setText(""); FipaMessagePanel.this.message.remove(SFipa.RECEIVERS); if(comptree!=null) comptree.repaint(); } }); } //-------- methods -------- /** * Set the message to be displayed. */ public void setMessage(Map message) { this.message = message; // Extract parameter values. performative.setSelectedItem(getParameter(SFipa.PERFORMATIVE)); tfsender.setText(getParameter(SFipa.SENDER)); tfreplyto.setText(getParameter(SFipa.REPLY_TO)); tfreceivers.setText(getParameter(SFipa.RECEIVERS)); content.setText(getParameter(SFipa.CONTENT)); language.setText(getParameter(SFipa.LANGUAGE)); encoding.setText(getParameter(SFipa.ENCODING)); ontology.setText(getParameter(SFipa.ONTOLOGY)); protocol.setSelectedItem(getParameter(SFipa.PROTOCOL)); convid.setText(getParameter(SFipa.CONVERSATION_ID)); inreplyto.setText(getParameter(SFipa.IN_REPLY_TO)); replywith.setText(getParameter(SFipa.REPLY_WITH)); replyby.setText(getParameter(SFipa.REPLY_BY)); // Beautify appearance of text fields. tfsender.setCaretPosition(0); tfreplyto.setCaretPosition(0); content.setCaretPosition(0); language.setCaretPosition(0); encoding.setCaretPosition(0); ontology.setCaretPosition(0); convid.setCaretPosition(0); inreplyto.setCaretPosition(0); replywith.setCaretPosition(0); replyby.setCaretPosition(0); // Extract sender / replyto sender = (IComponentIdentifier)message.get(SFipa.SENDER); replyto = (IComponentIdentifier)message.get(SFipa.REPLY_TO); receivers = (IComponentIdentifier[])message.get(SFipa.RECEIVERS); } /** * Get the displayed message. * Should be called to ensure that uptodate values are * contained in the message parameters. */ public Map getMessage() { if(!editable) return this.message; else this.message = new HashMap(this.message); // Set parameter values. setParameter(SFipa.PERFORMATIVE, (String)performative.getSelectedItem()); setParameter(SFipa.CONTENT, content.getText()); setParameter(SFipa.LANGUAGE, language.getText()); setParameter(SFipa.ENCODING, encoding.getText()); setParameter(SFipa.ONTOLOGY, ontology.getText()); setParameter(SFipa.PROTOCOL, (String)protocol.getSelectedItem()); setParameter(SFipa.CONVERSATION_ID, convid.getText()); setParameter(SFipa.IN_REPLY_TO, inreplyto.getText()); setParameter(SFipa.REPLY_WITH, replywith.getText()); // Set sender / replyto setParameter(SFipa.SENDER, sender); setParameter(SFipa.REPLY_TO, replyto); // Add receivers. setParameterSet(SFipa.RECEIVERS, receivers); // Parse reply-by field. Object replybyval = null; if(replyby.getText()!=null && !replyby.getText().equals("")) { try { replyby.commitEdit(); replybyval = replyby.getValue(); } catch(ParseException e) { throw new RuntimeException("Error parsing reply-by date: "+e); } } else { replybyval = null; } setParameter(SFipa.REPLY_BY, replybyval); return this.message; } /** * Allow editing of the message. */ public void setEditable(boolean editable) { if(editable!=this.editable) { // When setting to not-editable, make snapshot of message. if(!editable) { this.message = getMessage(); } this.editable = editable; performative.setEnabled(editable); setsender.setEnabled(editable); clearsender.setEnabled(editable); editreceivers.setEnabled(editable); clearreceivers.setEnabled(editable); setreplyto.setEnabled(editable); clearreplyto.setEnabled(editable); content.setEditable(editable); language.setEditable(editable); encoding.setEditable(editable); ontology.setEditable(editable); protocol.setEnabled(editable); convid.setEditable(editable); replywith.setEditable(editable); inreplyto.setEditable(editable); replyby.setEditable(editable); } } //-------- helper methods -------- /** * Get a message parameter value as string. */ protected String getParameter(String name) { Object val = message.get(name); return val!=null ? SUtil.arrayToString(val): ""; // arrayToString also works for non arrays. } /** * Set a message parameter from string. */ protected void setParameter(String name, final Object value) { // Replace empty string with null. final Object oval = value==null || value.equals("") ? null : value; message.put(name, oval); } /** * Set a message parameter set. */ protected void setParameterSet(String name, final Object[] values) { message.put(name, values); } /** * Get the currently set receivers. */ public IComponentIdentifier[] getReceivers() { return receivers; } }