added URL display for parameters/options and debugged parameter set switching
[jalview.git] / src / jalview / gui / WsJobParameters.java
index 89028ef..e7ecc03 100644 (file)
@@ -23,6 +23,7 @@ import java.awt.event.MouseListener;
 import java.awt.event.WindowEvent;
 import java.awt.event.WindowListener;
 import java.awt.event.WindowStateListener;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.EventObject;
 import java.util.HashSet;
@@ -35,14 +36,18 @@ import java.util.Vector;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
+import javax.swing.JComponent;
 import javax.swing.JDialog;
 import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JList;
+import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
 import javax.swing.JScrollPane;
 import javax.swing.JSlider;
+import javax.swing.JSplitPane;
 import javax.swing.JTable;
 import javax.swing.JTextArea;
 import javax.swing.JTextField;
@@ -53,6 +58,8 @@ import javax.swing.border.TitledBorder;
 import javax.swing.event.CellEditorListener;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
 import javax.swing.table.*;
 
 import compbio.metadata.Argument;
@@ -65,19 +72,45 @@ import compbio.metadata.ValueConstrain;
 import compbio.metadata.WrongParameterException;
 import compbio.metadata.ValueConstrain.Type;
 
+import jalview.util.jarInputStreamProvider;
 import jalview.ws.jws2.Jws2Discoverer;
+import jalview.ws.jws2.ParameterUtils;
 import jalview.ws.jws2.Jws2Discoverer.Jws2Instance;
 
+/**
+ * job parameter editing/browsing dialog box. User can browse existing settings
+ * (user + presets + Defaults), and any changes to parameters creates a modified
+ * user parameter set. LOGIC: If the parameter set is modified, and its name is
+ * a valid, non-existant user parameter set, then a save button is shown. If the
+ * parameter set is modified and its name is a valid, extant user parameter set,
+ * then an update button is shown. If user parameter set's name is edited, and
+ * old name exists as a writable user parameter set, then rename button is
+ * shown. If current parameter set is associated with a user defined parameter
+ * set, then : if set is modifed, a 'revert' button is shown. if set is not
+ * modified, a 'delete' button is shown.
+ * 
+ * @author JimP
+ * 
+ */
 public class WsJobParameters extends JPanel implements ItemListener,
-        ActionListener
+        ActionListener, DocumentListener
 {
-  private static final int PARAM_WIDTH = 340, PARAM_HEIGHT = 150,PARAM_CLOSEDHEIGHT=80;
+  private static final String SVC_DEF = "Defaults"; // this is the null
+                                                    // parameter set as shown to
+                                                    // user
+
+  private static final int PARAM_WIDTH = 340, PARAM_HEIGHT = 150,
+          PARAM_CLOSEDHEIGHT = 80;
 
   private static final int OPTSET_HEIGHT = 30;
 
+  JPanel SetNamePanel = new JPanel();
+
   JPanel setDetails = new JPanel();
 
-  JPanel settingsPanel = new JPanel();
+  JSplitPane settingsPanel = new JSplitPane();
+
+  JSplitPane jobPanel = new JSplitPane();
 
   JPanel jobOptions = new JPanel();
 
@@ -85,28 +118,18 @@ public class WsJobParameters extends JPanel implements ItemListener,
 
   JPanel jobParameters = new JPanel();
 
-  JPanel paramButtons = new JPanel();
+  JButton savmodified = new JButton();
+
+  JButton renmodified = new JButton();
 
-  JPanel paramPanel = new JPanel();
+  JButton deletesetting = new JButton();
 
-  JLabel modified = new JLabel();
+  JButton revertsetting = new JButton();
 
   JButton startjob = new JButton();
 
   JButton canceljob = new JButton();
 
-  JButton exportParams = new JButton();
-
-  JButton importParams = new JButton();
-
-  JButton resetParams = new JButton();
-
-  JButton addParam = new JButton();
-
-  JButton removeParam = new JButton();
-
-  JButton editParam = new JButton();
-
   JComboBox setName = new JComboBox();
 
   JTextArea setDescr = new JTextArea();
@@ -118,8 +141,6 @@ public class WsJobParameters extends JPanel implements ItemListener,
 
   RunnerConfig serviceOptions;
 
-  List<Parameter> availableParameters;
-
   private BorderLayout jparamLayout;
 
   WsJobParameters(Jws2Instance service)
@@ -144,7 +165,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
   {
     super();
     jbInit();
-    argSetModified(false);
+    // argSetModified(false);
     // populate parameter table
     initForService(service, p, jobArgset);
     // display in new JFrame attached to parent.
@@ -155,6 +176,11 @@ public class WsJobParameters extends JPanel implements ItemListener,
 
   JDialog frame = null;
 
+  /**
+   * shows a modal dialog containing the parameters.
+   * 
+   * @return
+   */
   public boolean showRunDialog()
   {
 
@@ -163,9 +189,12 @@ public class WsJobParameters extends JPanel implements ItemListener,
     frame.setTitle("Edit parameters for " + service.getActionText());
     Rectangle deskr = Desktop.instance.getBounds();
     frame.setBounds(new Rectangle((int) (deskr.getCenterX() - 240),
-            (int) (deskr.getCenterY() - 92), 380, 385));
+            (int) (deskr.getCenterY() - 250), 480, 500));
     frame.setContentPane(this);
-
+    // should recover defaults from user prefs.
+    frame.validate();
+    settingsPanel.setDividerLocation(0.4);
+    jobPanel.setDividerLocation(0.3);
     frame.setVisible(true);
 
     if (response > 0)
@@ -175,73 +204,58 @@ public class WsJobParameters extends JPanel implements ItemListener,
     return false;
   }
 
