drop down selection of different parameter sets
[jalview.git] / src / jalview / gui / WsJobParameters.java
1 package jalview.gui;
2
3 import java.awt.BorderLayout;
4 import java.awt.Color;
5 import java.awt.Component;
6 import java.awt.Dimension;
7 import java.awt.FlowLayout;
8 import java.awt.Font;
9 import java.awt.GridLayout;
10 import java.awt.Rectangle;
11 import java.awt.event.ActionEvent;
12 import java.awt.event.ActionListener;
13 import java.awt.event.ComponentEvent;
14 import java.awt.event.ComponentListener;
15 import java.awt.event.ContainerEvent;
16 import java.awt.event.ContainerListener;
17 import java.awt.event.ItemEvent;
18 import java.awt.event.ItemListener;
19 import java.awt.event.KeyEvent;
20 import java.awt.event.KeyListener;
21 import java.awt.event.MouseEvent;
22 import java.awt.event.MouseListener;
23 import java.awt.event.WindowEvent;
24 import java.awt.event.WindowListener;
25 import java.awt.event.WindowStateListener;
26 import java.util.ArrayList;
27 import java.util.EventObject;
28 import java.util.HashSet;
29 import java.util.Hashtable;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Vector;
34
35 import javax.swing.JButton;
36 import javax.swing.JCheckBox;
37 import javax.swing.JComboBox;
38 import javax.swing.JDialog;
39 import javax.swing.JFrame;
40 import javax.swing.JLabel;
41 import javax.swing.JList;
42 import javax.swing.JOptionPane;
43 import javax.swing.JPanel;
44 import javax.swing.JScrollPane;
45 import javax.swing.JSlider;
46 import javax.swing.JTable;
47 import javax.swing.JTextArea;
48 import javax.swing.JTextField;
49 import javax.swing.ListSelectionModel;
50 import javax.swing.SwingConstants;
51 import javax.swing.SwingUtilities;
52 import javax.swing.border.TitledBorder;
53 import javax.swing.event.CellEditorListener;
54 import javax.swing.event.ChangeEvent;
55 import javax.swing.event.ChangeListener;
56 import javax.swing.table.*;
57
58 import compbio.metadata.Argument;
59 import compbio.metadata.Option;
60 import compbio.metadata.Parameter;
61 import compbio.metadata.Preset;
62 import compbio.metadata.PresetManager;
63 import compbio.metadata.RunnerConfig;
64 import compbio.metadata.ValueConstrain;
65 import compbio.metadata.WrongParameterException;
66 import compbio.metadata.ValueConstrain.Type;
67
68 import jalview.ws.jws2.Jws2Discoverer;
69 import jalview.ws.jws2.Jws2Discoverer.Jws2Instance;
70
71 public class WsJobParameters extends JPanel implements ItemListener,
72         ActionListener
73 {
74   private static final int PARAM_WIDTH = 340, PARAM_HEIGHT = 150,PARAM_CLOSEDHEIGHT=80;
75
76   private static final int OPTSET_HEIGHT = 30;
77
78   JPanel setDetails = new JPanel();
79
80   JPanel settingsPanel = new JPanel();
81
82   JPanel jobOptions = new JPanel();
83
84   JScrollPane jobOptionsPane = new JScrollPane();
85
86   JPanel jobParameters = new JPanel();
87
88   JPanel paramButtons = new JPanel();
89
90   JPanel paramPanel = new JPanel();
91
92   JLabel modified = new JLabel();
93
94   JButton startjob = new JButton();
95
96   JButton canceljob = new JButton();
97
98   JButton exportParams = new JButton();
99
100   JButton importParams = new JButton();
101
102   JButton resetParams = new JButton();
103
104   JButton addParam = new JButton();
105
106   JButton removeParam = new JButton();
107
108   JButton editParam = new JButton();
109
110   JComboBox setName = new JComboBox();
111
112   JTextArea setDescr = new JTextArea();
113
114   JScrollPane paramPane = new JScrollPane();
115
116   // JList paramList = new JList();
117   JPanel paramList = new JPanel();
118
119   RunnerConfig serviceOptions;
120
121   List<Parameter> availableParameters;
122
123   private BorderLayout jparamLayout;
124
125   WsJobParameters(Jws2Instance service)
126   {
127     this(service, null);
128   }
129
130   public WsJobParameters(Jws2Instance service, Preset p)
131   {
132     this(null, service, p, null);
133   }
134
135   /**
136    * 
137    * @param desktop
138    *          - if null, create new JFrame outside of desktop
139    * @param service
140    * @param p
141    */
142   public WsJobParameters(JFrame parent, Jws2Instance service, Preset p,
143           List<Argument> jobArgset)
144   {
145     super();
146     jbInit();
147     argSetModified(false);
148     // populate parameter table
149     initForService(service, p, jobArgset);
150     // display in new JFrame attached to parent.
151     validate();
152   }
153
154   int response = -1;
155
156   JDialog frame = null;
157
158   public boolean showRunDialog()
159   {
160
161     frame = new JDialog(Desktop.instance, true);
162
163     frame.setTitle("Edit parameters for " + service.getActionText());
164     Rectangle deskr = Desktop.instance.getBounds();
165     frame.setBounds(new Rectangle((int) (deskr.getCenterX() - 240),
166             (int) (deskr.getCenterY() - 92), 380, 385));
167     frame.setContentPane(this);
168
169     frame.setVisible(true);
170
171     if (response > 0)
172     {
173       return true;
174     }
175     return false;
176   }
177
178   private void jbInit()
179   {
180     modified.setText("*");
181     modified.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
182     modified.setForeground(Color.red);
183     modified.setHorizontalAlignment(SwingConstants.RIGHT);
184
185     exportParams.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
186     exportParams.setText("Export");
187     exportParams.setToolTipText("Export parameters to a file");
188     exportParams.addActionListener(new ActionListener()
189     {
190       public void actionPerformed(ActionEvent e)
191       {
192         exportParams_actionPerformed(e);
193       }
194     });
195     importParams.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
196     importParams.setText("Import");
197     importParams.setToolTipText("Import parameters from a file");
198     importParams.addActionListener(new ActionListener()
199     {
200       public void actionPerformed(ActionEvent e)
201       {
202         importParams_actionPerformed(e);
203       }
204     });
205     resetParams.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
206     resetParams.setText("Defaults");
207     resetParams.setToolTipText("Reset to defaults");
208     resetParams.addActionListener(new ActionListener()
209     {
210       public void actionPerformed(ActionEvent e)
211       {
212         resetParams_actionPerformed(e);
213       }
214     });
215     addParam.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
216     addParam.setText("Add");
217     addParam.setToolTipText("Add new parameter");
218     addParam.addActionListener(new ActionListener()
219     {
220       public void actionPerformed(ActionEvent e)
221       {
222         addParam_actionPerformed(e);
223       }
224     });
225     removeParam.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
226     removeParam.setText("Remove");
227     removeParam.setToolTipText("Remove selected parameter");
228     removeParam.addActionListener(new ActionListener()
229     {
230       public void actionPerformed(ActionEvent e)
231       {
232         removeParam_actionPerformed(e);
233       }
234     });
235     editParam.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
236     editParam.setText("Edit");
237     editParam.setToolTipText("Edit selected parameter");
238     editParam.addActionListener(new ActionListener()
239     {
240       public void actionPerformed(ActionEvent e)
241       {
242         editParam_actionPerformed(e);
243       }
244     });
245     startjob.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
246     startjob.setText("Start");
247     startjob.setToolTipText("Start Job");
248     startjob.addActionListener(new ActionListener()
249     {
250       public void actionPerformed(ActionEvent e)
251       {
252         startjob_actionPerformed(e);
253       }
254     });
255     canceljob.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
256     canceljob.setText("Cancel");
257     canceljob.setToolTipText("Cancel Job");
258     canceljob.addActionListener(new ActionListener()
259     {
260       public void actionPerformed(ActionEvent e)
261       {
262         canceljob_actionPerformed(e);
263       }
264     });
265
266     setDetails.setBorder(new TitledBorder("Details"));
267     setDetails.setLayout(new BorderLayout());
268     setDescr.setColumns(40);
269     setDescr.setWrapStyleWord(true);
270     setDescr.setLineWrap(true);
271     setDescr.setBackground(getBackground());
272     setDescr.setEditable(false);
273     JScrollPane setDescrView = new JScrollPane();
274     // setDescrView.setPreferredSize(new Dimension(350, 200));
275     setDescrView.getViewport().setView(setDescr);
276     setName.setEditable(true);
277     setName.addItemListener(this);
278     setName.getEditor().addActionListener(this);
279     modified.setPreferredSize(new Dimension(15, 15));
280     JPanel SetNamePanel = new JPanel();
281     SetNamePanel.setLayout(new BorderLayout());
282     SetNamePanel.add(setName, BorderLayout.WEST);
283     SetNamePanel.add(modified, BorderLayout.EAST);
284     setDetails.add(SetNamePanel, BorderLayout.NORTH);
285     setDetails.add(setDescrView, BorderLayout.CENTER);
286     // setDetails.setPreferredSize(new Dimension(360, 100));
287     jobParameters.setBorder(new TitledBorder("Parameters"));
288     jobParameters.setLayout(jparamLayout = new BorderLayout());
289     paramPane.setPreferredSize(new Dimension(360, 300));
290     paramPane.getVerticalScrollBar().setUnitIncrement(20);
291     // paramPanel.setPreferredSize(new Dimension(360, 300));
292     paramButtons.setLayout(new GridLayout(2, 3));
293     paramButtons.add(addParam);
294     paramButtons.add(editParam);
295     paramButtons.add(removeParam);
296     // TODO: relayout buttons nicely
297     paramButtons.add(exportParams);
298     paramButtons.add(importParams);
299     paramButtons.add(resetParams);
300     paramPane.getViewport().setView(paramList);
301     jobParameters.add(paramPane, BorderLayout.NORTH);
302     // jobParameters.add(paramButtons, BorderLayout.SOUTH);
303     settingsPanel.setLayout(new BorderLayout());
304     // settingsPanel.add(modified, BorderLayout.NORTH);
305     JPanel jobOptionsPanel = new JPanel();
306     jobOptionsPanel.setBorder(new TitledBorder("Options"));
307     jobOptionsPane.getViewport().setView(jobOptions);
308     jobOptionsPanel.add(jobOptionsPane);
309     settingsPanel.add(jobOptionsPanel, BorderLayout.NORTH);
310     settingsPanel.add(jobParameters, BorderLayout.SOUTH);
311
312     setLayout(new BorderLayout());
313     // setPreferredSize(new Dimension(400, 600));
314     // setSize(new Dimension(400, 600));
315     add(setDetails, BorderLayout.NORTH);
316     add(settingsPanel, BorderLayout.CENTER);
317     JPanel dialogpanel = new JPanel();
318     dialogpanel.add(startjob);
319     dialogpanel.add(canceljob);
320     add(dialogpanel, BorderLayout.SOUTH);
321   }
322
323   protected void canceljob_actionPerformed(ActionEvent e)
324   {
325     response = 0;
326     if (frame != null)
327     {
328       frame.setVisible(false);
329     }
330   }
331
332   protected void startjob_actionPerformed(ActionEvent e)
333   {
334     response = 1;
335     if (frame != null)
336     {
337       frame.setVisible(false);
338     }
339   }
340
341   protected void editParam_actionPerformed(ActionEvent e)
342   {
343     // TODO Auto-generated method stub
344
345   }
346
347   protected void removeParam_actionPerformed(ActionEvent e)
348   {
349     // TODO Auto-generated method stub
350
351   }
352
353   protected void addParam_actionPerformed(ActionEvent e)
354   {
355     // TODO Auto-generated method stub
356
357   }
358
359   protected void resetParams_actionPerformed(ActionEvent e)
360   {
361     // TODO Auto-generated method stub
362
363   }
364
365   protected void importParams_actionPerformed(ActionEvent e)
366   {
367     // TODO Auto-generated method stub
368
369   }
370
371   protected void exportParams_actionPerformed(ActionEvent e)
372   {
373     // TODO Auto-generated method stub
374
375   }
376
377   Jws2Instance service;
378
379   void initForService(Jws2Instance service, Preset p,
380           List<Argument> jobArgset)
381   {
382     this.service = service;
383     serviceOptions = service.getRunnerConfig();
384     // add any presets not already added.
385     String curname = (p == null ? "" : p.getName());
386     PresetManager prman = service.getPresets();
387     if (prman != null)
388     {
389       List prList = service.getPresets().getPresets();
390       if (prList != null)
391       {
392         for (Object pr : prList)
393         {
394           if (p == null || !curname.equals(((Preset) pr).getName()))
395           {
396             setName.addItem(((Preset) pr).getName());
397           }
398         }
399       }
400     }
401     updateTable(p, jobArgset);
402   }
403
404   @SuppressWarnings("unchecked")
405   private void updateTable(Preset p, List<Argument> jobArgset)
406   {
407     availableParameters = new ArrayList<Parameter>();
408     List<Parameter> setargs = new ArrayList<Parameter>();
409     // populate table from default parameter set.
410     List<Argument> args = serviceOptions.getArguments();
411
412     // split to params and required arguments
413     {
414       for (Argument arg : args)
415       {
416         Argument myarg = (Argument) arg;
417         // Ideally, Argument would implement isRequired !
418         if (myarg instanceof Parameter)
419         {
420           Parameter parm = (Parameter) myarg;
421           if (true) // parm.isRequired())
422           {
423             addParameter(parm);
424           }
425           else
426           {
427             availableParameters.add(parm);
428           }
429         }
430         else
431         {
432           if (myarg instanceof Option)
433           {
434             Option opt = (Option) myarg;
435             addOption(opt);
436             if (opt.isRequired())
437             {
438               selectOption(opt, opt.getDefaultValue());
439             }
440           }
441           else
442           {
443             System.err.println("Ignoring unknown service argument type "
444                     + arg.getClass().getName());
445           }
446         }
447       }
448       args = null; // no more args to process.
449     }
450     if (p != null)
451     {
452       if (lastParmSet == null)
453       {
454         // initialise setname
455         setName.addItem(p.getName());
456       }
457       setDescr.setText(p.getDescription());
458       // TODO - URL link
459       try
460       {
461         args = p.getArguments(serviceOptions);
462       } catch (Exception e)
463       {
464         e.printStackTrace();
465       }
466       // TODO: check if args should be unselected prior to resetting using the
467       // preset
468       setargs.clear();
469     }
470     else
471     {
472       if (lastParmSet == null)
473       {
474         // first call - so create a dummy name
475         setName.addItem("Defaults *");
476       }
477     }
478     if (jobArgset != null)
479     {
480       argSetModified(true);
481       args = jobArgset;
482     }
483     // get setargs from current object
484     if (args != null)
485     {
486       for (Argument arg : args)
487       {
488         if (arg instanceof Parameter)
489         {
490           setargs.add((Parameter) arg);
491         }
492         else
493         {
494           if (arg instanceof Option)
495           {
496             selectOption((Option) arg, arg.getDefaultValue());
497           }
498         }
499
500       }
501     }
502
503     // mdl.setData(setargs);
504     // jobOptions.setLayout(new GridLayout(optSet.size() / 2 + 1, 2));
505     jobOptions.setPreferredSize(new Dimension(PARAM_WIDTH, optSet.size()
506             * OPTSET_HEIGHT));
507     jobOptions.setLayout(new GridLayout(optSet.size(), 1));
508     refreshParamLayout();
509     // paramPanel.setLayout(new GridLayout(paramSet.size(), 1));
510     // paramList.va
511     // paramPane.getViewport().validate();
512     paramPane.validate();
513     validate();
514   }
515
516   private boolean isModified()
517   {
518     return modified.isVisible();
519   }
520
521   private void argSetModified(boolean b)
522   {
523     modified.setVisible(b);
524     /*
525      * String setn = (String)setName.getSelectedItem(); if (setn==null) return;
526      * int p = setName.getSelectedIndex(); if (b) { if (setn.length()<2 ||
527      * setn.lastIndexOf(" *")!=setn.length()-2) { setn = setn+" *"; } } else {
528      * if (setn.lastIndexOf(" *")==setn.length()-2) { setn =
529      * setn.substring(0,setn.length()-2); } } // edit the list
530      * 
531      * Object[] objects = new Object[setName.getItemCount()]; for (int
532      * i=0;i<objects.length; i++) { objects[i] = setName.getItemAt(i); }
533      * objects[p] = setn; setName.removeAllItems(); for (int
534      * i=0;i<objects.length; i++) { setName.addItem(objects[i]); }
535      * setName.setSelectedIndex(p);
536      */
537     validate();
538   }
539
540   private void addParameter(Parameter parm)
541   {
542     ParamBox pb = paramSet.get(parm.getName());
543     if (pb == null)
544     {
545       pb = new ParamBox(this, parm);
546       paramSet.put(parm.getName(), pb);
547       paramList.add(pb);
548     }
549   }
550
551   private void selectOption(Option opt, String string)
552   {
553     OptionBox cb = optSet.get(opt.getName());
554     if (cb == null)
555     {
556       cb = addOption(opt);
557     }
558     if (string == null)
559     {
560       // no value specified.
561       if (opt.isRequired())
562       {
563         // indicate option needs to be selected!
564       }
565       else
566       {
567         cb.enabled.setSelected(false);
568       }
569     }
570     else
571     {
572       cb.enabled.setSelected(true);
573
574       if (opt.getPossibleValues().contains(string))
575       {
576         cb.val.setSelectedItem(string);
577       }
578       else
579       {
580         throw new Error("Invalid value " + string + " for option " + opt);
581       }
582
583     }
584   }
585
586   Map<String, ParamBox> paramSet = new Hashtable<String, ParamBox>();
587
588   public class ParamBox extends JPanel implements ChangeListener,
589           ActionListener
590   {
591     JCheckBox showDesc = new JCheckBox();
592
593     JTextArea string = new JTextArea();
594     JScrollPane descPanel = new JScrollPane();
595
596     JSlider slider = null;
597
598     JTextField valueField = null;
599
600     ValueConstrain validator = null;
601     JPanel settingPanel = new JPanel();
602     boolean integ = false;
603
604     boolean choice = false;
605
606     public ParamBox(final WsJobParameters pmlayout, Parameter parm)
607     {
608       setLayout(new FlowLayout(FlowLayout.LEFT));
609       setBorder(new TitledBorder(parm.getName()));
610       setPreferredSize(new Dimension(PARAM_WIDTH, PARAM_CLOSEDHEIGHT));
611       string.setFont(new Font("Verdana", Font.PLAIN, 11));
612       string.setBackground(getBackground());
613       // string.setSize(new Dimension(PARAM_WIDTH, 80));
614       string.setEditable(false);
615       showDesc.setText("Show Description");
616       showDesc.setSelected(false);
617       showDesc.setToolTipText(parm.getDescription());
618       //showDesc.setLocation(2,2);
619       descPanel.setPreferredSize(new Dimension(PARAM_WIDTH-20, 90));
620       descPanel.getViewport().setView(string);
621       //descPanel.setLocation(2,17);
622       descPanel.setVisible(false);
623       // string.setMinimumSize(new Dimension(140,80));
624       // string.setMaximumSize(new Dimension(280,80));
625       final ParamBox me=this;
626       showDesc.addActionListener(new ActionListener() {
627
628         @Override
629         public void actionPerformed(ActionEvent e)
630         {
631           boolean show = showDesc.isSelected();
632           descPanel.setVisible(show);
633           me.setPreferredSize(new Dimension(PARAM_WIDTH, (show) ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT));
634           me.validate();
635           pmlayout.refreshParamLayout();
636         }
637       });
638       string.setWrapStyleWord(true);
639       string.setLineWrap(true);
640       string.setColumns(32);
641       string.setText(parm.getDescription());
642       // name.setToolTipText(parm.getDescription());
643       add(showDesc);
644       validator = parm.getValidValue();
645       parameter = parm;
646       if (validator != null)
647       {
648         integ = validator.getType() == Type.Integer;
649       }
650       else
651       {
652         if (parameter.getPossibleValues() != null)
653         {
654           choice = true;
655         }
656       }
657       updateControls(parm);
658       add(descPanel); // , BorderLayout.NORTH);
659       validate();
660     }
661
662
663     boolean adjusting = false;
664
665     Parameter parameter;
666
667     JComboBox choicebox;
668     public int getBoxHeight()
669     {
670       return (showDesc.isSelected() ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT);
671     }
672     public void updateControls(Parameter parm)
673     {
674       adjusting = true;
675       boolean init = valueField == null;
676       float fVal = 0f;
677       int iVal = 0;
678       if (init)
679       {
680         if (choice)
681         {
682           choicebox = new JComboBox();
683           choicebox.addActionListener(this);
684           add(choicebox);
685         }
686         else
687         {
688           slider = new JSlider();
689           slider.addChangeListener(this);
690           valueField = new JTextField();
691           valueField.addActionListener(this);
692           valueField.setPreferredSize(new Dimension(80, 25));
693           JPanel container = new JPanel();
694           // container.setLayout(new FlowLayout());
695           add(slider);// , BorderLayout.SOUTH);
696           add(valueField);// ,BorderLayout.CENTER);
697           // add(container, BorderLayout.EAST);
698           // container.validate();
699
700         }
701       }
702
703       if (parm != null)
704       {
705         if (choice)
706         {
707           List vals = parm.getPossibleValues();
708           for (Object val : vals)
709           {
710             choicebox.addItem(val);
711           }
712           if (parm.getDefaultValue() != null)
713           {
714             choicebox.setSelectedItem(parm.getDefaultValue());
715           }
716         }
717         else
718         {
719           valueField.setText(parm.getDefaultValue());
720         }
721       }
722       updateSliderFromValueField();
723       adjusting = false;
724     }
725
726     public Parameter getParameter()
727     {
728       try
729       {
730         if (choice)
731         {
732           parameter.setDefaultValue((String) choicebox.getSelectedItem());
733         }
734         else
735         {
736           parameter.setDefaultValue(valueField.getText());
737         }
738       } catch (WrongParameterException e)
739       {
740         e.printStackTrace();
741         return null;
742       }
743       return parameter;
744     }
745
746     public Object updateSliderFromValueField()
747     {
748       int iVal;
749       float fVal;
750       if (validator != null)
751       {
752         if (integ)
753         {
754           iVal = 0;
755           try
756           {
757             valueField.setText(valueField.getText().trim());
758             iVal = Integer.valueOf(valueField.getText());
759           } catch (Exception e)
760           {
761           }
762           ;
763           if (validator.getMin() != null && validator.getMax() != null)
764           {
765             slider.getModel().setRangeProperties(iVal, 1,
766                     validator.getMin().intValue(),
767                     validator.getMax().intValue(), true);
768           }
769           else
770           {
771             slider.setVisible(false);
772           }
773           return new int[]
774           { iVal };
775         }
776         else
777         {
778           fVal = 0f;
779           try
780           {
781             fVal = Float.valueOf(valueField.getText());
782           } catch (Exception e)
783           {
784           }
785           ;
786           if (validator.getMin() != null && validator.getMax() != null)
787           {
788             slider.getModel().setRangeProperties((int) fVal * 1000, 1,
789                     (int) validator.getMin().floatValue() * 1000,
790                     (int) validator.getMax().floatValue() * 1000, true);
791           }
792           else
793           {
794             slider.setVisible(false);
795           }
796           return new float[]
797           { fVal };
798         }
799       }
800       else
801       {
802         if (!choice)
803         {
804           slider.setVisible(false);
805           return new String[]
806           { valueField.getText().trim() };
807         }
808         else
809         {
810           return new String[]
811           { (String) choicebox.getSelectedItem() };
812         }
813       }
814
815     }
816
817     @Override
818     public void stateChanged(ChangeEvent e)
819     {
820       if (!adjusting)
821       {
822         valueField.setText(""
823                 + ((integ) ? ("" + (int) slider.getValue())
824                         : ("" + (float) (slider.getValue() / 1000f))));
825       }
826     }
827
828     @Override
829     public void actionPerformed(ActionEvent e)
830     {
831       if (choice)
832       {
833       }
834       else if (!adjusting)
835       {
836         updateSliderFromValueField();
837       }
838       argSetModified(true);
839     }
840
841   }
842
843   Map<String, OptionBox> optSet = new Hashtable<String, OptionBox>();
844
845   public class OptionBox extends JPanel implements ActionListener
846   {
847     JComboBox val = new JComboBox();
848
849     JCheckBox enabled = new JCheckBox();
850
851     Option option;
852
853     public OptionBox(Option opt)
854     {
855       option = opt;
856       setLayout(new BorderLayout());
857       enabled.setSelected(opt.isRequired());
858       enabled.setFont(new Font("Verdana", Font.PLAIN, 11));
859       enabled.setText(opt.getName());
860       enabled.setToolTipText(opt.getDescription());
861       add(enabled, BorderLayout.NORTH);
862       if (opt.getPossibleValues().size() > 1)
863       {
864         setLayout(new GridLayout(1, 2));
865         for (Object str : opt.getPossibleValues())
866         {
867           val.addItem((String) str);
868         }
869         val.setSelectedItem((String) opt.getDefaultValue());
870         val.addActionListener(this);
871         add(val, BorderLayout.SOUTH);
872       }
873       // TODO: add actionListeners for popup (to open further info),
874       // and to update list of parameters if an option is enabled
875       // that takes a value.
876     }
877
878     public Option getOptionIfEnabled()
879     {
880       if (!enabled.isSelected())
881       {
882         return null;
883       }
884       try
885       {
886         if (val.getSelectedItem() != null)
887         {
888           option.setDefaultValue((String) val.getSelectedItem());
889         }
890       } catch (WrongParameterException e)
891       {
892         e.printStackTrace();
893         return null;
894       }
895       return option;
896     }
897
898     @Override
899     public void actionPerformed(ActionEvent e)
900     {
901       argSetModified(true);
902       enabled.setSelected(true);
903     }
904   }
905
906   private OptionBox addOption(Option opt)
907   {
908     OptionBox cb = optSet.get(opt.getName());
909     if (cb == null)
910     {
911       cb = new OptionBox(opt);
912       optSet.put(opt.getName(), cb);
913       jobOptions.add(cb);
914     }
915     return cb;
916   }
917
918   protected void refreshParamLayout()
919   {
920     int s=100;
921     for (ParamBox pbox : paramSet.values()){
922       s+=pbox.getBoxHeight();
923     }
924     paramList.setPreferredSize(new Dimension(PARAM_WIDTH, s));
925     paramList.setLayout(new FlowLayout());
926     validate();
927   }
928
929   /**
930    * testing method - grab a service and parameter set and show the window
931    * 
932    * @param args
933    */
934   public static void main(String[] args)
935   {
936     jalview.ws.jws2.Jws2Discoverer disc = jalview.ws.jws2.Jws2Discoverer
937             .getDiscoverer();
938     int p = 0;
939     if (args.length > 3)
940     {
941       Vector<String> services = new Vector<String>();
942       services.addElement(args[p++]);
943       Jws2Discoverer.setServiceUrls(services);
944     }
945     try
946     {
947       disc.run();
948     } catch (Exception e)
949     {
950       System.err.println("Aborting. Problem discovering services.");
951       e.printStackTrace();
952       return;
953     }
954     Jws2Discoverer.Jws2Instance lastserv = null;
955     for (Jws2Discoverer.Jws2Instance service : disc.getServices())
956     {
957       lastserv = service;
958       if (p < args.length && service.serviceType.equalsIgnoreCase(args[p]))
959       {
960         break;
961       }
962     }
963     if (lastserv != null)
964     {
965       List<Preset> prl = null;
966       Preset pr = null;
967       if (++p < args.length)
968       {
969         PresetManager prman = lastserv.getPresets();
970         if (prman != null)
971         {
972           pr = prman.getPresetByName(args[p]);
973           if (pr == null)
974           {
975             // just grab the last preset.
976             prl = prman.getPresets();
977           }
978         }
979       }
980       Iterator<Preset> en = (prl == null) ? null : prl.iterator();
981       while (true)
982       {
983         if (en != null)
984         {
985           if (!en.hasNext())
986           {
987             en = prl.iterator();
988           }
989           pr = en.next();
990         }
991         WsJobParameters pgui = new WsJobParameters(lastserv, pr);
992         JFrame jf = new JFrame("Parameters for " + lastserv.getActionText());
993         JPanel cont = new JPanel();
994         jf.setPreferredSize(new Dimension(600, 800));
995         cont.add(pgui);
996         jf.add(cont);
997         final Thread thr = Thread.currentThread();
998         jf.addWindowListener(new WindowListener()
999         {
1000
1001           @Override
1002           public void windowActivated(WindowEvent e)
1003           {
1004             // TODO Auto-generated method stub
1005
1006           }
1007
1008           @Override
1009           public void windowClosed(WindowEvent e)
1010           {
1011           }
1012
1013           @Override
1014           public void windowClosing(WindowEvent e)
1015           {
1016             thr.interrupt();
1017
1018           }
1019
1020           @Override
1021           public void windowDeactivated(WindowEvent e)
1022           {
1023             // TODO Auto-generated method stub
1024
1025           }
1026
1027           @Override
1028           public void windowDeiconified(WindowEvent e)
1029           {
1030             // TODO Auto-generated method stub
1031
1032           }
1033
1034           @Override
1035           public void windowIconified(WindowEvent e)
1036           {
1037             // TODO Auto-generated method stub
1038
1039           }
1040
1041           @Override
1042           public void windowOpened(WindowEvent e)
1043           {
1044             // TODO Auto-generated method stub
1045
1046           }
1047
1048         });
1049         jf.setVisible(true);
1050         boolean inter = false;
1051         while (!inter)
1052         {
1053           try
1054           {
1055             Thread.sleep(10000);
1056           } catch (Exception e)
1057           {
1058             inter = true;
1059           }
1060           ;
1061         }
1062         jf.dispose();
1063       }
1064     }
1065   }
1066
1067   public List<Argument> getJobParams()
1068   {
1069     List<Argument> argSet = new ArrayList<Argument>();
1070     // recover options and parameters from GUI
1071     for (OptionBox opts : optSet.values())
1072     {
1073       Option opt = opts.getOptionIfEnabled();
1074       if (opt != null)
1075       {
1076         argSet.add(opt);
1077       }
1078     }
1079     for (ParamBox parambox : paramSet.values())
1080     {
1081       Parameter parm = parambox.getParameter();
1082       if (parm != null)
1083       {
1084         argSet.add(parm);
1085       }
1086     }
1087
1088     return argSet;
1089   }
1090
1091   String lastParmSet = null;
1092
1093   Hashtable<String, Object[]> editedParams = new Hashtable<String, Object[]>();
1094
1095   @Override
1096   public void itemStateChanged(ItemEvent e)
1097   {
1098     if (e.getSource() == setName)
1099     {
1100       String setname = (String) setName.getSelectedItem();
1101       if (setname == null)
1102       {
1103         return;
1104       }
1105       // if modified - warn user - or at least save current edited set.
1106       if (lastParmSet != null)
1107       {
1108         // save current state
1109         Object[] pset;
1110         editedParams.put(lastParmSet, pset = new Object[3]);
1111         pset[0] = lastParmSet;
1112         pset[1] = setDescr.getText();
1113         pset[2] = getJobParams();
1114       }
1115       Object[] pset = editedParams.get(setname);
1116       if (pset != null)
1117       {
1118         setDescr.setText((String) pset[1]);
1119         updateTable(null, (List<Argument>) pset[2]);
1120         lastParmSet = setname;
1121         validate();
1122       }
1123       else
1124       {
1125         // must be a default preset from service
1126         Preset p = null;
1127         try
1128         {
1129           p = service.getPresets().getPresetByName(setname);
1130         } catch (Exception ex)
1131         {
1132           ex.printStackTrace();
1133         }
1134         if (p != null)
1135         {
1136           updateTable(p, null);
1137           validate();
1138           lastParmSet = setname;
1139         }
1140       }
1141
1142     }
1143   }
1144
1145   @Override
1146   public void actionPerformed(ActionEvent e)
1147   {
1148     if (e.getSource() == setName)
1149     {
1150       // rename any existing records we know about for this set.
1151       String newname = (String) setName.getSelectedItem();
1152       System.err.println("Command " + newname + " : "
1153               + e.getActionCommand());
1154     }
1155   }
1156 }