JAL-919, JAL-715 - prototype service editing dialog using jalview parameter model...
authorjprocter <jprocter@compbio.dundee.ac.uk>
Mon, 29 Aug 2011 14:44:06 +0000 (15:44 +0100)
committerjprocter <jprocter@compbio.dundee.ac.uk>
Mon, 29 Aug 2011 14:44:06 +0000 (15:44 +0100)
13 files changed:
src/jalview/gui/RestInputParamEditDialog.java [new file with mode: 0644]
src/jalview/gui/RestServiceEditorPane.java
src/jalview/jbgui/GRestInputParamEditDialog.java [new file with mode: 0644]
src/jalview/jbgui/GRestServiceEditorPane.java
src/jalview/ws/rest/InputType.java
src/jalview/ws/rest/RestServiceDescription.java
src/jalview/ws/rest/params/Alignment.java
src/jalview/ws/rest/params/AnnotationFile.java
src/jalview/ws/rest/params/JobConstant.java
src/jalview/ws/rest/params/SeqGroupIndexVector.java
src/jalview/ws/rest/params/SeqIdVector.java
src/jalview/ws/rest/params/SeqVector.java
src/jalview/ws/rest/params/Tree.java

diff --git a/src/jalview/gui/RestInputParamEditDialog.java b/src/jalview/gui/RestInputParamEditDialog.java
new file mode 100644 (file)
index 0000000..71fdb5d
--- /dev/null
@@ -0,0 +1,249 @@
+package jalview.gui;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+import javax.swing.JDialog;
+import javax.swing.JInternalFrame;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.event.ListSelectionEvent;
+
+import com.sun.tools.corba.se.idl.InvalidArgument;
+
+import net.miginfocom.swing.MigLayout;
+
+import jalview.jbgui.GRestInputParamEditDialog;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.InvalidArgumentException;
+import jalview.ws.params.OptionI;
+import jalview.ws.params.ParameterI;
+import jalview.ws.rest.InputType;
+import jalview.ws.rest.RestServiceDescription;
+
+public class RestInputParamEditDialog extends GRestInputParamEditDialog
+        implements OptsParametersContainerI
+{
+  Hashtable<String, Class> typeclass = new Hashtable<String, Class>();
+
+  Hashtable<String, ArrayList<JPanel>> typeopts = new Hashtable<String, ArrayList<JPanel>>();
+
+  Hashtable<String,OptsAndParamsPage> opanps = new Hashtable<String, OptsAndParamsPage>();
+  
+  private InputType getTypeFor(String name)
+  {
+    try
+    {
+      return (InputType) (typeclass.get(name).getConstructor()
+              .newInstance(null));
+    } catch (Throwable x)
+    {
+      System.err
+              .println("Unexpected exception when instantiating rest input type.");
+      x.printStackTrace();
+    }
+    return null;
+  }
+
+  int reply;
+  JalviewDialog frame = new JalviewDialog()
+  {
+    
+    @Override
+    protected void raiseClosed()
+    {
+      
+    }
+    
+    @Override
+    protected void okPressed()
+    {
+      reply=JOptionPane.OK_OPTION; 
+    }
+    
+    @Override
+    protected void cancelPressed()
+    {
+      reply=JOptionPane.CANCEL_OPTION; 
+      
+    }
+  };
+  InputType old,current;
+  public RestInputParamEditDialog(
+          RestServiceEditorPane restServiceEditorPane,
+          RestServiceDescription currentservice, InputType toedit)
+  {
+    initFor(restServiceEditorPane, currentservice, toedit);
+    frame.waitForInput();
+    // TODO: warn user if they are about to overwrite an existing parameter because they have used the same name when editing a different parameter.
+    // TODO: make any press of the return key cause 'OK' to be pressed
+  }
+  private void initFor(RestServiceEditorPane restServiceEditorPane,
+          RestServiceDescription currentservice, InputType toedit)
+  {
+    okcancel.add(frame.cancel);
+    okcancel.add(frame.ok);
+    frame.initDialogFrame(dpane, true, true, "Edit parameter for service "+currentservice.getName(), 600,800);
+    
+    initTypeLists();
+    reply=JOptionPane.CANCEL_OPTION;
+    old = toedit;
+    current = null;
+    if (old!=null) {
+      setStateFor(old);
+    }
+    updated = updated && reply==JOptionPane.OK_OPTION;
+    frame.validate();
+  }
+
+  public RestInputParamEditDialog(
+          RestServiceEditorPane restServiceEditorPane,
+          RestServiceDescription currentservice, String string)
+  {
+    initFor(restServiceEditorPane, currentservice,null);
+    tok.setText(string);
+    frame.waitForInput();
+  }
+
+  private void setStateFor(InputType current)
+  {
+    tok.setText(current.token);
+    OptsAndParamsPage opanp=opanps.get(current.getURLtokenPrefix());
+    for (OptionI ops:current.getOptions())
+    {
+      if (ops instanceof ParameterI)
+      {
+        opanp.setParameter((ParameterI) ops);
+      } else {
+        if (ops.getValue()!=null && ops.getValue().length()>0) {
+          opanp.selectOption(ops, ops.getValue());
+        }
+      }
+    }
+    typeList.setSelectedValue(current.getURLtokenPrefix(), true);
+    type_SelectionChangedActionPerformed(null);
+  }
+  private void updateCurrentType()
+  {
+    if (typeList.getSelectedValue()!=null) {
+    InputType newType = getTypeFor((String)typeList.getSelectedValue());
+    if (newType!=null) {
+      newType.token = tok.getText().trim();
+      try {
+        newType.configureFromArgumentI(opanps.get(newType.getURLtokenPrefix()).getCurrentSettings());
+        current=newType;
+        updated=true;
+      } catch (InvalidArgumentException ex) {
+        System.err.println("IMPLEMENTATION ERROR: Invalid argument for type : "+typeList.getSelectedValue()+"\n");
+        ex.printStackTrace();
+      }
+    }
+    }
+    
+  }
+  private void initTypeLists()
+  {
+    ArrayList<String> types=new ArrayList<String>();
+    // populate type list
+    for (Class type : RestServiceDescription.getInputTypes())
+    {
+
+      InputType jtype = null;
+      try
+      {
+        JPanel inopts = new JPanel(new MigLayout());
+        ArrayList<JPanel> opts = new ArrayList<JPanel>(), prms = new ArrayList<JPanel>();
+        jtype = (InputType) (type.getConstructor().newInstance(null));
+        typeclass.put(jtype.getURLtokenPrefix(), type);
+        // and populate parameters from this type
+        OptsAndParamsPage opanp = new OptsAndParamsPage(this,true);
+        opanps.put(jtype.getURLtokenPrefix(),opanp);
+        for (OptionI opt : jtype.getOptions())
+        {
+
+          if (opt instanceof ParameterI)
+          {
+            prms.add(opanp.addParameter((ParameterI) opt));
+          }
+          else
+          {
+            opts.add(opanp.addOption(opt));
+          }
+        }
+        // then tag the params at the end of the options.
+        for (JPanel pnl : prms)
+        {
+          opts.add(pnl);
+        }
+        typeopts.put(jtype.getURLtokenPrefix(), opts);
+        types.add(jtype.getURLtokenPrefix());
+      } catch (Throwable x)
+      {
+        System.err
+                .println("Unexpected exception when instantiating rest input type.");
+        x.printStackTrace();
+      }
+    }
+    typeList.setListData(types.toArray());
+    
+  }
+
+  @Override
+  protected void type_SelectionChangedActionPerformed(ListSelectionEvent e)
+  {
+    options.removeAll();
+    String typen = (String) typeList.getSelectedValue();
+    if (typeopts.get(typen) != null)
+    {
+      for (JPanel opt : typeopts.get(typen))
+      {
+        opt.setOpaque(true);
+        options.add(opt,"wrap");
+      }
+      options.invalidate();
+      optionsPanel.setVisible(true);
+    }
+    else
+    {
+      optionsPanel.setVisible(false);
+    }
+    dpane.revalidate();
+    updateCurrentType();
+  }
+
+  boolean updated=false;
+  public boolean wasUpdated()
+  {
+    return updated;
+  }
+
+  @Override
+  public void refreshParamLayout()
+  {
+    options.invalidate();
+    dpane.revalidate();
+  }
+
+  @Override
+  protected void tokChanged_actionPerformed()
+  {
+    if (tok.getText().trim().length()>0)
+    {
+      if (current!=null)
+      {
+        current.token = tok.getText().trim();
+        updated = true; 
+      } 
+    }
+  }
+  @Override
+  public void argSetModified(Object modifiedElement, boolean b)
+  {
+    updated = updated | b;
+    if (updated)
+    {
+      updateCurrentType();
+    }
+  }
+
+}
index 581a44e..4f9c13e 100644 (file)
@@ -1,37 +1,30 @@
 package jalview.gui;
 