+  protected JButton makeButton(String label, String tooltip,
+          ActionListener action)
+  {
+    JButton button = new JButton();
+    button.setText(label);
+    button.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
+    button.setForeground(Color.black);
+    button.setHorizontalAlignment(SwingConstants.CENTER);
+    button.setToolTipText(tooltip);
+    button.addActionListener(action);
+    return button;
+  }
+
   private void jbInit()
   {
-    modified.setText("*");
-    modified.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    modified.setForeground(Color.red);
-    modified.setHorizontalAlignment(SwingConstants.RIGHT);
+    savmodified = makeButton("Save", "Not implemented yet :) ",
+            new ActionListener()
+            {
+
+              public void actionPerformed(ActionEvent e)
+              {
+                savModified_actionPerformed(e);
+              }
+            });
+    renmodified = makeButton("Rename", "Not implemented yet :) ",
+            new ActionListener()
+            {
+
+              public void actionPerformed(ActionEvent e)
+              {
+                renModified_actionPerformed(e);
+              }
+            });
+    deletesetting = makeButton("Delete", "Not implemented yet :) ",
+            new ActionListener()
+            {
+
+              public void actionPerformed(ActionEvent e)
+              {
+                deleteSetting_actionPerformed(e);
+              }
+            });
+    revertsetting = makeButton("Revert", "Undo changes to parameters.",
+            new ActionListener()
+            {
+
+              public void actionPerformed(ActionEvent e)
+              {
+                revertSetting_actionPerformed(e);
+              }
+            });
 
-    exportParams.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    exportParams.setText("Export");
-    exportParams.setToolTipText("Export parameters to a file");
-    exportParams.addActionListener(new ActionListener()
-    {
-      public void actionPerformed(ActionEvent e)
-      {
-        exportParams_actionPerformed(e);
-      }
-    });
-    importParams.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    importParams.setText("Import");
-    importParams.setToolTipText("Import parameters from a file");
-    importParams.addActionListener(new ActionListener()
-    {
-      public void actionPerformed(ActionEvent e)
-      {
-        importParams_actionPerformed(e);
-      }
-    });
-    resetParams.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    resetParams.setText("Defaults");
-    resetParams.setToolTipText("Reset to defaults");
-    resetParams.addActionListener(new ActionListener()
-    {
-      public void actionPerformed(ActionEvent e)
-      {
-        resetParams_actionPerformed(e);
-      }
-    });
-    addParam.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    addParam.setText("Add");
-    addParam.setToolTipText("Add new parameter");
-    addParam.addActionListener(new ActionListener()
-    {
-      public void actionPerformed(ActionEvent e)
-      {
-        addParam_actionPerformed(e);
-      }
-    });
-    removeParam.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    removeParam.setText("Remove");
-    removeParam.setToolTipText("Remove selected parameter");
-    removeParam.addActionListener(new ActionListener()
-    {
-      public void actionPerformed(ActionEvent e)
-      {
-        removeParam_actionPerformed(e);
-      }
-    });
-    editParam.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
-    editParam.setText("Edit");
-    editParam.setToolTipText("Edit selected parameter");
-    editParam.addActionListener(new ActionListener()
-    {
-      public void actionPerformed(ActionEvent e)
-      {
-        editParam_actionPerformed(e);
-      }
-    });
     startjob.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
     startjob.setText("Start");
     startjob.setToolTipText("Start Job");
@@ -269,19 +283,28 @@ public class WsJobParameters extends JPanel implements ItemListener,
     setDescr.setWrapStyleWord(true);
     setDescr.setLineWrap(true);
     setDescr.setBackground(getBackground());
-    setDescr.setEditable(false);
+    setDescr.setEditable(true);
+    setDescr.getDocument().addDocumentListener(this);
     JScrollPane setDescrView = new JScrollPane();
     // setDescrView.setPreferredSize(new Dimension(350, 200));
     setDescrView.getViewport().setView(setDescr);
     setName.setEditable(true);
     setName.addItemListener(this);
     setName.getEditor().addActionListener(this);
-    modified.setPreferredSize(new Dimension(15, 15));
-    JPanel SetNamePanel = new JPanel();
     SetNamePanel.setLayout(new BorderLayout());
     SetNamePanel.add(setName, BorderLayout.WEST);
-    SetNamePanel.add(modified, BorderLayout.EAST);
-    setDetails.add(SetNamePanel, BorderLayout.NORTH);
+    // initial button visibility
+    deletesetting.setVisible(false);
+    revertsetting.setVisible(false);
+    renmodified.setVisible(false);
+    savmodified.setVisible(false);
+    JPanel setsavebuts = new JPanel();
+    setsavebuts.setLayout(new FlowLayout());
+    setsavebuts.add(revertsetting, BorderLayout.CENTER);
+    setsavebuts.add(renmodified, BorderLayout.CENTER);
+    setsavebuts.add(deletesetting, BorderLayout.CENTER);
+    setsavebuts.add(savmodified, BorderLayout.EAST);
+    SetNamePanel.add(setsavebuts, BorderLayout.EAST);
     setDetails.add(setDescrView, BorderLayout.CENTER);
     // setDetails.setPreferredSize(new Dimension(360, 100));
     jobParameters.setBorder(new TitledBorder("Parameters"));
@@ -289,101 +312,134 @@ public class WsJobParameters extends JPanel implements ItemListener,
     paramPane.setPreferredSize(new Dimension(360, 300));
     paramPane.getVerticalScrollBar().setUnitIncrement(20);
     // paramPanel.setPreferredSize(new Dimension(360, 300));
-    paramButtons.setLayout(new GridLayout(2, 3));
-    paramButtons.add(addParam);
-    paramButtons.add(editParam);
-    paramButtons.add(removeParam);
     // TODO: relayout buttons nicely
-    paramButtons.add(exportParams);
-    paramButtons.add(importParams);
-    paramButtons.add(resetParams);
     paramPane.getViewport().setView(paramList);
-    jobParameters.add(paramPane, BorderLayout.NORTH);
-    // jobParameters.add(paramButtons, BorderLayout.SOUTH);
-    settingsPanel.setLayout(new BorderLayout());
-    // settingsPanel.add(modified, BorderLayout.NORTH);
+    jobParameters.add(paramPane, BorderLayout.CENTER);
     JPanel jobOptionsPanel = new JPanel();
+    jobOptionsPanel.setLayout(new BorderLayout());
     jobOptionsPanel.setBorder(new TitledBorder("Options"));
     jobOptionsPane.getViewport().setView(jobOptions);
-    jobOptionsPanel.add(jobOptionsPane);
-    settingsPanel.add(jobOptionsPanel, BorderLayout.NORTH);
-    settingsPanel.add(jobParameters, BorderLayout.SOUTH);
+    jobOptionsPanel.add(jobOptionsPane, BorderLayout.CENTER);
+    settingsPanel.setLeftComponent(jobOptionsPanel);
+    settingsPanel.setRightComponent(jobParameters);
+    settingsPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
 
     setLayout(new BorderLayout());
     // setPreferredSize(new Dimension(400, 600));
     // setSize(new Dimension(400, 600));
-    add(setDetails, BorderLayout.NORTH);
-    add(settingsPanel, BorderLayout.CENTER);
+    jobPanel.setLeftComponent(setDetails);
+    jobPanel.setRightComponent(settingsPanel);
+    jobPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
+    add(SetNamePanel, BorderLayout.NORTH);
+    add(jobPanel, BorderLayout.CENTER);
     JPanel dialogpanel = new JPanel();
     dialogpanel.add(startjob);
     dialogpanel.add(canceljob);
     add(dialogpanel, BorderLayout.SOUTH);
   }
 
-  protected void canceljob_actionPerformed(ActionEvent e)
+  protected void revertSetting_actionPerformed(ActionEvent e)
   {
-    response = 0;
-    if (frame != null)
-    {
-      frame.setVisible(false);
-    }
+    // TODO Auto-generated method stub
+
   }
 
-  protected void startjob_actionPerformed(ActionEvent e)
+  protected void deleteSetting_actionPerformed(ActionEvent e)
   {
-    response = 1;
-    if (frame != null)
+    String setname = (String) setName.getSelectedItem();
+    int p = setName.getSelectedIndex();
+    if (_getUserPreset(setname) != null)
     {
-      frame.setVisible(false);
-    }
-  }
+      _deleteUserPreset(setname);
 
-  protected void editParam_actionPerformed(ActionEvent e)
-  {
-    // TODO Auto-generated method stub
+    }
+    if (p > 0 && p + 1 == setName.getItemCount())
+    {
+      p--;
+    }
+    setName.setSelectedIndex(p);
 
   }
 
-  protected void removeParam_actionPerformed(ActionEvent e)
+  protected void renModified_actionPerformed(ActionEvent e)
   {
-    // TODO Auto-generated method stub
-
+    if (curSetName == null || _getUserPreset(lastSetName) == null)
+    {
+      System.err
+              .println("can't rename - names unchanged or original name not a preset.");
+      return;
+    }
+    _deleteUserPreset(lastSetName);
+    lastSetName = curSetName;
+    savModified_actionPerformed(e);
+    curSetName = null;
+    boolean setd = settingDialog;
+    settingDialog = true;
+    syncSetNamesWithStore();
+    settingDialog = setd;
   }
 
-  protected void addParam_actionPerformed(ActionEvent e)
+  protected void savModified_actionPerformed(ActionEvent e)
   {
-    // TODO Auto-generated method stub
-
+    _storeUserPreset(lastSetName=(String) setName.getSelectedItem(), setDescr.getText(), getJobParams());
+    curSetName = null;
+    initArgSetModified(); // reset the modification state
   }
 
-  protected void resetParams_actionPerformed(ActionEvent e)
+  protected void canceljob_actionPerformed(ActionEvent e)
   {
-    // TODO Auto-generated method stub
-
+    response = 0;
+    if (frame != null)
+    {
+      frame.setVisible(false);
+    }
   }
 
-  protected void importParams_actionPerformed(ActionEvent e)
+  protected void startjob_actionPerformed(ActionEvent e)
   {
-    // TODO Auto-generated method stub
-
+    response = 1;
+    if (frame != null)
+    {
+      frame.setVisible(false);
+    }
   }
 
-  protected void exportParams_actionPerformed(ActionEvent e)
-  {
-    // TODO Auto-generated method stub
+  Jws2Instance service;
 
-  }
+  /**
+   * list of service presets in the gui
+   */
+  Hashtable servicePresets = null;
 