-import jalview.bin.Cache;
 import jalview.io.packed.DataProvider.JvDataType;
-import jalview.jbgui.*;
+import jalview.jbgui.GRestServiceEditorPane;
 import jalview.ws.rest.InputType;
 import jalview.ws.rest.RestServiceDescription;
 
-import java.awt.*;
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.awt.event.ComponentEvent;
 import java.awt.event.ComponentListener;
-import java.awt.event.ContainerEvent;
-import java.awt.event.ContainerListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
-import java.awt.event.WindowEvent;
-import java.awt.event.WindowListener;
-import java.awt.event.WindowStateListener;
-import java.util.ArrayList;
+import java.awt.event.MouseEvent;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Vector;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import javax.swing.*;
-import javax.swing.event.CaretEvent;
+import javax.swing.JFrame;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.text.GapContent;
-
-import org.apache.log4j.lf5.LogLevel;
 
 public class RestServiceEditorPane extends GRestServiceEditorPane
 {
@@ -52,9 +45,6 @@ public class RestServiceEditorPane extends GRestServiceEditorPane
     // begin with initial text description box enabled.
     urldesc.addKeyListener(new KeyListener()
     {
-      long lastWait;
-      boolean doUpdate;
-      Thread updater=null;
       @Override
       public void keyTyped(KeyEvent e)
       {
@@ -69,7 +59,6 @@ public class RestServiceEditorPane extends GRestServiceEditorPane
       @Override
       public void keyPressed(KeyEvent e)
       {
-        // TODO Auto-generated method stub
         
       }
     });
@@ -89,13 +78,21 @@ public class RestServiceEditorPane extends GRestServiceEditorPane
         
       }
       });
+    currentservice = new RestServiceDescription("Analysis", "service description", "service name", "http://localhost/", "", null, false, false, '-');
+    initGuiWith(currentservice);
+    refreshCutnPaste(false);
+    updateButtons();
   }
 
   public RestServiceEditorPane(RestServiceDescription toedit)
   {
-    this();
+    super();
     oldservice = toedit;
-    currentservice = new RestServiceDescription(toedit);
+    if (oldservice!=null)
+    {    currentservice = new RestServiceDescription(toedit);
+    } else {
+      currentservice = new RestServiceDescription("Analysis", "service description", "service name", "http://localhost/", "", null, false, false, '-');
+    }
     initGuiWith(currentservice);
     refreshCutnPaste(false);
     updateButtons();
@@ -106,7 +103,7 @@ public class RestServiceEditorPane extends GRestServiceEditorPane
    */
   public void updateButtons()
   {
-    cancelButton.setEnabled(oldservice != null);
+    cancelButton.setEnabled(true);
     okButton.setEnabled(currentservice != null && currentservice.isValid());
 
   }
@@ -123,12 +120,28 @@ public class RestServiceEditorPane extends GRestServiceEditorPane
    */
   private void initGuiWith(RestServiceDescription currentservice)
   {
+    _iparam.clear();
+    _rparam.clear();
+    action.removeAllItems();
+    action.addItem("Alignment");
+    action.addItem("Analysis");
+    gapChar.removeAllItems();
+    gapChar.addItem(".");
+    gapChar.addItem(" ");
+    gapChar.addItem("-");
+    if (currentservice==null)
+    {
+      name.setText("");
+      descr.setText("");
+      url.setText("");
+      urlsuff.setText("");
+      action.setSelectedItem("Analysis");
+      gapChar.setSelectedItem("-");
+    } else {
     name.setText(currentservice.getName());
     descr.setText(currentservice.getDescription());
     url.setText(currentservice.getPostUrl());
     urlsuff.setText(currentservice.getUrlSuffix());
-    _iparam.clear();
-    _rparam.clear();
     for (Map.Entry<String, InputType> inparam : currentservice
             .getInputParams().entrySet())
     {
@@ -136,23 +149,143 @@ public class RestServiceEditorPane extends GRestServiceEditorPane
               + inparam.getValue().getURLtokenPrefix() + ":"
               + inparam.getValue().getURLEncodedParameter().toString());
     }
+      
     for (JvDataType oparam : currentservice.getResultDataTypes())
     {
-      _rparam.add((oparam.name()));
+      _rparam.add(oparam.name());
     }
     iprms.setListData(_iparam);
     rdata.setListData(_rparam);
 
-    action.removeAllItems();
-    action.addItem("Alignment");
-    action.addItem("Analysis");
-    // action.addItem("Analysis");
     action.setSelectedItem(currentservice.getAction());
+
+    gapChar.setSelectedItem(""+currentservice.getGapCharacter());
+    }
     revalidate();
   }