-  Jws2Instance service;
+  /**
+   * set if dialog is being set - so handlers will avoid spurious events
+   */
+  boolean settingDialog = false;
 
   void initForService(Jws2Instance service, Preset p,
           List<Argument> jobArgset)
   {
+    settingDialog = true;
     this.service = service;
+    // TODO: Recover window geometry prefs for this service
+    // jobPanel.setDividerLocation(proportionalLocation)
+    // settingsPanel.setDividerLocation(proportionalLocation)
+    Hashtable exnames = new Hashtable();
+    for (int i = 0, iSize = setName.getItemCount(); i < iSize; i++)
+    {
+      exnames.put((String) setName.getItemAt(i), setName.getItemAt(i));
+    }
+    // Add the default entry - if not present already.
+    if (!exnames.contains(SVC_DEF))
+    {
+      setName.addItem(SVC_DEF);
+      exnames.put(SVC_DEF, SVC_DEF);
+    }
     serviceOptions = service.getRunnerConfig();
     // add any presets not already added.
     String curname = (p == null ? "" : p.getName());
     PresetManager prman = service.getPresets();
+    servicePresets = new Hashtable();
     if (prman != null)
     {
       List prList = service.getPresets().getPresets();
@@ -391,7 +447,8 @@ public class WsJobParameters extends JPanel implements ItemListener,
       {
         for (Object pr : prList)
         {
-          if (p == null || !curname.equals(((Preset) pr).getName()))
+          servicePresets.put(((Preset) pr).getName(), "preset");
+          if (!exnames.contains(((Preset) pr).getName()))
           {
             setName.addItem(((Preset) pr).getName());
           }
@@ -399,12 +456,14 @@ public class WsJobParameters extends JPanel implements ItemListener,
       }
     }
     updateTable(p, jobArgset);
+    initArgSetModified();
+    settingDialog = false;
+
   }
 
   @SuppressWarnings("unchecked")
   private void updateTable(Preset p, List<Argument> jobArgset)
   {
-    availableParameters = new ArrayList<Parameter>();
     List<Parameter> setargs = new ArrayList<Parameter>();
     // populate table from default parameter set.
     List<Argument> args = serviceOptions.getArguments();
@@ -418,25 +477,14 @@ public class WsJobParameters extends JPanel implements ItemListener,
         if (myarg instanceof Parameter)
         {
           Parameter parm = (Parameter) myarg;
-          if (true) // parm.isRequired())
-          {
-            addParameter(parm);
-          }
-          else
-          {
-            availableParameters.add(parm);
-          }
+          addParameter(parm);
         }
         else
         {
           if (myarg instanceof Option)
           {
             Option opt = (Option) myarg;
-            addOption(opt);
-            if (opt.isRequired())
-            {
-              selectOption(opt, opt.getDefaultValue());
-            }
+            addOption(opt).resetToDefault();
           }
           else
           {
@@ -449,12 +497,9 @@ public class WsJobParameters extends JPanel implements ItemListener,
     }
     if (p != null)
     {
-      if (lastParmSet == null)
-      {
-        // initialise setname
-        setName.addItem(p.getName());
-      }
-      setDescr.setText(p.getDescription());
+      // initialise setname
+      setName.setSelectedItem(lastSetName = p.getName());
+      setDescr.setText(lastDescrText = p.getDescription());
       // TODO - URL link
       try
       {
@@ -472,12 +517,13 @@ public class WsJobParameters extends JPanel implements ItemListener,
       if (lastParmSet == null)
       {
         // first call - so create a dummy name
-        setName.addItem("Defaults *");
+        setName.setSelectedItem(lastSetName = SVC_DEF);
       }
     }
+
     if (jobArgset != null)
     {
-      argSetModified(true);
+      argSetModified(jobArgset, true);
       args = jobArgset;
     }
     // get setargs from current object
@@ -487,12 +533,15 @@ public class WsJobParameters extends JPanel implements ItemListener,
       {
         if (arg instanceof Parameter)
         {
-          setargs.add((Parameter) arg);
+          setParameter((Parameter) arg);
         }
         else
         {
           if (arg instanceof Option)
           {
+//            System.out.println("Setting option "
+//                    + System.identityHashCode(arg) + ":" + arg.getName()
+//                    + " with " + arg.getDefaultValue());
             selectOption((Option) arg, arg.getDefaultValue());
           }
         }
@@ -500,43 +549,146 @@ public class WsJobParameters extends JPanel implements ItemListener,
       }
     }
 
-    // mdl.setData(setargs);
-    // jobOptions.setLayout(new GridLayout(optSet.size() / 2 + 1, 2));
     jobOptions.setPreferredSize(new Dimension(PARAM_WIDTH, optSet.size()
             * OPTSET_HEIGHT));
     jobOptions.setLayout(new GridLayout(optSet.size(), 1));
     refreshParamLayout();
-    // paramPanel.setLayout(new GridLayout(paramSet.size(), 1));
-    // paramList.va
-    // paramPane.getViewport().validate();
     paramPane.validate();
     validate();
   }
 
   private boolean isModified()
   {
-    return modified.isVisible();
+    return modifiedElements.size() > 0;
   }
 
-  private void argSetModified(boolean b)
+  private Hashtable modifiedElements = new Hashtable();
+
+  /**
+   * reset gui and modification state settings
+   */
+  private void initArgSetModified()
   {
-    modified.setVisible(b);
-    /*
-     * String setn = (String)setName.getSelectedItem(); if (setn==null) return;
-     * int p = setName.getSelectedIndex(); if (b) { if (setn.length()<2 ||
-     * setn.lastIndexOf(" *")!=setn.length()-2) { setn = setn+" *"; } } else {
-     * if (setn.lastIndexOf(" *")==setn.length()-2) { setn =
-     * setn.substring(0,setn.length()-2); } } // edit the list
-     * 
-     * Object[] objects = new Object[setName.getItemCount()]; for (int
-     * i=0;i<objects.length; i++) { objects[i] = setName.getItemAt(i); }
-     * objects[p] = setn; setName.removeAllItems(); for (int
-     * i=0;i<objects.length; i++) { setName.addItem(objects[i]); }
-     * setName.setSelectedIndex(p);
-     */
+    curSetName = null;
+    modifiedElements.clear();
+    renmodified.setVisible(false);
+    savmodified.setVisible(false);
+
+  }
+
+  private void argSetModified(Object modifiedElement, boolean b)
+  {
+    if (settingDialog)
+    {
+      return;
+    }
+
+    if (!b)
+    {
+      modifiedElements.remove(modifiedElement);
+    }
+    else
+    {
+      modifiedElements.put(modifiedElement, modifiedElement);
+    }
+    // set mod status based on presence of elements in table
+    if (modifiedElements.size() > 0)
+    {
+      makeSetNameValid();
+      savmodified.setVisible(true);
+      revertsetting.setVisible(false);
+    }
+    else
+    {
+      revertsetting.setVisible(false);
+      deletesetting
+              .setVisible(!isServicePreset((String) setName
+                      .getSelectedItem())
+                      && _getUserPreset((String) setName.getSelectedItem()) != null);
+      savmodified.setVisible(false);
+    }
+    // special reveal if setName has been modified
+    if (modifiedElements.get(setName) != null)
+    {
+      if (curSetName != null && lastSetName != null
+              && !lastSetName.equals(curSetName))
+      {
+        renmodified.setVisible(!isServicePreset(lastSetName));
+      }
+    }
+    else
+    {
+      // setname isn't in modlist - so don't rename
+      renmodified.setVisible(false);
+    }
     validate();
   }
 
+  private boolean isServicePreset(String selectedItem)
+  {
+    return selectedItem.equals(SVC_DEF)
+            || servicePresets.containsKey(selectedItem);
+  }
+
+  /**
+   * check if the current set name is a valid set name for saving, if not, then
+   * fix it.
+   */
+  private void makeSetNameValid()
+  {
+    boolean stn = settingDialog;
+    boolean renamed = false;
+    settingDialog = true;
+    String nm = (String) setName.getSelectedItem();
+    // check if the name is reserved - if it is, rename it.
+    if (isServicePreset(nm))
+    {
+      nm = "User " + nm;
+      String tnm=nm;
+      renamed = true;
+      int i=0;
+      while (_getUserPreset(tnm)!=null)
+      {
+        tnm = nm+" ("+(++i)+")";
+      }
+      if (i>0)
+      {
+        nm = tnm;
+      }
+    }
+    // if ()
+    // if nm exists in user's preset store then savmodified will update an
+    // existing user defined preset
+    // if nm doesn't exist, then the button will create a new preset.
+
+    boolean makeupdate = false;
+    // sync the gui with the preset database
+    for (int i = 0, iS = setName.getItemCount(); i < iS; i++)
+    {
+      String snm = (String) setName.getItemAt(i);
+      if (snm.equals(nm))
+      {
+        makeupdate = true;
+        setName.setSelectedIndex(i);
+      }
+    }
+
+    if (_getUserPreset(nm) != null)
+    {
+      savmodified.setText("Update");
+    }
+    else
+    {
+      if (renamed)
+      {
+        setName.addItem(nm);
+        setName.setSelectedIndex(setName.getItemCount() - 1);
+      }
+      savmodified.setText("Save");
+    }
+    settingDialog = stn;
+  }
+
   private void addParameter(Parameter parm)
   {
     ParamBox pb = paramSet.get(parm.getName());
@@ -546,6 +698,23 @@ public class WsJobParameters extends JPanel implements ItemListener,
       paramSet.put(parm.getName(), pb);
       paramList.add(pb);
     }
+    pb.init();
+    // take the defaults from the parameter
+    pb.updateControls(parm);
+  }
+
+  private void setParameter(Parameter arg)
+  {
+    ParamBox pb = paramSet.get(arg.getName());
+    if (pb == null)
+    {
+      addParameter(arg);
+    }
+    else
+    {
+      pb.updateControls(arg);
+    }
+
   }
 
   private void selectOption(Option opt, String string)
@@ -555,22 +724,9 @@ public class WsJobParameters extends JPanel implements ItemListener,
     {
       cb = addOption(opt);
     }
-    if (string == null)
+    cb.enabled.setSelected(true); // initial state for an option.
+    if (string != null)
     {
-      // no value specified.
-      if (opt.isRequired())
-      {
-        // indicate option needs to be selected!
-      }
-      else
-      {
-        cb.enabled.setSelected(false);
-      }
-    }
-    else
-    {
-      cb.enabled.setSelected(true);
-
       if (opt.getPossibleValues().contains(string))
       {
         cb.val.setSelectedItem(string);
@@ -581,16 +737,22 @@ public class WsJobParameters extends JPanel implements ItemListener,
       }
 
     }
+    if (opt.isRequired() && !cb.enabled.isSelected())
+    {
+      // TODO: indicate paramset is not valid.. option needs to be selected!
+    }
+    cb.setInitialValue();
   }
 
   Map<String, ParamBox> paramSet = new Hashtable<String, ParamBox>();
 
   public class ParamBox extends JPanel implements ChangeListener,
-          ActionListener
+          ActionListener, MouseListener
   {
-    JCheckBox showDesc = new JCheckBox();
+    JButton showDesc = new JButton();
 
     JTextArea string = new JTextArea();
+
     JScrollPane descPanel = new JScrollPane();
 
     JSlider slider = null;
@@ -598,39 +760,58 @@ public class WsJobParameters extends JPanel implements ItemListener,
     JTextField valueField = null;
 
     ValueConstrain validator = null;
+
     JPanel settingPanel = new JPanel();
+
+    JPanel controlPanel = new JPanel();
+
     boolean integ = false;
 
     boolean choice = false;
 
+    boolean descisvisible = false;
+
+    final WsJobParameters pmdialogbox;
+
+    final URL finfo;
+
     public ParamBox(final WsJobParameters pmlayout, Parameter parm)
     {
-      setLayout(new FlowLayout(FlowLayout.LEFT));
-      setBorder(new TitledBorder(parm.getName()));
+      pmdialogbox = pmlayout;
       setPreferredSize(new Dimension(PARAM_WIDTH, PARAM_CLOSEDHEIGHT));
+      setBorder(new TitledBorder(parm.getName()));
+      setLayout(null);
+      showDesc.setFont(new Font("Verdana", Font.PLAIN, 6));
+      showDesc.setText("+");
       string.setFont(new Font("Verdana", Font.PLAIN, 11));
       string.setBackground(getBackground());
       // string.setSize(new Dimension(PARAM_WIDTH, 80));
       string.setEditable(false);
-      showDesc.setText("Show Description");
-      showDesc.setSelected(false);
-      showDesc.setToolTipText(parm.getDescription());
-      //showDesc.setLocation(2,2);
-      descPanel.setPreferredSize(new Dimension(PARAM_WIDTH-20, 90));
       descPanel.getViewport().setView(string);
-      //descPanel.setLocation(2,17);
+      // descPanel.setLocation(2,17);
       descPanel.setVisible(false);
       // string.setMinimumSize(new Dimension(140,80));
       // string.setMaximumSize(new Dimension(280,80));
-      final ParamBox me=this;
-      showDesc.addActionListener(new ActionListener() {
+      final ParamBox me = this;
+      finfo = parm.getFurtherDetails();
+      if (finfo != null)
+      {
+        showDesc.setToolTipText("<html><p>Click to show brief description, and right click to open link for further information.</p></html>");
+        showDesc.addMouseListener(this);
+      }
+      else
+      {
+        showDesc.setToolTipText("<html><p>Click to show brief description.</p></html>");
+      }
+      showDesc.addActionListener(new ActionListener()
+      {
 
-        @Override
         public void actionPerformed(ActionEvent e)
         {
-          boolean show = showDesc.isSelected();
-          descPanel.setVisible(show);
-          me.setPreferredSize(new Dimension(PARAM_WIDTH, (show) ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT));
+          descisvisible = !descisvisible;
+          descPanel.setVisible(descisvisible);
+          me.setPreferredSize(new Dimension(PARAM_WIDTH,
+                  (descisvisible) ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT));
           me.validate();
           pmlayout.refreshParamLayout();
         }
@@ -639,8 +820,17 @@ public class WsJobParameters extends JPanel implements ItemListener,
       string.setLineWrap(true);
       string.setColumns(32);
       string.setText(parm.getDescription());
-      // name.setToolTipText(parm.getDescription());
-      add(showDesc);
+      JPanel firstrow = new JPanel();
+      firstrow.setLayout(null);
+      controlPanel.setLayout(new BorderLayout());
+      controlPanel.setBounds(new Rectangle(39, 10, PARAM_WIDTH - 70,
+              PARAM_CLOSEDHEIGHT - 50));
+      showDesc.setBounds(new Rectangle(10, 10, 16, 16));
+      firstrow.add(showDesc);
+      firstrow.add(controlPanel);
+      firstrow.setBounds(new Rectangle(10, 20, PARAM_WIDTH - 30,
+              PARAM_CLOSEDHEIGHT - 30));
+      add(firstrow);
       validator = parm.getValidValue();
       parameter = parm;
       if (validator != null)
@@ -655,24 +845,33 @@ public class WsJobParameters extends JPanel implements ItemListener,
         }
       }
       updateControls(parm);
-      add(descPanel); // , BorderLayout.NORTH);
+      descPanel.setBounds(new Rectangle(10, PARAM_CLOSEDHEIGHT,
+              PARAM_WIDTH - 20, PARAM_HEIGHT - PARAM_CLOSEDHEIGHT - 5));
+      add(descPanel);
       validate();
     }
 
+    public void init()
+    {
+      // reset the widget's initial value.
+      lastVal = null;
+    }
 
     boolean adjusting = false;
 
     Parameter parameter;
 
     JComboBox choicebox;
+
     public int getBoxHeight()
     {
-      return (showDesc.isSelected() ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT);
+      return (descisvisible ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT);
     }
+
     public void updateControls(Parameter parm)
     {
       adjusting = true;
-      boolean init = valueField == null;
+      boolean init = (choicebox == null && valueField == null);
       float fVal = 0f;
       int iVal = 0;
       if (init)
@@ -681,7 +880,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
         {
           choicebox = new JComboBox();
           choicebox.addActionListener(this);
-          add(choicebox);
+          controlPanel.add(choicebox, BorderLayout.CENTER);
         }
         else
         {
@@ -689,13 +888,9 @@ public class WsJobParameters extends JPanel implements ItemListener,
           slider.addChangeListener(this);
           valueField = new JTextField();
           valueField.addActionListener(this);
-          valueField.setPreferredSize(new Dimension(80, 25));
-          JPanel container = new JPanel();
-          // container.setLayout(new FlowLayout());
-          add(slider);// , BorderLayout.SOUTH);
-          add(valueField);// ,BorderLayout.CENTER);
-          // add(container, BorderLayout.EAST);
-          // container.validate();
+          valueField.setPreferredSize(new Dimension(60, 25));
+          controlPanel.add(slider, BorderLayout.WEST);
+          controlPanel.add(valueField, BorderLayout.EAST);
 
         }
       }
@@ -704,11 +899,15 @@ public class WsJobParameters extends JPanel implements ItemListener,
       {
         if (choice)
         {
-          List vals = parm.getPossibleValues();
-          for (Object val : vals)
+          if (init)
           {
-            choicebox.addItem(val);
+            List vals = parm.getPossibleValues();
+            for (Object val : vals)
+            {
+              choicebox.addItem(val);
+            }
           }
+
           if (parm.getDefaultValue() != null)
           {
             choicebox.setSelectedItem(parm.getDefaultValue());
@@ -719,28 +918,31 @@ public class WsJobParameters extends JPanel implements ItemListener,
           valueField.setText(parm.getDefaultValue());
         }
       }
-      updateSliderFromValueField();
+      lastVal = updateSliderFromValueField();
       adjusting = false;
     }
 
+    Object lastVal;
+
     public Parameter getParameter()
     {
+      Parameter prm = ParameterUtils.copyParameter(parameter);
       try
       {
         if (choice)
         {
-          parameter.setDefaultValue((String) choicebox.getSelectedItem());
+          prm.setDefaultValue((String) choicebox.getSelectedItem());
         }
         else
         {
-          parameter.setDefaultValue(valueField.getText());
+          prm.setDefaultValue(valueField.getText());
         }
       } catch (WrongParameterException e)
       {
         e.printStackTrace();
         return null;
       }
-      return parameter;
+      return prm;
     }
 
     public Object updateSliderFromValueField()
@@ -814,7 +1016,6 @@ public class WsJobParameters extends JPanel implements ItemListener,
 
     }
 
-    @Override
     public void stateChanged(ChangeEvent e)
     {
       if (!adjusting)
@@ -822,42 +1023,123 @@ public class WsJobParameters extends JPanel implements ItemListener,
         valueField.setText(""
                 + ((integ) ? ("" + (int) slider.getValue())
                         : ("" + (float) (slider.getValue() / 1000f))));
+        checkIfModified();
       }
+
     }
 
-    @Override
     public void actionPerformed(ActionEvent e)
     {
-      if (choice)
+      if (adjusting)
       {
+        return;
       }
-      else if (!adjusting)
+      if (!choice)
       {
         updateSliderFromValueField();
       }
-      argSetModified(true);
+      checkIfModified();
+    }
+
+    private void checkIfModified()
+    {
+      Object cstate = updateSliderFromValueField();
+      boolean notmod = false;
+      if (cstate.getClass() == lastVal.getClass())
+      {
+        if (cstate instanceof int[])
+        {
+          notmod = (((int[]) cstate)[0] == ((int[]) lastVal)[0]);
+        }
+        else if (cstate instanceof float[])
+        {
+          notmod = (((float[]) cstate)[0] == ((float[]) lastVal)[0]);
+        }
+        else if (cstate instanceof String[])
+        {
+          notmod = (((String[]) cstate)[0].equals(((String[]) lastVal)[0]));
+        }
+      }
+      pmdialogbox.argSetModified(this, !notmod);
+    }
+
+    public void mouseClicked(MouseEvent e)
+    {
+      if (javax.swing.SwingUtilities.isRightMouseButton(e))
+      {
+        Desktop.showUrl(finfo.toString());
+      }
+    }
+
+    public void mousePressed(MouseEvent e)
+    {
+      // TODO Auto-generated method stub
+
+    }
+
+    public void mouseReleased(MouseEvent e)
+    {
+      // TODO Auto-generated method stub
+
+    }
+
+    public void mouseEntered(MouseEvent e)
+    {
+      // TODO Auto-generated method stub
+
+    }
+
+    public void mouseExited(MouseEvent e)
+    {
+      // TODO Auto-generated method stub
+
     }
 
   }
 
   Map<String, OptionBox> optSet = new Hashtable<String, OptionBox>();
 