+  private String getSelectedInputToken()
+  {
+    if (iprms.getSelectedIndex()>-1)
+    {
+    String toktoedit = (String) iprms.getSelectedValue();
+    toktoedit=toktoedit.substring(0, toktoedit.indexOf(" "));
+    return toktoedit;
+    }
+    return null;
+  }
+  @Override
+  protected void iprmListSelection_doubleClicked()
+  {
+    String toktoedit = getSelectedInputToken();
+    if (toktoedit!=null)
+    {
+      InputType toedit = currentservice.getInputParams().get(toktoedit);
+      String oldParam=toktoedit;
+      RestInputParamEditDialog dialog=new RestInputParamEditDialog(this, currentservice, toedit);
+      if (dialog.wasUpdated()) {
+        currentservice.getInputParams().remove(oldParam);
+        currentservice.getInputParams().put(dialog.current.token, dialog.current);
+        initGuiWith(currentservice);
+      }
+      
+    }
+  }
+  @Override
+  protected void iprmsAdd_actionPerformed(ActionEvent e)
+  {
+    RestInputParamEditDialog dialog=new RestInputParamEditDialog(this, currentservice, "param"+(1+currentservice.getInputParams().size()));
+    if (dialog.wasUpdated()) {
+      currentservice.getInputParams().put(dialog.current.token, dialog.current);
+      initGuiWith(currentservice);
+    }
+
+  }
+  @Override
+  protected void iprmsRem_actionPerformed(ActionEvent e)
+  {
+    String toktoedit = getSelectedInputToken();
+    if (toktoedit!=null)
+    {
+      currentservice.getInputParams().remove(toktoedit);
+      initGuiWith(currentservice);
+
+    }
+  }
+  @Override
+  protected void rdata_rightClicked(MouseEvent mouse)
+  {
+    final int rdatasel = rdata.getSelectedIndex();
+    if (rdatasel>-1)
+    {
+      JPopupMenu popup = new JPopupMenu("Select return type");
+      for (final JvDataType type:JvDataType.values()) {
+        popup.add(new JMenuItem(type.name())).addActionListener(new ActionListener()
+        {
+          
+          @Override
+          public void actionPerformed(ActionEvent e)
+          {
+            currentservice.getResultDataTypes().set(rdatasel, type);
+            initGuiWith(currentservice);   
+            rdata.setSelectedIndex(rdatasel);
+          }
+        });
+      }
+      popup.show(rdata, mouse.getX(), mouse.getY());
+    }
+  }
+  @Override
+  protected void rdataAdd_actionPerformed(ActionEvent e)
+  {
+    int p;
+    if ((p=rdata.getSelectedIndex())>-1)
+    {
+      currentservice.getResultDataTypes().add(p+1, JvDataType.ANNOTATION);
+    } else {
+      currentservice.addResultDatatype(JvDataType.ANNOTATION);
+    }
+    initGuiWith(currentservice);
+    rdata.setSelectedIndex(p==-1 ? currentservice.getResultDataTypes().size()-1 : p+1);
+  }
+  @Override
+  protected void rdataNdown_actionPerformed(ActionEvent e)
+  {
+    int p;
+    if ((p=rdata.getSelectedIndex())>-1 && p<_rparam.size()-1)
+    {
+      List<JvDataType> rtypes = currentservice.getResultDataTypes();
+      JvDataType below = rtypes.get(p+1);
+      rtypes.set(p+1, rtypes.get(p));
+      rtypes.set(p, below);
+      initGuiWith(currentservice);
+      rdata.setSelectedIndex(p+1);
+    }
+  }
+  @Override
+  protected void rdataNup_actionPerformed(ActionEvent e)
+  {
+    int p;
+    if ((p=rdata.getSelectedIndex())>0)
+    {
+      List<JvDataType> rtypes = currentservice.getResultDataTypes();
+      JvDataType above = rtypes.get(p-1);
+      rtypes.set(p-1, rtypes.get(p));
+      rtypes.set(p, above);
+      initGuiWith(currentservice);
+      rdata.setSelectedIndex(p-1);
+    }
+  }
+  @Override
+  protected void rdataRem_actionPerformed(ActionEvent e)
+  {
+    if (rdata.getSelectedIndex()>-1)
+    {
+      currentservice.getResultDataTypes().remove(rdata.getSelectedIndex());
+      initGuiWith(currentservice);
+    }
+  }
 
   private boolean updateServiceFromGui() {
-    boolean valid=true;
     Map<String,InputType>inputTypes = new HashMap<String, InputType>();
     StringBuffer warnings=new StringBuffer();
     for (String its:_iparam)
@@ -246,37 +379,35 @@ public class RestServiceEditorPane extends GRestServiceEditorPane
 
         public void run()
         {
+          boolean nulserv=true;
           while (visible)
           {
             final Thread runner = Thread.currentThread();
             JFrame df = new JFrame();
             df.getContentPane().setLayout(new BorderLayout());
             df.getContentPane().add(
-                    new RestServiceEditorPane(jalview.ws.rest.RestClient
-                            .makeShmmrRestClient().getRestDescription()),
+                    (nulserv=!nulserv) ? new RestServiceEditorPane(jalview.ws.rest.RestClient
+                            .makeShmmrRestClient().getRestDescription()) : new RestServiceEditorPane(), 
                     BorderLayout.CENTER);
-            df.setBounds(100, 100, 400, 600);
+            df.setBounds(100, 100, 600, 400);
             df.addComponentListener(new ComponentListener()
             {
 
               @Override
               public void componentShown(ComponentEvent e)
               {
-                // TODO Auto-generated method stub
 
               }
 
               @Override
               public void componentResized(ComponentEvent e)
               {
-                // TODO Auto-generated method stub
 
               }
 
               @Override
               public void componentMoved(ComponentEvent e)
               {
-                // TODO Auto-generated method stub
 
               }
 
diff --git a/src/jalview/jbgui/GRestInputParamEditDialog.java b/src/jalview/jbgui/GRestInputParamEditDialog.java
new file mode 100644 (file)
index 0000000..a277759
--- /dev/null
@@ -0,0 +1,93 @@
+package jalview.jbgui;
+
+import java.awt.Dimension;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+import jalview.gui.JvSwingUtils;
+import jalview.gui.OptsAndParamsPage;
+
+import javax.swing.*;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import net.miginfocom.swing.MigLayout;
+
+
+public class GRestInputParamEditDialog
+{
+
+  protected JPanel dpane;
+  protected JPanel okcancel;
+  protected JList typeList;
+  protected JTextField tok;
+  protected JPanel options;
+  protected JPanel optionsPanel;
+  public GRestInputParamEditDialog() 
+  {
+    jbInit();
+  }
+  protected void jbInit() {
+    dpane = new JPanel(new MigLayout("","[][][fill]","[][fill][]"));
+    dpane.setPreferredSize(new Dimension(110+100+OptsAndParamsPage.PARAM_WIDTH,400));
+    typeList = new JList();
+    typeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+    typeList.getSelectionModel().addListSelectionListener(new ListSelectionListener()
+    {
+      
+      @Override
+      public void valueChanged(ListSelectionEvent e)
+      {
+        type_SelectionChangedActionPerformed(e);
+      };
+    });
+    
+    tok = new JTextField();
+    tok.addKeyListener(new KeyListener()
+    {
+      
+      @Override
+      public void keyTyped(KeyEvent e)
+      {
+      }
+      
+      @Override
+      public void keyReleased(KeyEvent e)
+      {
+        tokChanged_actionPerformed();
+      }
+      
+      @Override
+      public void keyPressed(KeyEvent e)
+      {
+        
+      }
+    });
+    options = new JPanel(new MigLayout("","[grow 100,fill]",""));
+    optionsPanel = new JPanel(new MigLayout("","[fill]","[fill]"));
+    JScrollPane optionView = new JScrollPane();
+    optionView.setViewportView(options);
+    JvSwingUtils.mgAddtoLayout(dpane, "Input Parameter name", new JLabel("Name"), tok, "grow,spanx 3,wrap");
+    JPanel paramsType = new JPanel(new MigLayout("","[grow 100,fill]","[grow 100,fill]"));
+    paramsType.setBorder(new TitledBorder("Select input type"));
+    JScrollPane jlistScroller=new JScrollPane();
+    jlistScroller.setViewportView(typeList);
+    paramsType.add(jlistScroller,"spanx 2,spany 2");
+    dpane.add(paramsType);
+    optionsPanel.setBorder(new TitledBorder("Set options for type"));
+    optionsPanel.add(optionView);
+    dpane.add(optionsPanel,"wrap");
+    okcancel = new JPanel(new MigLayout("","[center][center]","[]"));
+    dpane.add(okcancel,"spanx 3,wrap");
+
+  }
+  protected void tokChanged_actionPerformed()
+  {
+    
+  }
+  protected void type_SelectionChangedActionPerformed(ListSelectionEvent e)
+  {
+  }
+  
+}
index 69b9704..c80e789 100644 (file)
@@ -8,6 +8,8 @@ import java.awt.FlowLayout;
 import java.awt.GridLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
 
 import javax.swing.BoxLayout;
 import javax.swing.JButton;
@@ -20,12 +22,14 @@ import javax.swing.JScrollPane;
 import javax.swing.JTabbedPane;
 import javax.swing.JTextArea;
 import javax.swing.JViewport;
+import javax.swing.ListSelectionModel;
 import javax.swing.UIManager;
 import javax.swing.border.TitledBorder;
 import javax.swing.event.CaretEvent;
 import javax.swing.event.CaretListener;
 import javax.swing.event.DocumentEvent;
 import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionListener;
 
 import net.miginfocom.swing.MigLayout;
 
@@ -102,13 +106,13 @@ public class GRestServiceEditorPane extends JPanel {
                     cpanel,
                     "What kind of function the service performs (e.g. alignment, analysis, search, etc).",
                     new JLabel("Service Action:"), action,"wrap");
-    descr = new JTextArea(4, 40);
+    descr = new JTextArea(4, 60);
     descrVp = new JScrollPane();
     descrVp.setViewportView(descr);
     JvSwingUtils.mgAddtoLayout(cpanel, "Brief description of service",
             new JLabel("Description:"), descrVp,"wrap");
 
-    url = new JTextArea(2, 20);
+    url = new JTextArea(2, 60);
     urlVp = new JScrollPane();
     urlVp.setViewportView(url);
     JvSwingUtils
@@ -118,7 +122,7 @@ public class GRestServiceEditorPane extends JPanel {
                     new JLabel("POST URL:"), urlVp,"wrap");
 
     urlsuff = new JTextArea();
-    urlsuff.setColumns(20);
+    urlsuff.setColumns(60);
 
     JvSwingUtils
             .mgAddtoLayout(
@@ -179,10 +183,51 @@ public class GRestServiceEditorPane extends JPanel {
     // Inputparams
     JPanel iprmsList = new JPanel();
     iprmsList.setBorder(new TitledBorder("Data input parameters"));
-    iprmsList.setLayout(new MigLayout());
+    iprmsList.setLayout(new MigLayout("","[grow 90, fill][]"));
     iprmVp = new JScrollPane();
     iprmVp.getViewport().setView(iprms = new JList());
     iprmsList.add(iprmVp);
+    iprms.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+    iprms.addMouseListener(new MouseListener()
+    {
+      
+      @Override
+      public void mouseReleased(MouseEvent e)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public void mousePressed(MouseEvent e)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public void mouseExited(MouseEvent e)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public void mouseEntered(MouseEvent e)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public void mouseClicked(MouseEvent e)
+      {
+        if (e.getClickCount()>1) {
+          iprmListSelection_doubleClicked();
+        }
+         
+      }
+    });
     JPanel iprmButs = new JPanel();
     iprmButs.setLayout(new MigLayout());
 
@@ -263,8 +308,49 @@ public class GRestServiceEditorPane extends JPanel {
 
     JPanel rparamList = new JPanel();
     rparamList.setBorder(new TitledBorder("Data returned by service"));
-    rparamList.setLayout(new MigLayout());
+    rparamList.setLayout(new MigLayout("","[grow 90, fill][]"));
     rdata = new JList();
+    rdata.setToolTipText("Right click to edit currently selected parameter.");
+    rdata.addMouseListener(new MouseListener()
+    {
+      
+      @Override
+      public void mouseReleased(MouseEvent arg0)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public void mousePressed(MouseEvent arg0)
+      {
+        
+      }
+      
+      @Override
+      public void mouseExited(MouseEvent arg0)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public void mouseEntered(MouseEvent arg0)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public void mouseClicked(MouseEvent arg0)
+      {
+        if (arg0.getButton()==MouseEvent.BUTTON3)
+        {
+          rdata_rightClicked(arg0);
+        }
+        
+      }
+    });
     rdataVp = new JScrollPane();
     rdataVp.getViewport().setView(rdata);
     rparamList.add(rdataVp);
@@ -280,7 +366,7 @@ public class GRestServiceEditorPane extends JPanel {
     // Parse flat-text to a service
 
     
-    urldesc = new JTextArea(4,50);
+    urldesc = new JTextArea(4,60);
     urldesc.setEditable(true);
     urldesc.setWrapStyleWord(true);
     urldescVp = new JScrollPane();
@@ -296,7 +382,7 @@ public class GRestServiceEditorPane extends JPanel {
     parseResVp = new JScrollPane();
     parseResVp.setViewportView(parseRes);
     parseRes.setWrapStyleWord(true);
-    parseRes.setColumns(40);
+    parseRes.setColumns(60);
     parseWarnings = new JPanel(new MigLayout("","[grow 100, fill]", "[grow 100, fill]"));
     parseWarnings.setBorder(new TitledBorder("Parsing errors"));
     parseWarnings.setToolTipText("<html>"+JvSwingUtils.wrapTooltip("Results of parsing the RSBS representation")+"</html>");
@@ -327,6 +413,18 @@ public class GRestServiceEditorPane extends JPanel {
 
   }
 
+  protected void rdata_rightClicked(MouseEvent arg0)
+  {
+    // TODO Auto-generated method stub
+    
+  }
+
+  protected void iprmListSelection_doubleClicked()
+  {
+    // TODO Auto-generated method stub
+    
+  }
+
   protected void hSeparable_actionPerformed(ActionEvent arg0)
   {
     // TODO Auto-generated method stub
index 3c0b511..bc55893 100644 (file)
@@ -1,5 +1,11 @@
 package jalview.ws.rest;
 
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.InvalidArgumentException;
+import jalview.ws.params.OptionI;
+import jalview.ws.params.ParameterI;
+import jalview.ws.params.simple.IntegerParameter;
+import jalview.ws.params.simple.Option;
 import jalview.ws.rest.params.SeqGroupIndexVector;
 
 import java.io.IOException;
@@ -10,6 +16,7 @@ import java.io.StringWriter;
 import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.regex.Matcher;
@@ -32,7 +39,17 @@ public abstract class InputType {
    * not used yet
    */
   boolean replaceids;
-  public enum molType { NUC, PROT, MIX}
+  public enum molType { NUC, PROT, MIX;
+
+  public static Collection<String> toStringValues()
+  {
+    Collection<String> c = new ArrayList<String>();
+    for (molType type:values())
+    {
+      c.add(type.toString());
+    }
+    return c;
+  }}
   public String token;
   public int min=1;
   public int max=0; // unbounded
@@ -120,7 +137,7 @@ public abstract class InputType {
    * @return true if property was set
    */
   public abstract boolean configureProperty(String tok, String val, StringBuffer warnings);
-  
+    
   /**
    * Get unique key for this type of parameter in a URL encoding.
    * @return the string that prefixes an input parameter of InputType<T> type in the string returned from getURLEncodedParameter
@@ -157,7 +174,13 @@ public abstract class InputType {
                 warnings.append("Invalid value for parameter "+mtch.group(1).toLowerCase()+" '"+mtch.group(2)+"' (expected an integer)\n");
             }
           
-          valid = valid && configureProperty(mtch.group(1), mtch.group(2), warnings);
+          if (!configureProperty(mtch.group(1), mtch.group(2), warnings)) {
+            if (warnings.length()==0)
+            {
+              warnings.append("Failed to configure InputType :"+getURLtokenPrefix()+" with property string: '"+mtch.group(0)+"'\n (token is '"+mtch.group(1)+"' and value is '"+mtch.group(2)+"')\n");
+            }
+            valid=false;
+          }
         }
         }
       return valid;
@@ -169,7 +192,58 @@ public abstract class InputType {
       prms.add("min='"+min+"'");
     }
     if (max!=0) {
-      prms.add("min='"+max+"'");
+      prms.add("max='"+max+"'");
     }
   }
+  
+  public abstract List<OptionI> getOptions();
+  public List<OptionI> getBaseOptions()
+  {
+    ArrayList<OptionI> opts = new ArrayList<OptionI>();
+    opts.add(new IntegerParameter("min","Minimum number of data of this type",true,1,min,0,-1));
+    opts.add(new IntegerParameter("max","Maximum number of data of this type",false,0,max,0,-1));
+    return opts;
+  }
+  /**
+   * make a copy of this InputType
+   * @return
+   * may not be needed
+  public abstract InputType copy();
+   */
+  
+  /**
+   * parse a set of configuration options
+   * @param currentSettings - modified settings originally from getOptions
+   * @throws InvalidArgumentException thrown if currentSettings contains invalid options for this type.
+   */
+  public void configureFromArgumentI(List<ArgumentI> currentSettings) throws InvalidArgumentException
+  {
+    ArrayList<String> urltoks = new ArrayList<String>();
+    String rg;
+    for (ArgumentI arg: currentSettings)
+    {
+      if (arg instanceof ParameterI)
+      {
+        rg=arg.getName()+"='"+arg.getValue()+"'";
+      } else {
+        // TODO: revise architecture - this is counter intuitive - options with different values to their names are actually parameters
+        rg=(arg.getValue().length()>0) ? (arg.getValue().equals(arg.getName()) ? arg.getName():arg.getName()+"='"+arg.getValue()+"'")
+                : arg.getName();
+      } 
+      if (rg.length()>0) {
+        urltoks.add(rg);
+      }
+    }
+    StringBuffer warnings;
+    if (!configureFromURLtokenString(urltoks, warnings=new StringBuffer()))
+    {
+      throw new InvalidArgumentException(warnings.toString());
+    }
+  }
+  protected OptionI createMolTypeOption(String name, String descr,
+          boolean req, molType curType, molType defType)
+  {
+    return new Option(name,descr, req, defType==null ? "" : defType.toString(), curType==null ? "" : curType.toString(),molType.toStringValues(),
+            null);
+  }
 }
\ No newline at end of file
index 20895a2..dec4d7c 100644 (file)
@@ -64,12 +64,15 @@ public class RestServiceDescription
   {
     super();
     this.details = new UIinfo();
-    details.Action = action;
-    details.description = description;
-    details.Name = name;
-    this.postUrl = postUrl;
-    this.urlSuffix = urlSuffix;
-    this.inputParams = inputParams;
+    details.Action = action == null ? "" : action;
+    details.description = description == null ? "" : description;
+    details.Name = name == null ? "" : name;
+    this.postUrl = postUrl == null ? "" : postUrl;
+    this.urlSuffix = urlSuffix == null ? "" : urlSuffix;
+    if (inputParams != null)
+    {
+      this.inputParams = inputParams;
+    }
     this.hseparable = hseparable;
     this.vseparable = vseparable;
     this.gapCharacter = gapCharacter;
@@ -229,7 +232,7 @@ public class RestServiceDescription
   /**
    * input info given as key/value pairs - mapped to post arguments
    */
-  Map<String, InputType> inputParams = new HashMap<String,InputType>();
+  Map<String, InputType> inputParams = new HashMap<String, InputType>();
 
   /**
    * assigns the given inputType it to its corresponding input parameter token
@@ -318,30 +321,20 @@ public class RestServiceDescription
 
   public RestServiceDescription(RestServiceDescription toedit)
   {
-    // Rather then do the above, we cheat and use our human readable serialization code to clone everything
+    // Rather then do the above, we cheat and use our human readable
+    // serialization code to clone everything
     this(toedit.toString());
     /**
-    if (toedit == null)
-    {
-      return;
-    }
-    /**
-    urlSuffix = toedit.urlSuffix;
-    postUrl = toedit.postUrl;
-    hseparable = toedit.hseparable;
-    vseparable = toedit.vseparable;
-    gapCharacter = toedit.gapCharacter;
-    details = new RestServiceDescription.UIinfo();
-    details.Action = toedit.details.Action;
-    details.description = toedit.details.description;
-    details.Name = toedit.details.Name;
-    for (InputType itype: toedit.inputParams.values())
-    {
-      inputParams.put(itype.token, itype.clone());
-      
-    }
-            
-       */
+     * if (toedit == null) { return; } /** urlSuffix = toedit.urlSuffix; postUrl
+     * = toedit.postUrl; hseparable = toedit.hseparable; vseparable =
+     * toedit.vseparable; gapCharacter = toedit.gapCharacter; details = new
+     * RestServiceDescription.UIinfo(); details.Action = toedit.details.Action;
+     * details.description = toedit.details.description; details.Name =
+     * toedit.details.Name; for (InputType itype: toedit.inputParams.values()) {
+     * inputParams.put(itype.token, itype.clone());
+     * 
+     * }
+     */
     // TODO Implement copy constructor NOW*/
   }
 
@@ -380,12 +373,13 @@ public class RestServiceDescription
       return null;
     java.util.ArrayList<String> jv = new ArrayList<String>();
     int cp = 0, pos, escape;
-    boolean wasescaped = false;
+    boolean wasescaped = false,wasquoted=false;
     String lstitem = null;
     while ((pos = list.indexOf(separator, cp)) >= cp)
     {
-      escape = (pos>0 && list.charAt(pos - 1) == '\\') ? -1 : 0;
-      if (wasescaped)
+      
+      escape = (pos > 0 && list.charAt(pos - 1) == '\\') ? -1 : 0;
+      if (wasescaped || wasquoted)
       {
         // append to previous pos
         jv.set(jv.size() - 1,
@@ -399,11 +393,20 @@ public class RestServiceDescription
       }
       cp = pos + seplen;
       wasescaped = escape == -1;
+      if (!wasescaped)
+      {
+        // last separator may be in an unmatched quote
+        if (java.util.regex.Pattern.matches("('[^']*')*[^']*'",lstitem))
+        {
+          wasquoted=true;
+        }
+      }
+      
     }
     if (cp < list.length())
     {
       String c = list.substring(cp);
-      if (wasescaped)
+      if (wasescaped || wasquoted)
       {
         // append final separator
         jv.set(jv.size() - 1, lstitem + separator + c);
@@ -455,7 +458,7 @@ public class RestServiceDescription
       {
         if (list[i] != null)
         {
-          if (v.length()>0)
+          if (v.length() > 0)
           {
             v.append(separator);
           }
@@ -496,7 +499,7 @@ public class RestServiceDescription
       return true;
     }
     ;
-    boolean valid=true;
+    boolean valid = true;
     String val = null;
     int i;
     for (String prop : props)
@@ -521,9 +524,9 @@ public class RestServiceDescription
       }
       if (prop.equals("gapCharacter"))
       {
-        if (val == null || val.length()==0 || val.length() > 1)
+        if (val == null || val.length() == 0 || val.length() > 1)
         {
-          valid=false;
+          valid = false;
           warnings.append((warnings.length() > 0 ? "\n" : "")
                   + ("Invalid service property: gapCharacter=' ' (single character) - was given '"
                           + val + "'"));
@@ -535,9 +538,9 @@ public class RestServiceDescription
       }
       if (prop.equals("returns"))
       {
-        int l=warnings.length();
+        int l = warnings.length();
         _configureOutputFormatFrom(val, warnings);
-        valid =  (l!=warnings.length());
+        valid = (l != warnings.length());
       }
     }
     return valid;
@@ -546,7 +549,7 @@ public class RestServiceDescription
   private String _genOutputFormatString()
   {
     String buff = "";
-    if (resultData==null)
+    if (resultData == null)
     {
       return "";
     }
@@ -564,9 +567,10 @@ public class RestServiceDescription
   private void _configureOutputFormatFrom(String outstring,
           StringBuffer warnings)
   {
-    if (outstring.indexOf(";")==-1) {
+    if (outstring.indexOf(";") == -1)
+    {
       // we add a token, for simplicity
-      outstring = outstring+";";
+      outstring = outstring + ";";
     }
     StringTokenizer st = new StringTokenizer(outstring, ";");
     String tok = "";
@@ -637,7 +641,7 @@ public class RestServiceDescription
     details.Name = list[0];
     details.Action = list[1];
     details.description = list[2];
-    invalid|=!configureFromServiceInputProperties(list[3], warnings);
+    invalid |= !configureFromServiceInputProperties(list[3], warnings);
     if (list.length > 5)
     {
       urlSuffix = list[4];
@@ -645,8 +649,11 @@ public class RestServiceDescription
     }
     else
     {
-      urlSuffix = null;
-      invalid |= !configureFromInputParamEncodedUrl(list[4], warnings);
+      if (list.length > 4)
+      {
+        urlSuffix = null;
+        invalid |= !configureFromInputParamEncodedUrl(list[4], warnings);
+      }
     }
     return !invalid;
   }
@@ -746,7 +753,8 @@ public class RestServiceDescription
         iprmparams = iprm.substring(colon + 1);
         iprm = iprm.substring(0, colon);
       }
-      valid = parseTypeString(prms.group(0), tok,  iprm, iprmparams, iparams, warnings);
+      valid = parseTypeString(prms.group(0), tok, iprm, iprmparams,
+              iparams, warnings);
     }
     if (valid)
     {
@@ -764,19 +772,25 @@ public class RestServiceDescription
     return valid;
   }
 
-  public static boolean parseTypeString(String fullstring, String tok, String iprm, String iprmparams,
-           Map<String, InputType> iparams, StringBuffer warnings)
+  public static Class[] getInputTypes()
   {
-    boolean valid=true;
-    InputType jinput;
     // TODO - find a better way of maintaining this classlist
-    for (Class type : new Class[]
+    return new Class[]
     { jalview.ws.rest.params.Alignment.class,
         jalview.ws.rest.params.AnnotationFile.class,
         SeqGroupIndexVector.class,
         jalview.ws.rest.params.SeqIdVector.class,
         jalview.ws.rest.params.SeqVector.class,
-        jalview.ws.rest.params.Tree.class })
+        jalview.ws.rest.params.Tree.class };
+  }
+
+  public static boolean parseTypeString(String fullstring, String tok,
+          String iprm, String iprmparams, Map<String, InputType> iparams,
+          StringBuffer warnings)
+  {
+    boolean valid = true;
+    InputType jinput;
+    for (Class type : getInputTypes())
     {
       try
       {
@@ -786,20 +800,20 @@ public class RestServiceDescription
           ArrayList<String> al = new ArrayList<String>();
           for (String prprm : separatorListToArray(iprmparams, ","))
           {
+            // hack to ensure that strings like "sep=','" containing unescaped commas as values are concatenated
             al.add(prprm.trim());
           }
           if (!jinput.configureFromURLtokenString(al, warnings))
           {
             valid = false;
-            warnings.append("Failed to parse '" + fullstring
-                    + "' as a " + jinput.getURLtokenPrefix()
-                    + " input tag.\n");
+            warnings.append("Failed to parse '" + fullstring + "' as a "
+                    + jinput.getURLtokenPrefix() + " input tag.\n");
           }
           else
           {
             jinput.token = tok;
             iparams.put(tok, jinput);
-            valid=true;
+            valid = true;
           }
           break;
         }
@@ -812,9 +826,20 @@ public class RestServiceDescription
     return valid;
   }
 
-
   public static void main(String argv[])
   {
+    // test separator list
+    try {
+      assert(separatorListToArray("foo=',',min='foo',max='1,2,3',fa=','", ",").length==4);
+      if (separatorListToArray("minsize='2', sep=','", ",").length==2)
+      {
+        assert(false);
+      }
+      
+    } catch (AssertionError x)
+    {
+      System.err.println("separatorListToArray is faulty.");
+    }
     if (argv.length == 0)
     {
       if (!testRsdExchange("Test using default Shmmr service",
@@ -971,7 +996,7 @@ public class RestServiceDescription
     return jobId + urlSuffix;
   }
 
-  private List<JvDataType> resultData=new ArrayList<JvDataType>();
+  private List<JvDataType> resultData = new ArrayList<JvDataType>();
 
   /**
    * 
@@ -1003,5 +1028,5 @@ public class RestServiceDescription
   {
     return resultData;
   }
-  
+
 }
index 770b564..dc6e6e8 100644 (file)
@@ -1,6 +1,9 @@
 package jalview.ws.rest.params;
 
 import jalview.datamodel.AlignmentI;
+import jalview.ws.params.OptionI;
+import jalview.ws.params.simple.BooleanOption;
+import jalview.ws.params.simple.Option;
 import jalview.ws.rest.InputType;
 import jalview.ws.rest.NoValidInputDataException;
 import jalview.ws.rest.RestJob;
@@ -18,6 +21,7 @@ import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.http.entity.mime.content.ContentBody;
@@ -47,7 +51,7 @@ public class Alignment extends InputType
   /**
    * input data as a file upload rather than inline content
    */
-  public boolean writeAsFile;
+  public boolean writeAsFile=false;
 
   @Override
   public ContentBody formatForInput(RestJob rj)
@@ -165,4 +169,20 @@ public class Alignment extends InputType
     }
     return false;
   }
+  @Override
+  public List<OptionI> getOptions()
+  {
+    List<OptionI> lst = getBaseOptions();
+    lst.add(new BooleanOption("jvsuffix","Append jalview style /start-end suffix to ID", false, false, jvsuffix, null));
+    lst.add(new BooleanOption("writeasfile","Append jalview style /start-end suffix to ID", false, false, writeAsFile, null));
+    
+    lst.add(new Option("format",
+            "Alignment upload format", true, "FASTA",
+            format, Arrays.asList(jalview.io.FormatAdapter.WRITEABLE_FORMATS), null));
+    lst.add(createMolTypeOption("type", "Sequence type", false, type,
+            null));
+    
+    return lst;
+  }
+
 }
\ No newline at end of file
index 5abf0fc..b1681a0 100644 (file)
@@ -1,6 +1,8 @@
 package jalview.ws.rest.params;
 
 import jalview.datamodel.AlignmentI;
+import jalview.ws.params.OptionI;
+import jalview.ws.params.simple.Option;
 import jalview.ws.rest.InputType;
 import jalview.ws.rest.NoValidInputDataException;
 import jalview.ws.rest.RestJob;
@@ -9,6 +11,7 @@ import jalview.ws.rest.InputType.molType;
 
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.http.entity.mime.content.ContentBody;
@@ -90,4 +93,15 @@ public class AnnotationFile extends InputType {
     }
     return false;
   }
+  @Override
+  public List<OptionI> getOptions()
+  {
+    // TODO - consider disregarding base options here.
+    List<OptionI> lst = getBaseOptions();
+    lst.add(new Option("format",
+            "Alignment annotation upload format", true, JVANNOT,
+            format, Arrays.asList(new String[]
+            { JVANNOT, CSVANNOT}), null));
+    return lst;
+  }
 }
index 01b54cb..fddfd3b 100644 (file)
@@ -1,5 +1,6 @@
 package jalview.ws.rest.params;
 
+import jalview.ws.params.OptionI;
 import jalview.ws.rest.InputType;
 import jalview.ws.rest.NoValidInputDataException;
 import jalview.ws.rest.RestJob;
@@ -80,4 +81,11 @@ public class JobConstant extends InputType
     warnings.append("IMPLEMENTATION ERROR: No Properties to configure for a Constant parameter.");
     return false;
   }
+
+  @Override
+  public List<OptionI> getOptions()
+  {
+    // empty list - this parameter isn't configurable, so don't try.
+    return new ArrayList<OptionI>();
+  }
 }
index 7df7d1c..ba2c1b3 100644 (file)
@@ -3,6 +3,9 @@ package jalview.ws.rest.params;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.ws.params.OptionI;
+import jalview.ws.params.simple.IntegerParameter;
+import jalview.ws.params.simple.Option;
 import jalview.ws.rest.AlignmentProcessor;
 import jalview.ws.rest.InputType;
 import jalview.ws.rest.NoValidInputDataException;
@@ -12,6 +15,7 @@ import jalview.ws.rest.InputType.molType;
 
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Vector;
 
@@ -70,12 +74,13 @@ public class SeqGroupIndexVector extends InputType implements
     // assume that alignment is properly ordered so groups form consecutive
     // blocks
     ArrayList<int[]> gl = new ArrayList<int[]>();
-    int p=0;
+    int p = 0;
     for (SequenceGroup sg : (Vector<SequenceGroup>) al.getGroups())
     {
-      if (sg.getSize()<minsize)
+      if (sg.getSize() < minsize)
       {
-        throw new NoValidInputDataException("Group contains less than "+minsize+" sequences.");
+        throw new NoValidInputDataException("Group contains less than "
+                + minsize + " sequences.");
       }
       // TODO: refactor to sequenceGroup for efficiency -
       // getAlignmentRowInterval(AlignmentI al)
@@ -101,40 +106,62 @@ public class SeqGroupIndexVector extends InputType implements
         gl.add(se);
       }
     }
-    // are there any more sequences ungrouped that should be added as a single remaining group ? - these might be at the start or the end
-    if (gl.size()>0)
+    // are there any more sequences ungrouped that should be added as a single
+    // remaining group ? - these might be at the start or the end
+    if (gl.size() > 0)
     {
-      int[] tail=gl.get(0);
-      if (tail[0]>0) {
-        if (1+tail[0]>minsize)
+      int[] tail = gl.get(0);
+      if (tail[0] > 0)
       {
-        gl.add(0,new int[] { 0,tail[0]-1});
-      } else {
-        // lets be intelligent here - if the remaining sequences aren't enough to make a final group, then don't make one.
-        // throw new NoValidInputDataException("Group from remaining ungrouped sequences in input contains less than "+minsize+" sequences.");       
+        if (1 + tail[0] > minsize)
+        {
+          gl.add(0, new int[]
+          { 0, tail[0] - 1 });
+        }
+        else
+        {
+          // lets be intelligent here - if the remaining sequences aren't enough
+          // to make a final group, then don't make one.
+          // throw new
+          // NoValidInputDataException("Group from remaining ungrouped sequences in input contains less than "+minsize+" sequences.");
+        }
       }
-      } else {
-        tail=gl.get(gl.size()-1);
-        if (1+tail[1]<al.getHeight())
+      else
+      {
+        tail = gl.get(gl.size() - 1);
+        if (1 + tail[1] < al.getHeight())
         {
-          if (al.getHeight()-(1+tail[1])>minsize) {
-            gl.add(new int[] { tail[1]+1, al.getHeight()-1});            
-          } else {
-            // lets be intelligent here - if the remaining sequences aren't enough to make a final group, then don't make one.
-            //  throw new NoValidInputDataException("Group from remaining ungrouped sequences in input contains less than "+minsize+" sequences.");       
+          if (al.getHeight() - (1 + tail[1]) > minsize)
+          {
+            gl.add(new int[]
+            { tail[1] + 1, al.getHeight() - 1 });
+          }
+          else
+          {
+            // lets be intelligent here - if the remaining sequences aren't
+            // enough to make a final group, then don't make one.
+            // throw new
+            // NoValidInputDataException("Group from remaining ungrouped sequences in input contains less than "+minsize+" sequences.");
           }
         }
       }
-    } else {
-      gl.add(new int[] { 0, al.getHeight()-1});
     }
-    if (min>=0 && gl.size()<min)
+    else
     {
-      throw new NoValidInputDataException("Not enough sequence groups for input. Need at least "+min+" groups (including ungrouped regions).");
+      gl.add(new int[]
+      { 0, al.getHeight() - 1 });
     }
-    if (max>0 && gl.size()>max)
+    if (min >= 0 && gl.size() < min)
     {
-      throw new NoValidInputDataException("Too many sequence groups for input. Need at most "+max+" groups (including ungrouped regions).");
+      throw new NoValidInputDataException(
+              "Not enough sequence groups for input. Need at least " + min
+                      + " groups (including ungrouped regions).");
+    }
+    if (max > 0 && gl.size() > max)
+    {
+      throw new NoValidInputDataException(
+              "Too many sequence groups for input. Need at most " + max
+                      + " groups (including ungrouped regions).");
     }
     int[][] vals = gl.toArray(new int[gl.size()][]);
     int[] srt = new int[gl.size()];
@@ -160,28 +187,34 @@ public class SeqGroupIndexVector extends InputType implements
   }
 
   /**
-   * set minimum number of sequences allowed in a partition. Default is 1 sequence.
-   * @param i (number greater than 1)
+   * set minimum number of sequences allowed in a partition. Default is 1
+   * sequence.
+   * 
+   * @param i
+   *          (number greater than 1)
    */
   public void setMinsize(int i)
   {
-    if (minsize>=1)
-      {
-      minsize=i;
-      } else {
-        minsize=1;
-      }
+    if (minsize >= 1)
+    {
+      minsize = i;
+    }
+    else
+    {
+      minsize = 1;
+    }
   }
+
   @Override
   public List<String> getURLEncodedParameter()
   {
     ArrayList<String> prms = new ArrayList<String>();
     super.addBaseParams(prms);
-    prms.add("minsize='"+ minsize+"'");
-    prms.add("sep='"+ sep+"'");
-    if (type!=null)
+    prms.add("minsize='" + minsize + "'");
+    prms.add("sep='" + sep + "'");
+    if (type != null)
     {
-      prms.add("type='"+type+"'");
+      prms.add("type='" + type + "'");
     }
     return prms;
   }
@@ -199,32 +232,36 @@ public class SeqGroupIndexVector extends InputType implements
 
     if (tok.startsWith("sep"))
     {
-      sep=val;
+      sep = val;
       return true;
     }
     if (tok.startsWith("minsize"))
     {
-      try {
-        minsize=Integer.valueOf(val);
-        if (minsize>=0)
-        return true;
+      try
+      {
+        minsize = Integer.valueOf(val);
+        if (minsize >= 0)
+          return true;
       } catch (Exception x)
       {
-        
+
       }
-      warnings.append("Invalid minsize value '"+val+"'. Must be a positive integer.\n");
+      warnings.append("Invalid minsize value '" + val
+              + "'. Must be a positive integer.\n");
     }
     if (tok.startsWith("type"))
     {
-      try {
-        type=molType.valueOf(val);
+      try
+      {
+        type = molType.valueOf(val);
         return true;
       } catch (Exception x)
       {
-        warnings.append("Invalid molecule type '"+val+"'. Must be one of (");
-        for (molType v:molType.values())
+        warnings.append("Invalid molecule type '" + val
+                + "'. Must be one of (");
+        for (molType v : molType.values())
         {
-          warnings.append(" "+v);
+          warnings.append(" " + v);
         }
         warnings.append(")\n");
       }
@@ -232,4 +269,17 @@ public class SeqGroupIndexVector extends InputType implements
     return false;
   }
 
+  @Override
+  public List<OptionI> getOptions()
+  {
+    List<OptionI> lst = getBaseOptions();
+    lst.add(new Option("sep",
+            "Separator character between elements of vector", true, ",",
+            sep, Arrays.asList(new String[]
+            { " ", ",", ";", "\t", "|" }), null));
+    lst.add(new IntegerParameter("minsize", "Minimum size of partition allowed by service", true, 1, minsize, 1,0));
+    lst.add(createMolTypeOption("type", "Sequence type", false, type, molType.MIX));
+    return lst;
+  }
+
 }
index 5f7c551..c77c8da 100644 (file)
@@ -2,6 +2,8 @@ package jalview.ws.rest.params;
 
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
+import jalview.ws.params.OptionI;
+import jalview.ws.params.simple.Option;
 import jalview.ws.rest.InputType;
 import jalview.ws.rest.NoValidInputDataException;
 import jalview.ws.rest.RestJob;
@@ -10,6 +12,7 @@ import jalview.ws.rest.InputType.molType;
 
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -18,27 +21,33 @@ import org.apache.http.entity.mime.content.ContentBody;
 import org.apache.http.entity.mime.content.StringBody;
 
 /**
- * input a list of sequence IDs separated by some separator 
+ * input a list of sequence IDs separated by some separator
+ * 
  * @author JimP
- *
+ * 
  */
-public class SeqIdVector extends InputType {
+public class SeqIdVector extends InputType
+{
   public SeqIdVector()
   {
-    super(new Class[] { AlignmentI.class} );
+    super(new Class[]
+    { AlignmentI.class });
   }
 
   /**
    * separator for list of sequence IDs - default is ','
    */
-  String sep=",";
+  String sep = ",";
+
   molType type;
+
   @Override
-  public ContentBody formatForInput(RestJob rj) throws UnsupportedEncodingException, NoValidInputDataException
+  public ContentBody formatForInput(RestJob rj)
+          throws UnsupportedEncodingException, NoValidInputDataException
   {
     StringBuffer idvector = new StringBuffer();
-    boolean list=false;
-    for (SequenceI seq:rj.getSequencesForInput(token, type))
+    boolean list = false;
+    for (SequenceI seq : rj.getSequencesForInput(token, type))
     {
       if (list)
       {
@@ -47,44 +56,66 @@ public class SeqIdVector extends InputType {
       idvector.append(seq.getName());
     }
     return new StringBody(idvector.toString());
-  }  
+  }
+
   @Override
   public List<String> getURLEncodedParameter()
   {
     ArrayList<String> prms = new ArrayList<String>();
     super.addBaseParams(prms);
-    prms.add("sep='"+ sep+"'");
-    prms.add("type='"+type+"'");
+    prms.add("sep='" + sep + "'");
+    if (type!=null)
+    {
+      prms.add("type='"+type+"'");
+    }
     return prms;
   }
+
   @Override
   public String getURLtokenPrefix()
   {
     return "SEQIDS";
   }
+
   @Override
-  public boolean configureProperty(String tok, String val, StringBuffer warnings)
+  public boolean configureProperty(String tok, String val,
+          StringBuffer warnings)
   {
     if (tok.startsWith("sep"))
     {
-      sep=val;
+      sep = val;
       return true;
     }
     if (tok.startsWith("type"))
     {
-      try {
-        type=molType.valueOf(val);
+      try
+      {
+        type = molType.valueOf(val);
         return true;
       } catch (Exception x)
       {
-        warnings.append("Invalid molecule type '"+val+"'. Must be one of (");
-        for (molType v:molType.values())
+        warnings.append("Invalid molecule type '" + val
+                + "'. Must be one of (");
+        for (molType v : molType.values())
         {
-          warnings.append(" "+v);
+          warnings.append(" " + v);
         }
         warnings.append(")\n");
       }
     }
     return false;
   }
+
+  @Override
+  public List<OptionI> getOptions()
+  {
+    List<OptionI> lst = getBaseOptions();
+    lst.add(new Option("sep",
+            "Separator character between elements of vector", true, ",",
+            sep, Arrays.asList(new String[]
+            { " ", ",", ";", "\t", "|" }), null));
+    lst.add(createMolTypeOption("type", "Sequence type", false, type,
+            null));
+    return lst;
+  }
 }
index 3a5b414..040e000 100644 (file)
@@ -2,6 +2,8 @@ package jalview.ws.rest.params;
 
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
+import jalview.ws.params.OptionI;
+import jalview.ws.params.simple.Option;
 import jalview.ws.rest.InputType;
 import jalview.ws.rest.NoValidInputDataException;
 import jalview.ws.rest.RestJob;
@@ -10,10 +12,12 @@ import jalview.ws.rest.InputType.molType;
 
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.http.entity.mime.content.ContentBody;
 import org.apache.http.entity.mime.content.StringBody;
+import org.jmol.util.ArrayUtil;
 
 /**
  * input a list of sequences separated by some separator 
@@ -49,7 +53,10 @@ public class SeqVector extends InputType {
     ArrayList<String> prms = new ArrayList<String>();
     super.addBaseParams(prms);
     prms.add("sep='"+ sep+"'");
-    prms.add("type='"+type+"'");
+    if (type!=null)
+    {
+      prms.add("type='"+type+"'");
+    }
     return prms;
   }
 
@@ -87,4 +94,18 @@ public class SeqVector extends InputType {
     return false;
   }
 
+  @Override
+  public List<OptionI> getOptions()
+  {
+    List<OptionI> lst = getBaseOptions();
+    lst.add(new Option("sep",
+            "Separator character between elements of vector", true, ",",
+            sep, Arrays.asList(new String[]
+            { " ", ",", ";", "\t", "|" }), null));
+    lst.add(createMolTypeOption("type", "Sequence type", false, type,
+            molType.MIX));
+    
+    return lst;
+  }
+
 }
\ No newline at end of file
index 69d2f58..ff54654 100644 (file)
@@ -1,6 +1,8 @@
 package jalview.ws.rest.params;
 
 import jalview.datamodel.AlignmentI;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.OptionI;
 import jalview.ws.rest.InputType;
 import jalview.ws.rest.RestJob;
 import jalview.ws.rest.RestServiceDescription;
@@ -53,4 +55,10 @@ public class Tree extends InputType {
     return true;
   }
 
+  @Override
+  public List<OptionI> getOptions()
+  {
+    return getBaseOptions();
+  }
+
 }
\ No newline at end of file