-  public class OptionBox extends JPanel implements ActionListener
+  public class OptionBox extends JPanel implements MouseListener,
+          ActionListener
   {
     JComboBox val = new JComboBox();
 
     JCheckBox enabled = new JCheckBox();
 
+    JLabel optlabel = new JLabel();
+
+    URL linkImageURL = getClass().getResource("/images/link.gif");
+
+    final URL finfo;
+
+    boolean hasLink = false;
+
     Option option;
 
     public OptionBox(Option opt)
     {
       option = opt;
       setLayout(new BorderLayout());
-      enabled.setSelected(opt.isRequired());
+      enabled.setSelected(opt.isRequired()); // TODO: lock required options
       enabled.setFont(new Font("Verdana", Font.PLAIN, 11));
+      enabled.setText("");
       enabled.setText(opt.getName());
-      enabled.setToolTipText(opt.getDescription());
+      enabled.addActionListener(this);
+      finfo = option.getFurtherDetails();
+      if (finfo != null)
+      {
+        hasLink = true;
+        // optlabel.setToolTipText("<html><p>"+opt.getDescription()+"</p><img src=\""+linkImageURL+"\"/></html>");
+        enabled.setToolTipText("<html><p>" + opt.getDescription()
+                + "</p><img src=\"" + linkImageURL + "\"/></html>");
+        // optlabel.addMouseListener(this);
+        enabled.addMouseListener(this);
+      }
+      else
+      {
+        // optlabel.setToolTipText(opt.getDescription());
+        enabled.setToolTipText(opt.getDescription());
+      }
       add(enabled, BorderLayout.NORTH);
       if (opt.getPossibleValues().size() > 1)
       {
@@ -873,6 +1155,35 @@ public class WsJobParameters extends JPanel implements ItemListener,
       // TODO: add actionListeners for popup (to open further info),
       // and to update list of parameters if an option is enabled
       // that takes a value.
+      setInitialValue();
+    }
+
+    public void resetToDefault()
+    {
+      enabled.setSelected(false);
+      if (option.isRequired())
+      {
+        // Apply default value
+        selectOption(option, option.getDefaultValue());
+      }
+    }
+
+    boolean initEnabled = false;
+
+    String initVal = null;
+
+    public void setInitialValue()
+    {
+      initEnabled = enabled.isSelected();
+      if (option.getPossibleValues() != null
+              && option.getPossibleValues().size() > 1)
+      {
+        initVal = (String) val.getSelectedItem();
+      }
+      else
+      {
+        initVal = null;
+      }
     }
 
     public Option getOptionIfEnabled()
@@ -883,9 +1194,11 @@ public class WsJobParameters extends JPanel implements ItemListener,
       }
       try
       {
+        Option opt = jalview.ws.jws2.ParameterUtils.copyOption(option);
+
         if (val.getSelectedItem() != null)
         {
-          option.setDefaultValue((String) val.getSelectedItem());
+          opt.setDefaultValue((String) val.getSelectedItem());
         }
       } catch (WrongParameterException e)
       {
@@ -895,12 +1208,57 @@ public class WsJobParameters extends JPanel implements ItemListener,
       return option;
     }
 
-    @Override
     public void actionPerformed(ActionEvent e)
     {
-      argSetModified(true);
-      enabled.setSelected(true);
+      if (e.getSource() != enabled)
+      {
+        enabled.setSelected(true);
+      }
+      checkIfModified();
+    }
+
+    private void checkIfModified()
+    {
+      boolean notmod = (initEnabled == enabled.isSelected());
+      if (enabled.isSelected() && initVal != null)
+      {
+        notmod |= initVal.equals(val.getSelectedItem());
+      }
+      argSetModified(this, !notmod);
+    }
+
+    public void mouseClicked(MouseEvent e)
+    {
+      if (javax.swing.SwingUtilities.isRightMouseButton(e))
+      {
+        showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
+      }
     }
+
+    public void mousePressed(MouseEvent e)
+    {
+      // TODO Auto-generated method stub
+
+    }
+
+    public void mouseReleased(MouseEvent e)
+    {
+      // TODO Auto-generated method stub
+
+    }
+
+    public void mouseEntered(MouseEvent e)
+    {
+      // TODO Auto-generated method stub
+
+    }
+
+    public void mouseExited(MouseEvent e)
+    {
+      // TODO Auto-generated method stub
+
+    }
+
   }
 
   private OptionBox addOption(Option opt)
@@ -915,11 +1273,32 @@ public class WsJobParameters extends JPanel implements ItemListener,
     return cb;
   }
 
+  public static void showUrlPopUp(JComponent invoker, final String finfo,
+          int x, int y)
+  {
+
+    JPopupMenu mnu = new JPopupMenu();
+    JMenuItem mitem = new JMenuItem("View " + finfo);
+    mitem.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        Desktop.showUrl(finfo);
+
+      }
+    });
+    mnu.add(mitem);
+    mnu.show(invoker, x, y);
+  }
+
   protected void refreshParamLayout()
   {
-    int s=100;
-    for (ParamBox pbox : paramSet.values()){
-      s+=pbox.getBoxHeight();
+    int s = 100;
+    for (ParamBox pbox : paramSet.values())
+    {
+      s += pbox.getBoxHeight();
     }
     paramList.setPreferredSize(new Dimension(PARAM_WIDTH, s));
     paramList.setLayout(new FlowLayout());
@@ -955,111 +1334,149 @@ public class WsJobParameters extends JPanel implements ItemListener,
     for (Jws2Discoverer.Jws2Instance service : disc.getServices())
     {
       lastserv = service;
-      if (p < args.length && service.serviceType.equalsIgnoreCase(args[p]))
+      if (p >= args.length || service.serviceType.equalsIgnoreCase(args[p]))
       {
-        break;
-      }
-    }
-    if (lastserv != null)
-    {
-      List<Preset> prl = null;
-      Preset pr = null;
-      if (++p < args.length)
-      {
-        PresetManager prman = lastserv.getPresets();
-        if (prman != null)
+        if (lastserv != null)
         {
-          pr = prman.getPresetByName(args[p]);
-          if (pr == null)
+          List<Preset> prl = null;
+          Preset pr = null;
+          if (++p < args.length)
           {
-            // just grab the last preset.
-            prl = prman.getPresets();
+            PresetManager prman = lastserv.getPresets();
+            if (prman != null)
+            {
+              pr = prman.getPresetByName(args[p]);
+              if (pr == null)
+              {
+                // just grab the last preset.
+                prl = prman.getPresets();
+              }
+            }
+          } else {
+            PresetManager prman = lastserv.getPresets();
+            if (prman!=null) {
+              prl = prman.getPresets();
+            }
           }
-        }
-      }
-      Iterator<Preset> en = (prl == null) ? null : prl.iterator();
-      while (true)
-      {
-        if (en != null)
-        {
-          if (!en.hasNext())
+          Iterator<Preset> en = (prl == null) ? null : prl.iterator();
+          while (en!=null && en.hasNext())
           {
-            en = prl.iterator();
-          }
-          pr = en.next();
-        }
-        WsJobParameters pgui = new WsJobParameters(lastserv, pr);
-        JFrame jf = new JFrame("Parameters for " + lastserv.getActionText());
-        JPanel cont = new JPanel();
-        jf.setPreferredSize(new Dimension(600, 800));
-        cont.add(pgui);
-        jf.add(cont);
-        final Thread thr = Thread.currentThread();
-        jf.addWindowListener(new WindowListener()
-        {
+            if (en != null)
+            {
+              if (!en.hasNext())
+              {
+                en = prl.iterator();
+              }
+              pr = en.next();
+            }
+            {
+              System.out.println("Testing opts dupes for "+lastserv.getHost()+" : "+lastserv.getActionText()+":"+pr.getName());
+              List<Option> rg = lastserv.getRunnerConfig().getOptions();
+              for (Option o : rg)
+              {
+                try
+                {
+                  Option cpy = jalview.ws.jws2.ParameterUtils.copyOption(o);
+                } catch (Exception e)
+                {
+                  System.err.println("Failed to copy " + o.getName());
+                  e.printStackTrace();
+                } catch (Error e)
+                {
+                  System.err.println("Failed to copy " + o.getName());
+                  e.printStackTrace();
+                }
+              }
+            }
+            {
+              System.out.println("Testing param dupes:");
+              List<Parameter> rg = lastserv.getRunnerConfig()
+                      .getParameters();
+              for (Parameter o : rg)
+              {
+                try
+                {
+                  Parameter cpy = jalview.ws.jws2.ParameterUtils
+                          .copyParameter(o);
+                } catch (Exception e)
+                {
+                  System.err.println("Failed to copy " + o.getName());
+                  e.printStackTrace();
+                } catch (Error e)
+                {
+                  System.err.println("Failed to copy " + o.getName());
+                  e.printStackTrace();
+                }
+              }
+            }
+            WsJobParameters pgui = new WsJobParameters(lastserv, pr);
+            JFrame jf = new JFrame("Parameters for "
+                    + lastserv.getActionText());
+            JPanel cont = new JPanel();
+            // jf.setPreferredSize(new Dimension(600, 800));
+            cont.add(pgui);
+            jf.add(cont);
+            final Thread thr = Thread.currentThread();
+            jf.addWindowListener(new WindowListener()
+            {
 
-          @Override
-          public void windowActivated(WindowEvent e)
-          {
-            // TODO Auto-generated method stub
+              public void windowActivated(WindowEvent e)
+              {
+                // TODO Auto-generated method stub
 
-          }
+              }
 
-          @Override
-          public void windowClosed(WindowEvent e)
-          {
-          }
+              public void windowClosed(WindowEvent e)
+              {
+              }
 
-          @Override
-          public void windowClosing(WindowEvent e)
-          {
-            thr.interrupt();
+              public void windowClosing(WindowEvent e)
+              {
+                thr.interrupt();
 
-          }
+              }
 
-          @Override
-          public void windowDeactivated(WindowEvent e)
-          {
-            // TODO Auto-generated method stub
+              public void windowDeactivated(WindowEvent e)
+              {
+                // TODO Auto-generated method stub
 
-          }
+              }
 
-          @Override
-          public void windowDeiconified(WindowEvent e)
-          {
-            // TODO Auto-generated method stub
+              public void windowDeiconified(WindowEvent e)
+              {
+                // TODO Auto-generated method stub
 
-          }
+              }
 
-          @Override
-          public void windowIconified(WindowEvent e)
-          {
-            // TODO Auto-generated method stub
+              public void windowIconified(WindowEvent e)
+              {
+                // TODO Auto-generated method stub
 
-          }
+              }
 
-          @Override
-          public void windowOpened(WindowEvent e)
-          {
-            // TODO Auto-generated method stub
+              public void windowOpened(WindowEvent e)
+              {
+                // TODO Auto-generated method stub
 
-          }
+              }
 
-        });
-        jf.setVisible(true);
-        boolean inter = false;
-        while (!inter)
-        {
-          try
-          {
-            Thread.sleep(10000);
-          } catch (Exception e)
-          {
-            inter = true;
+            });
+            jf.setVisible(true);
+            boolean inter = false;
+            while (!inter)
+            {
+              try
+              {
+                Thread.sleep(10000);
+              } catch (Exception e)
+              {
+                inter = true;
+              }
+              ;
+            }
+            jf.dispose();
           }
-          ;
         }
-        jf.dispose();
       }
     }
   }
@@ -1092,9 +1509,130 @@ public class WsJobParameters extends JPanel implements ItemListener,
 
   Hashtable<String, Object[]> editedParams = new Hashtable<String, Object[]>();
 
-  @Override
+  /**
+   * store the given parameters in the user parameter set database.
+   * 
+   * @param storeSetName
+   *          - lastParmSet
+   * @param descr
+   *          - setDescr.getText()
+   * @param jobParams
+   *          - getJobParams()
+   */
+  private void _storeUserPreset(String storeSetName, String descr,
+          List<Argument> jobParams)
+  {
+    // this is a simple hash store.
+    Object[] pset;
+    editedParams.put(storeSetName, pset = new Object[3]);
+    pset[0] = storeSetName;
+    pset[1] = descr;
+    pset[2] = jobParams;
+    //writeParam("Saving " + storeSetName + ": ", jobParams);
+  }
+
+  private void writeParam(String nm, List<Argument> params)
+  {
+    for (Argument p : params)
+    {
+      System.out.println(nm + ":" + System.identityHashCode(p) + " Name: "
+              + p.getName() + " Value: " + p.getDefaultValue());
+    }
+  }
+
+  private Object[] _getUserPreset(String setName)
+  {
+    Object[] pset = editedParams.get(setName);
+    //if (pset != null)
+    //  writeParam("Retrieving " + setName + ": ", (List<Argument>) pset[2]);
+    return pset;
+  }
+
+  /**
+   * remove the given user preset from the preset stash
+   * 
+   * @param setName
+   */
+  private void _deleteUserPreset(String setName)
+  {
+    editedParams.remove(setName);
+  }
+
+  private void syncSetNamesWithStore()
+  {
+    int n = 0;
+    // remove any set names in the drop down menu that aren't either a reserved
+    // setting, or a user defined or service preset.
+    while (n < setName.getItemCount())
+    {
+      String item = (String) setName.getItemAt(n);
+      if (!isServicePreset(item) && _getUserPreset(item) == null)
+      {
+        setName.removeItemAt(n);
+      }
+      else
+      {
+        n++;
+      }
+
+    }
+  }
+
+  private void reInitDialog(String nextPreset)
+  {
+    settingDialog = true;
+    syncSetNamesWithStore();
+    // updateTable(null,null); // first reset to defaults
+
+    Object[] pset = _getUserPreset(nextPreset);
+    if (pset != null)
+    {
+      setDescr.setText((String) pset[1]);
+      updateTable(null, (List<Argument>) pset[2]);
+      lastParmSet = nextPreset;
+      validate();
+    }
+    else
+    {
+      setDescr.setText("");
+      // must be a default preset from service
+      Preset p = null;
+      try
+      {
+        PresetManager prman = service.getPresets();
+        if (prman != null)
+        {
+          p = prman.getPresetByName(nextPreset);
+        }
+      } catch (Exception ex)
+      {
+        ex.printStackTrace();
+      }
+      if (p != null)
+      {
+        updateTable(p, null);
+        lastParmSet = nextPreset;
+      }
+      else
+      {
+        updateTable(null, null);
+      }
+    }
+    initArgSetModified();
+    validate();
+    settingDialog = false;
+
+  }
+
+  String curSetName = null;
+
   public void itemStateChanged(ItemEvent e)
   {
+    if (settingDialog)
+    {
+      // ignore event
+      return;
+    }
     if (e.getSource() == setName)
     {
       String setname = (String) setName.getSelectedItem();
@@ -1102,55 +1640,98 @@ public class WsJobParameters extends JPanel implements ItemListener,
       {
         return;
       }
-      // if modified - warn user - or at least save current edited set.
-      if (lastParmSet != null)
-      {
-        // save current state
-        Object[] pset;
-        editedParams.put(lastParmSet, pset = new Object[3]);
-        pset[0] = lastParmSet;
-        pset[1] = setDescr.getText();
-        pset[2] = getJobParams();
-      }
-      Object[] pset = editedParams.get(setname);
-      if (pset != null)
+      if (curSetName == null || !setname.equals(curSetName))
       {
-        setDescr.setText((String) pset[1]);
-        updateTable(null, (List<Argument>) pset[2]);
-        lastParmSet = setname;
-        validate();
+        settingDialog = true;
+        if (isModified())
+        {
+          System.out.println("Prompting for "+setname);
+          if (javax.swing.JOptionPane.showConfirmDialog(this,
+                  "Parameter set is modifed - save ?", "Save changes ?",
+                  javax.swing.JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION)
+          {
+            System.out.println("Saving for "+setname);
+            savModified_actionPerformed(null);
+          }
+        }
+        reInitDialog(setname);
+
       }
-      else
+    }
+  }
+
+  /**
+   * last saved name for this user preset
+   */
+  String lastSetName = null;
+
+  /**
+   * last saved value of the description text for this user preset
+   */
+  String lastDescrText = null;
+
+  public void actionPerformed(ActionEvent e)
+  {
+    if (e.getSource() instanceof Component)
+    {
+      Component src = (Component) e.getSource();
+      if (src.getParent() == setName)
       {
-        // must be a default preset from service
-        Preset p = null;
-        try
+        // rename any existing records we know about for this set.
+        String newname = (String) e.getActionCommand();
+        String msg = null;
+        if (isServicePreset(newname))
         {
-          p = service.getPresets().getPresetByName(setname);
-        } catch (Exception ex)
+          JOptionPane.showConfirmDialog(this,
+                  "Invalid name - preset already exists.", "Invalid name",
+                  JOptionPane.OK_OPTION);
+          return;
+        }
+        curSetName = newname;
+        System.err.println("Command " + curSetName + " : "
+                + setName.getSelectedItem());
+        if (curSetName.trim().equals(setName.getSelectedItem()))
         {
-          ex.printStackTrace();
+          curSetName = null;
         }
-        if (p != null)
+        if (curSetName != null)
         {
-          updateTable(p, null);
-          validate();
-          lastParmSet = setname;
+          setName.addItem(curSetName);
+          setName.setSelectedItem(curSetName);
+          argSetModified(setName,
+                  lastSetName != null && !curSetName.equals(lastSetName));
+          return;
         }
-      }
 
+      }
     }
   }
 
-  @Override
-  public void actionPerformed(ActionEvent e)
+  private void checkDescrModified()
   {
-    if (e.getSource() == setName)
+    if (!settingDialog)
     {
-      // rename any existing records we know about for this set.
-      String newname = (String) setName.getSelectedItem();
-      System.err.println("Command " + newname + " : "
-              + e.getActionCommand());
+
+      argSetModified(
+              setDescr,
+              (lastDescrText == null ? setDescr.getText().trim().length() > 0
+                      : !setDescr.getText().equals(lastDescrText)));
+
     }
   }
-}
+
+  public void insertUpdate(DocumentEvent e)
+  {
+    checkDescrModified();
+  }
+
+  public void removeUpdate(DocumentEvent e)
+  {
+    checkDescrModified();
+  }
+
+  public void changedUpdate(DocumentEvent e)
+  {
+    checkDescrModified();
+  }
+}
\ No newline at end of file