918724c8c842606bbd9c326ab21fbfef8bebd01d
[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.net.URL;
27 import java.util.ArrayList;
28 import java.util.EventObject;
29 import java.util.HashSet;
30 import java.util.Hashtable;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Vector;
35
36 import javax.swing.InputVerifier;
37 import javax.swing.JButton;
38 import javax.swing.JCheckBox;
39 import javax.swing.JComboBox;
40 import javax.swing.JComponent;
41 import javax.swing.JDialog;
42 import javax.swing.JFrame;
43 import javax.swing.JLabel;
44 import javax.swing.JList;
45 import javax.swing.JMenuItem;
46 import javax.swing.JOptionPane;
47 import javax.swing.JPanel;
48 import javax.swing.JPopupMenu;
49 import javax.swing.JScrollPane;
50 import javax.swing.JSlider;
51 import javax.swing.JSplitPane;
52 import javax.swing.JTabbedPane;
53 import javax.swing.JTable;
54 import javax.swing.JTextArea;
55 import javax.swing.JTextField;
56 import javax.swing.ListSelectionModel;
57 import javax.swing.SwingConstants;
58 import javax.swing.SwingUtilities;
59 import javax.swing.border.TitledBorder;
60 import javax.swing.event.CellEditorListener;
61 import javax.swing.event.ChangeEvent;
62 import javax.swing.event.ChangeListener;
63 import javax.swing.event.DocumentEvent;
64 import javax.swing.event.DocumentListener;
65 import javax.swing.table.*;
66
67 import compbio.metadata.Argument;
68 import compbio.metadata.Option;
69 import compbio.metadata.Parameter;
70 import compbio.metadata.Preset;
71 import compbio.metadata.PresetManager;
72 import compbio.metadata.RunnerConfig;
73 import compbio.metadata.ValueConstrain;
74 import compbio.metadata.WrongParameterException;
75 import compbio.metadata.ValueConstrain.Type;
76
77 import jalview.util.jarInputStreamProvider;
78 import jalview.ws.jws2.JabaParamStore;
79 import jalview.ws.jws2.JabaPreset;
80 import jalview.ws.jws2.Jws2Discoverer;
81 import jalview.ws.jws2.ParameterUtils;
82 import jalview.ws.jws2.Jws2Discoverer.Jws2Instance;
83 import jalview.ws.jws2.dm.JabaOption;
84 import jalview.ws.jws2.dm.JabaParameter;
85 import jalview.ws.params.ArgumentI;
86 import jalview.ws.params.OptionI;
87 import jalview.ws.params.ParamDatastoreI;
88 import jalview.ws.params.ParameterI;
89 import jalview.ws.params.ValueConstrainI;
90 import jalview.ws.params.WsParamSetI;
91
92 /**
93  * job parameter editing/browsing dialog box. User can browse existing settings
94  * (user + presets + Defaults), and any changes to parameters creates a modified
95  * user parameter set. LOGIC: If the parameter set is modified, and its name is
96  * a valid, non-existant user parameter set, then a save button is shown. If the
97  * parameter set is modified and its name is a valid, extant user parameter set,
98  * then an update button is shown. If user parameter set's name is edited, and
99  * old name exists as a writable user parameter set, then rename button is
100  * shown. If current parameter set is associated with a user defined parameter
101  * set, then : if set is modifed, a 'revert' button is shown. if set is not
102  * modified, a 'delete' button is shown.
103  * 
104  * @author JimP
105  * 
106  */
107 public class WsJobParameters extends JPanel implements ItemListener,
108         ActionListener, DocumentListener
109 {
110   URL linkImageURL = getClass().getResource("/images/link.gif");
111   private static final String SVC_DEF = "Defaults"; // this is the null
112                                                     // parameter set as shown to
113                                                     // user
114
115   private static final int PARAM_WIDTH = 340, PARAM_HEIGHT = 150,
116           PARAM_CLOSEDHEIGHT = 80;
117
118   private static final int OPTSET_HEIGHT = 30;
119
120   JPanel SetNamePanel = new JPanel();
121
122   JPanel setDetails = new JPanel();
123
124   JSplitPane settingsPanel = new JSplitPane();
125
126   JSplitPane jobPanel = new JSplitPane();
127   boolean split=true;
128   JTabbedPane tabpanels=new JTabbedPane();
129   JPanel jobOptions = new JPanel();
130
131   JScrollPane jobOptionsPane = new JScrollPane();
132
133   JPanel jobParameters = new JPanel();
134
135   JButton createpref = new JButton();
136
137   JButton deletepref = new JButton();
138
139   JButton revertpref = new JButton();
140
141   JButton updatepref = new JButton();
142
143   JButton startjob = new JButton();
144
145   JButton canceljob = new JButton();
146
147   JComboBox setName = new JComboBox();
148
149   JTextArea setDescr = new JTextArea();
150
151   JScrollPane paramPane = new JScrollPane();
152
153   JPanel paramList = new JPanel();
154
155   RunnerConfig serviceOptions;
156
157   ParamDatastoreI paramStore;
158
159   WsJobParameters(Jws2Instance service)
160   {
161     this(service, null);
162   }
163
164   public WsJobParameters(Jws2Instance service, WsParamSetI preset)
165   {
166     this(null, service, preset, null);
167   }
168
169   /**
170    * 
171    * @param desktop
172    *          - if null, create new JFrame outside of desktop
173    * @param service
174    * @param preset
175    */
176   public WsJobParameters(JFrame parent, Jws2Instance service,
177           WsParamSetI preset, List<Argument> jobArgset)
178   {
179     this(parent, null, service, preset, jobArgset);
180   }
181
182   /**
183    * 
184    * @param parent
185    * @param paramStorei
186    * @param service
187    * @param preset
188    * @param jobArgset
189    */
190   public WsJobParameters(JFrame parent, ParamDatastoreI paramStorei,
191           Jws2Instance service, WsParamSetI preset, List<Argument> jobArgset)
192   {
193     super();
194     jbInit();
195     this.paramStore = paramStorei;
196     if (paramStore == null)
197     {
198       paramStore = service.getParamStore();
199     }
200     this.service = service;
201     // argSetModified(false);
202     // populate parameter table
203     initForService(service, preset, jobArgset);
204     // display in new JFrame attached to parent.
205     validate();
206   }
207
208   int response = -1;
209
210   JDialog frame = null;
211
212   /**
213    * shows a modal dialog containing the parameters.
214    * 
215    * @return
216    */
217   public boolean showRunDialog()
218   {
219
220     frame = new JDialog(Desktop.instance, true);
221
222     frame.setTitle("Edit parameters for " + service.getActionText());
223     Rectangle deskr = Desktop.instance.getBounds();
224     frame.setBounds(new Rectangle((int) (deskr.getCenterX() - 240),
225             (int) (deskr.getCenterY() - 250), 480, 500));
226     frame.setContentPane(this);
227     // should recover defaults from user prefs.
228     //settingsPanel.setDividerLocation(0.4);
229     //jobPanel.setDividerLocation(0.5);
230     frame.validate();
231     if (split) {
232       javax.swing.SwingUtilities.invokeLater(new Runnable() {
233         public void run() {
234           settingsPanel.setDividerLocation(0.5);
235           jobPanel.setDividerLocation(setDescr.getLineCount()>3 ? 0.35 : 0.16 );
236         }
237       });
238     } else {
239       tabpanels.setSelectedComponent(jobOptionsPane);
240     }
241     frame.setVisible(true);
242
243     if (response > 0)
244     {
245       return true;
246     }
247     return false;
248   }
249
250
251   private void jbInit()
252   {
253     updatepref = JvSwingUtils.makeButton("Update", "Update this existing user parameter set.",
254             new ActionListener()
255             {
256
257               public void actionPerformed(ActionEvent e)
258               {
259                 update_actionPerformed(e);
260               }
261             });
262     deletepref = JvSwingUtils.makeButton("Delete", "Delete the currently selected user parameter set.",
263             new ActionListener()
264             {
265
266               public void actionPerformed(ActionEvent e)
267               {
268                 delete_actionPerformed(e);
269               }
270             });
271     createpref = JvSwingUtils.makeButton("Create", "Create a new parameter set with the current settings.",
272             new ActionListener()
273             {
274
275               public void actionPerformed(ActionEvent e)
276               {
277                 create_actionPerformed(e);
278               }
279             });
280     revertpref = JvSwingUtils.makeButton("Revert",
281             "Undo all changes to the current parameter set", new ActionListener()
282             {
283
284               public void actionPerformed(ActionEvent e)
285               {
286                 revert_actionPerformed(e);
287               }
288             });
289     startjob = JvSwingUtils.makeButton("Start Job", "Start Job with current settings.",new ActionListener()
290     {
291       public void actionPerformed(ActionEvent e)
292       {
293         startjob_actionPerformed(e);
294       }
295     });
296     canceljob = JvSwingUtils.makeButton("Cancel Job", "Close this dialog and cancel job.", new ActionListener()
297     {
298       public void actionPerformed(ActionEvent e)
299       {
300         canceljob_actionPerformed(e);
301       }
302     });
303
304     setDetails.setBorder(new TitledBorder("Details"));
305     setDetails.setLayout(new BorderLayout());
306     setDescr.setColumns(40);
307     setDescr.setWrapStyleWord(true);
308     setDescr.setLineWrap(true);
309     setDescr.setBackground(getBackground());
310     setDescr.setEditable(true);
311     setDescr.getDocument().addDocumentListener(this);
312     setDescr.setToolTipText("Click to edit the notes for this parameter set.");
313     JScrollPane setDescrView = new JScrollPane();
314     // setDescrView.setPreferredSize(new Dimension(350, 200));
315     setDescrView.getViewport().setView(setDescr);
316     setName.setEditable(true);
317     setName.addItemListener(this);
318     setName.getEditor().addActionListener(this);
319     JPanel setNameInfo = new JPanel(new FlowLayout(FlowLayout.LEFT));
320     SetNamePanel.setLayout(new GridLayout(2, 1));
321     SetNamePanel.setMinimumSize(new Dimension(300, 40));
322     JLabel setNameLabel = new JLabel("Current parameter set name :");
323     setNameLabel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
324     // setNameLabel.setHorizontalAlignment(FlowLayout.LEFT);
325     setNameInfo.add(setNameLabel);
326     setNameInfo.add(setName);
327     // initial button visibility
328     updatepref.setVisible(false);
329     deletepref.setVisible(false);
330     revertpref.setVisible(false);
331     createpref.setVisible(false);
332     JPanel setsavebuts = new JPanel();
333     setsavebuts.setLayout(new FlowLayout(FlowLayout.LEFT)); // GridLayout(1,2));
334     ((FlowLayout) setsavebuts.getLayout()).setHgap(10);
335     ((FlowLayout) setsavebuts.getLayout()).setVgap(0);
336     setsavebuts.add(deletepref);
337     setsavebuts.add(revertpref);
338     setsavebuts.add(createpref);
339     setsavebuts.add(updatepref);
340     setsavebuts.setSize(new Dimension(150, 20));
341     JPanel buttonArea = new JPanel(new GridLayout(1, 1));
342     buttonArea.add(setsavebuts);
343     SetNamePanel.add(setNameInfo);
344     SetNamePanel.add(buttonArea);
345     setDetails.add(setDescrView, BorderLayout.CENTER);
346     //setDetails.setPreferredSize(new Dimension(360, 100));
347     jobParameters.setBorder(new TitledBorder("Parameters"));
348     jobParameters.setLayout(new BorderLayout());
349     paramPane.setPreferredSize(new Dimension(360, 300));
350     paramPane.getVerticalScrollBar().setUnitIncrement(20);
351     // paramPanel.setPreferredSize(new Dimension(360, 300));
352     // TODO: relayout buttons nicely
353     paramPane.getViewport().setView(paramList);
354     jobParameters.add(paramPane, BorderLayout.CENTER);
355     JPanel jobOptionsPanel = new JPanel();
356     jobOptionsPanel.setLayout(new BorderLayout());
357     jobOptionsPanel.setBorder(new TitledBorder("Options"));
358     jobOptionsPane.getViewport().setView(jobOptions);
359     jobOptionsPanel.add(jobOptionsPane, BorderLayout.CENTER);
360     
361     setLayout(new BorderLayout());
362     jobPanel.setLeftComponent(setDetails);
363     if (split) {
364       settingsPanel.setLeftComponent(jobOptionsPanel);
365       settingsPanel.setRightComponent(jobParameters);
366       settingsPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
367       jobPanel.setRightComponent(settingsPanel);
368     } else {
369     jobPanel.setRightComponent(tabpanels);
370     jobOptionsPane.setName("Options");
371     tabpanels.add(jobOptionsPane);
372     paramPane.setName("Parameters");
373     tabpanels.add(paramPane);
374     }
375     jobPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
376     add(SetNamePanel, BorderLayout.NORTH);    
377     add(jobPanel, BorderLayout.CENTER);
378     JPanel dialogpanel = new JPanel();
379     dialogpanel.add(startjob);
380     dialogpanel.add(canceljob);
381     add(dialogpanel, BorderLayout.SOUTH);
382   }
383
384   protected void revert_actionPerformed(ActionEvent e)
385   {
386     reInitDialog(lastParmSet);
387
388   }
389
390   protected void update_actionPerformed(ActionEvent e)
391   {
392     if (isUserPreset)
393     {
394       String curname = ((String) setName.getSelectedItem()).trim();
395       _updatePreset(lastParmSet, curname);
396       lastParmSet = curname;
397       isUserPreset = true;
398       initArgSetModified();
399       syncSetNamesWithStore();
400     }
401   }
402
403   private void _deleteUserPreset(String lastParmSet2)
404   {
405     paramStore.deletePreset(lastParmSet2);
406   }
407
408   protected void delete_actionPerformed(ActionEvent e)
409   {
410     if (isUserPreset)
411     {
412       // delete current preset's saved entry
413       _deleteUserPreset(lastParmSet);
414     }
415     reInitDialog(null); // service default
416   }
417
418   protected void create_actionPerformed(ActionEvent e)
419   {
420     String curname = ((String) setName.getSelectedItem()).trim();
421     if (curname.length() > 0)
422     {
423       _storeCurrentPreset(curname);
424       lastParmSet = curname;
425       isUserPreset = true;
426       initArgSetModified();
427     }
428     else
429     {
430       // TODO: show warning
431       System.err.println("Invalid name. Not saved.");
432     }
433   }
434
435   protected void canceljob_actionPerformed(ActionEvent e)
436   {
437     response = 0;
438     if (frame != null)
439     {
440       frame.setVisible(false);
441     }
442   }
443
444   protected void startjob_actionPerformed(ActionEvent e)
445   {
446     response = 1;
447     if (frame != null)
448     {
449       frame.setVisible(false);
450     }
451   }
452
453   Jws2Instance service;
454
455   /**
456    * list of service presets in the gui
457    */
458   Hashtable servicePresets = null;
459
460   /**
461    * set if dialog is being set - so handlers will avoid spurious events
462    */
463   boolean settingDialog = false;
464
465   void initForService(Jws2Instance service, WsParamSetI jabap,
466           List<Argument> jabajobArgset)
467   {
468     WsParamSetI p = null;
469     List<ArgumentI> jobArgset = null;
470     settingDialog = true;
471     { // instantiate the abstract proxy for Jaba objects
472       jobArgset = jabajobArgset == null ? null : JabaParamStore
473               .getJwsArgsfromJaba(jabajobArgset);
474       p = jabap; // (jabap != null) ? paramStore.getPreset(jabap.getName()) :
475                  // null;
476     }
477     // TODO: Recover window geometry prefs for this service
478     // jobPanel.setDividerLocation(proportionalLocation)
479     // settingsPanel.setDividerLocation(proportionalLocation)
480     Hashtable exnames = new Hashtable();
481     for (int i = 0, iSize = setName.getItemCount(); i < iSize; i++)
482     {
483       exnames.put((String) setName.getItemAt(i), setName.getItemAt(i));
484     }
485     servicePresets = new Hashtable();
486     // Add the default entry - if not present already.
487     if (!exnames.contains(SVC_DEF))
488     {
489       setName.addItem(SVC_DEF);
490       exnames.put(SVC_DEF, SVC_DEF);
491       servicePresets.put(SVC_DEF, SVC_DEF);
492     }
493     String curname = (p == null ? "" : p.getName());
494     for (WsParamSetI pr : paramStore.getPresets())
495     {
496       if (!pr.isModifiable())
497       {
498         servicePresets.put(pr.getName(), "preset");
499       }
500       else
501       {
502       }
503       if (!exnames.contains(pr.getName()))
504       {
505         setName.addItem(pr.getName());
506       }
507     }
508     // TODO: if initial jobArgset matches a given user setting or preset then
509     // should recover setting accordingly
510     // updateTable(p, jobArgset);
511     if (p != null)
512     {
513       reInitDialog(p.getName());
514       initArgSetModified();
515     }
516     else
517     {
518       if (jobArgset != null && jobArgset.size() > 0)
519       {
520         curSetName = "Supplied Settings";
521         updateTable(p, jobArgset);
522       }
523       else
524       {
525         curSetName = null;
526         reInitDialog(null);
527       }
528     }
529     settingDialog = false;
530
531   }
532
533   @SuppressWarnings("unchecked")
534   private void updateTable(WsParamSetI p, List<ArgumentI> jobArgset)
535   {
536     // populate table from default parameter set.
537     List<ArgumentI> args = paramStore.getServiceParameters();
538
539     // split to params and required arguments
540     {
541       for (ArgumentI myarg : args)
542       {
543         // Ideally, Argument would implement isRequired !
544         if (myarg instanceof ParameterI)
545         {
546           ParameterI parm = (ParameterI) myarg;
547           addParameter(parm);
548         }
549         else
550         {
551           if (myarg instanceof OptionI)
552           {
553             OptionI opt = (OptionI) myarg;
554             addOption(opt).resetToDefault();
555           }
556           else
557           {
558             System.err.println("Ignoring unknown service argument type "
559                     + myarg.getClass().getName());
560           }
561         }
562       }
563       args = null; // no more args to process.
564     }
565     if (p != null)
566     {
567       isUserPreset = false;
568       // initialise setname
569       setName.setSelectedItem(lastSetName = p.getName());
570       setDescr.setText(lastDescrText = p.getDescription());
571       // TODO - URL link
572       try
573       {
574         args = p.getArguments();
575       } catch (Exception e)
576       {
577         e.printStackTrace();
578       }
579       // TODO: check if args should be unselected prior to resetting using the
580       // preset
581     }
582     else
583     {
584       if (lastParmSet == null)
585       {
586         isUserPreset = false;
587         // first call - so create a dummy name
588
589         setName.setSelectedItem(lastSetName = SVC_DEF);
590       }
591     }
592
593     if (jobArgset != null)
594     {
595       argSetModified(jobArgset, true);
596       args = jobArgset;
597     }
598     // get setargs from current object
599     if (args != null)
600     {
601       for (ArgumentI arg : args)
602       {
603         if (arg instanceof ParameterI)
604         {
605           setParameter((ParameterI) arg);
606         }
607         else
608         {
609           if (arg instanceof OptionI)
610           {
611             // System.out.println("Setting option "
612             // + System.identityHashCode(arg) + ":" + arg.getName()
613             // + " with " + arg.getDefaultValue());
614             selectOption((OptionI) arg, arg.getDefaultValue());
615           }
616         }
617
618       }
619     }
620
621     jobOptions.setPreferredSize(new Dimension(PARAM_WIDTH, optSet.size()
622             * OPTSET_HEIGHT));
623     jobOptions.setLayout(new GridLayout(optSet.size(), 1));
624     refreshParamLayout();
625     paramPane.validate();
626     revalidate();
627   }
628
629   private boolean isModified()
630   {
631     return modifiedElements.size() > 0;
632   }
633
634   private Hashtable modifiedElements = new Hashtable();
635
636   /**
637    * reset gui and modification state settings
638    */
639   private void initArgSetModified()
640   {
641     curSetName = null;
642     modifiedElements.clear();
643     updateButtonDisplay();
644   }
645
646   private void updateButtonDisplay()
647   {
648     boolean _update = false, _create = false, _delete = false, _revert = false;
649     if (modifiedElements.size() > 0)
650     {
651       // set modified
652       _revert = true;
653       _update = isUserPreset; // can only update user presets
654       if (!isUserPreset || modifiedElements.containsKey(setName))
655       {
656         // name modified - can create new preset
657         _create = true;
658       }
659     }
660     else
661     {
662       // set unmodified
663     }
664     // can still delete a user preset
665     _delete = isUserPreset;
666
667     createpref.setVisible(_create);
668     updatepref.setVisible(_update);
669     deletepref.setVisible(_delete);
670     revertpref.setVisible(_revert);
671     validate();
672   }
673
674   private void argSetModified(Object modifiedElement, boolean b)
675   {
676     if (settingDialog)
677     {
678       return;
679     }
680     if (!b)
681     {
682       modifiedElements.remove(modifiedElement);
683     }
684     else
685     {
686       if (b && modifiedElement == setName
687               && modifiedElements.contains(modifiedElement))
688       {
689         // HACK! prevents iteration on makeSetNameValid
690         b = false;
691       }
692       modifiedElements.put(modifiedElement, modifiedElement);
693     }
694     // set mod status based on presence of elements in table
695     if (b && modifiedElements.size() > 0)
696     {
697       makeSetNameValid(!isUserPreset);
698       SetNamePanel.revalidate();
699     }
700     updateButtonDisplay();
701   }
702
703   private boolean isServicePreset(String selectedItem)
704   {
705     return selectedItem.equals(SVC_DEF)
706             || servicePresets.containsKey(selectedItem);
707   }
708
709   /**
710    * check if the current set name is a valid set name for saving, if not, then
711    * fix it.
712    */
713   private void makeSetNameValid(boolean newuserset)
714   {
715     boolean stn = settingDialog;
716     boolean renamed = false;
717     settingDialog = true;
718     String nm = (curSetName != null ? curSetName : (String) setName
719             .getSelectedItem());
720     // check if the name is reserved - if it is, rename it.
721     if (isServicePreset(nm))
722     {
723       nm = "User " + nm;
724       renamed = true;
725     }
726     String tnm = nm;
727     if (newuserset)
728     {
729       int i = 0;
730       while (paramStore.getPreset(tnm) != null)
731       {
732         tnm = nm + " (" + (++i) + ")";
733         renamed = true;
734       }
735       if (i > 0)
736       {
737         nm = tnm;
738       }
739     }
740
741     boolean makeupdate = false;
742     // sync the gui with the preset database
743     for (int i = 0, iS = setName.getItemCount(); i < iS; i++)
744     {
745       String snm = (String) setName.getItemAt(i);
746       if (snm.equals(nm))
747       {
748         makeupdate = true;
749         // setName.setSelectedIndex(i);
750       }
751     }
752     if (!makeupdate)
753     {
754       setName.addItem(curSetName = nm);
755       setName.setSelectedItem(curSetName);
756     }
757     if (renamed)
758     {
759       settingDialog = false; // we need this name change to be registered.
760       argSetModified(setName, renamed);
761     }
762     settingDialog = stn;
763   }
764
765   private void addParameter(ParameterI arg)
766   {
767     ParamBox pb = paramSet.get(arg.getName());
768     if (pb == null)
769     {
770       pb = new ParamBox(this, arg);
771       paramSet.put(arg.getName(), pb);
772       paramList.add(pb);
773     }
774     pb.init();
775     // take the defaults from the parameter
776     pb.updateControls(arg);
777   }
778
779   private void setParameter(ParameterI arg)
780   {
781     ParamBox pb = paramSet.get(arg.getName());
782     if (pb == null)
783     {
784       addParameter(arg);
785     }
786     else
787     {
788       pb.updateControls(arg);
789     }
790
791   }
792
793   private void selectOption(OptionI option, String string)
794   {
795     OptionBox cb = optSet.get(option.getName());
796     if (cb == null)
797     {
798       cb = addOption(option);
799     }
800     cb.enabled.setSelected(string != null); // initial state for an option.
801     if (string != null)
802     {
803       if (option.getPossibleValues().contains(string))
804       {
805         cb.val.setSelectedItem(string);
806       }
807       else
808       {
809         throw new Error("Invalid value " + string + " for option " + option);
810       }
811
812     }
813     if (option.isRequired() && !cb.enabled.isSelected())
814     {
815       // TODO: indicate paramset is not valid.. option needs to be selected!
816     }
817     cb.setInitialValue();
818   }
819
820   Map<String, ParamBox> paramSet = new Hashtable<String, ParamBox>();
821
822   public class ParamBox extends JPanel implements ChangeListener,
823           ActionListener, MouseListener
824   {
825     JButton showDesc = new JButton();
826
827     JTextArea string = new JTextArea();
828
829     JScrollPane descPanel = new JScrollPane();
830
831     JSlider slider = null;
832
833     JTextField valueField = null;
834
835     ValueConstrainI validator = null;
836
837     JPanel settingPanel = new JPanel();
838
839     JPanel controlPanel = new JPanel();
840
841     boolean integ = false;
842
843     boolean choice = false;
844
845     boolean descisvisible = false;
846
847     final WsJobParameters pmdialogbox;
848
849     final URL finfo;
850
851     public ParamBox(final WsJobParameters pmlayout, ParameterI parm)
852     {
853       pmdialogbox = pmlayout;
854       setPreferredSize(new Dimension(PARAM_WIDTH, PARAM_CLOSEDHEIGHT));
855       setBorder(new TitledBorder(parm.getName()));
856       setLayout(null);
857       showDesc.setFont(new Font("Verdana", Font.PLAIN, 6));
858       showDesc.setText("+");
859       string.setFont(new Font("Verdana", Font.PLAIN, 11));
860       string.setBackground(getBackground());
861       // string.setSize(new Dimension(PARAM_WIDTH, 80));
862       string.setEditable(false);
863       descPanel.getViewport().setView(string);
864       // descPanel.setLocation(2,17);
865       descPanel.setVisible(false);
866       // string.setMinimumSize(new Dimension(140,80));
867       // string.setMaximumSize(new Dimension(280,80));
868       final ParamBox me = this;
869       finfo = parm.getFurtherDetails();
870       if (finfo != null)
871       {
872         showDesc.setToolTipText("<html>"+JvSwingUtils.wrapTooltip("Click to show brief description<br><img src=\"" + linkImageURL + "\"/> Right click for further information.")+"</html>");
873         showDesc.addMouseListener(this);
874       }
875       else
876       {
877         showDesc.setToolTipText("<html>"+JvSwingUtils.wrapTooltip("Click to show brief description.")+"</html>");
878       }
879       showDesc.addActionListener(new ActionListener()
880       {
881
882         public void actionPerformed(ActionEvent e)
883         {
884           descisvisible = !descisvisible;
885           descPanel.setVisible(descisvisible);
886           me.setPreferredSize(new Dimension(PARAM_WIDTH,
887                   (descisvisible) ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT));
888           me.validate();
889           pmlayout.refreshParamLayout();
890         }
891       });
892       string.setWrapStyleWord(true);
893       string.setLineWrap(true);
894       string.setColumns(32);
895       string.setText(parm.getDescription());
896       JPanel firstrow = new JPanel();
897       firstrow.setLayout(null);
898       controlPanel.setLayout(new BorderLayout());
899       controlPanel.setBounds(new Rectangle(39, 10, PARAM_WIDTH - 70,
900               PARAM_CLOSEDHEIGHT - 50));
901       showDesc.setBounds(new Rectangle(10, 10, 16, 16));
902       firstrow.add(showDesc);
903       firstrow.add(controlPanel);
904       firstrow.setBounds(new Rectangle(10, 20, PARAM_WIDTH - 30,
905               PARAM_CLOSEDHEIGHT - 30));
906       add(firstrow);
907       validator = parm.getValidValue();
908       parameter = parm;
909       if (validator != null)
910       {
911         integ = validator.getType() == Type.Integer;
912       }
913       else
914       {
915         if (parameter.getPossibleValues() != null)
916         {
917           choice = true;
918         }
919       }
920       updateControls(parm);
921       descPanel.setBounds(new Rectangle(10, PARAM_CLOSEDHEIGHT,
922               PARAM_WIDTH - 20, PARAM_HEIGHT - PARAM_CLOSEDHEIGHT - 5));
923       add(descPanel);
924       validate();
925     }
926
927     public void init()
928     {
929       // reset the widget's initial value.
930       lastVal = null;
931     }
932
933     boolean adjusting = false;
934
935     ParameterI parameter;
936
937     JComboBox choicebox;
938
939     public int getBoxHeight()
940     {
941       return (descisvisible ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT);
942     }
943
944     public void updateControls(ParameterI parm)
945     {
946       adjusting = true;
947       boolean init = (choicebox == null && valueField == null);
948       float fVal = 0f;
949       int iVal = 0;
950       if (init)
951       {
952         if (choice)
953         {
954           choicebox = new JComboBox();
955           choicebox.addActionListener(this);
956           controlPanel.add(choicebox, BorderLayout.CENTER);
957         }
958         else
959         {
960           slider = new JSlider();
961           slider.addChangeListener(this);
962           valueField = new JTextField();
963           valueField.addActionListener(this);
964           valueField.setPreferredSize(new Dimension(60, 25));
965           controlPanel.add(slider, BorderLayout.WEST);
966           controlPanel.add(valueField, BorderLayout.EAST);
967
968         }
969       }
970
971       if (parm != null)
972       {
973         if (choice)
974         {
975           if (init)
976           {
977             List vals = parm.getPossibleValues();
978             for (Object val : vals)
979             {
980               choicebox.addItem(val);
981             }
982           }
983
984           if (parm.getDefaultValue() != null)
985           {
986             choicebox.setSelectedItem(parm.getDefaultValue());
987           }
988         }
989         else
990         {
991           valueField.setText(parm.getDefaultValue());
992         }
993       }
994       lastVal = updateSliderFromValueField();
995       adjusting = false;
996     }
997
998     Object lastVal;
999
1000     public ParameterI getParameter()
1001     {
1002       ParameterI prm = parameter.copy();
1003       if (choice)
1004       {
1005         prm.setDefaultValue((String) choicebox.getSelectedItem());
1006       }
1007       else
1008       {
1009         prm.setDefaultValue(valueField.getText());
1010       }
1011       return prm;
1012     }
1013
1014     public Object updateSliderFromValueField()
1015     {
1016       int iVal;
1017       float fVal;
1018       if (validator != null)
1019       {
1020         if (integ)
1021         {
1022           iVal = 0;
1023           try
1024           {
1025             valueField.setText(valueField.getText().trim());
1026             iVal = Integer.valueOf(valueField.getText());
1027             if (validator.getMin() != null
1028                     && validator.getMin().intValue() > iVal)
1029             {
1030               iVal = validator.getMin().intValue();
1031               // TODO: provide visual indication that hard limit was reached for
1032               // this parameter
1033             }
1034             if (validator.getMax() != null
1035                     && validator.getMax().intValue() < iVal)
1036             {
1037               iVal = validator.getMax().intValue();
1038               // TODO: provide visual indication that hard limit was reached for
1039               // this parameter
1040             }
1041           } catch (Exception e)
1042           {
1043           }
1044           ;
1045           if (validator.getMin() != null && validator.getMax() != null)
1046           {
1047             slider.getModel().setRangeProperties(iVal, 1,
1048                     validator.getMin().intValue(),
1049                     validator.getMax().intValue(), true);
1050           }
1051           else
1052           {
1053             slider.setVisible(false);
1054           }
1055           return new int[]
1056           { iVal };
1057         }
1058         else
1059         {
1060           fVal = 0f;
1061           try
1062           {
1063             fVal = Float.valueOf(valueField.getText());
1064             if (validator.getMin() != null
1065                     && validator.getMin().floatValue() > fVal)
1066             {
1067               fVal = validator.getMin().floatValue();
1068               // TODO: provide visual indication that hard limit was reached for
1069               // this parameter
1070             }
1071             if (validator.getMax() != null
1072                     && validator.getMax().floatValue() < fVal)
1073             {
1074               fVal = validator.getMax().floatValue();
1075               // TODO: provide visual indication that hard limit was reached for
1076               // this parameter
1077             }
1078           } catch (Exception e)
1079           {
1080           }
1081           ;
1082           if (validator.getMin() != null && validator.getMax() != null)
1083           {
1084             slider.getModel().setRangeProperties((int) fVal * 1000, 1,
1085                     (int) validator.getMin().floatValue() * 1000,
1086                     (int) validator.getMax().floatValue() * 1000, true);
1087           }
1088           else
1089           {
1090             slider.setVisible(false);
1091           }
1092           return new float[]
1093           { fVal };
1094         }
1095       }
1096       else
1097       {
1098         if (!choice)
1099         {
1100           slider.setVisible(false);
1101           return new String[]
1102           { valueField.getText().trim() };
1103         }
1104         else
1105         {
1106           return new String[]
1107           { (String) choicebox.getSelectedItem() };
1108         }
1109       }
1110
1111     }
1112
1113     public void stateChanged(ChangeEvent e)
1114     {
1115       if (!adjusting)
1116       {
1117         valueField.setText(""
1118                 + ((integ) ? ("" + (int) slider.getValue())
1119                         : ("" + (float) (slider.getValue() / 1000f))));
1120         checkIfModified();
1121       }
1122
1123     }
1124
1125     public void actionPerformed(ActionEvent e)
1126     {
1127       if (adjusting)
1128       {
1129         return;
1130       }
1131       if (!choice)
1132       {
1133         updateSliderFromValueField();
1134       }
1135       checkIfModified();
1136     }
1137
1138     private void checkIfModified()
1139     {
1140       Object cstate = updateSliderFromValueField();
1141       boolean notmod = false;
1142       if (cstate.getClass() == lastVal.getClass())
1143       {
1144         if (cstate instanceof int[])
1145         {
1146           notmod = (((int[]) cstate)[0] == ((int[]) lastVal)[0]);
1147         }
1148         else if (cstate instanceof float[])
1149         {
1150           notmod = (((float[]) cstate)[0] == ((float[]) lastVal)[0]);
1151         }
1152         else if (cstate instanceof String[])
1153         {
1154           notmod = (((String[]) cstate)[0].equals(((String[]) lastVal)[0]));
1155         }
1156       }
1157       pmdialogbox.argSetModified(this, !notmod);
1158     }
1159
1160     public void mouseClicked(MouseEvent e)
1161     {
1162       if (javax.swing.SwingUtilities.isRightMouseButton(e))
1163       {
1164         showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
1165       }
1166     }
1167
1168     public void mousePressed(MouseEvent e)
1169     {
1170       // TODO Auto-generated method stub
1171
1172     }
1173
1174     public void mouseReleased(MouseEvent e)
1175     {
1176       // TODO Auto-generated method stub
1177
1178     }
1179
1180     public void mouseEntered(MouseEvent e)
1181     {
1182       // TODO Auto-generated method stub
1183
1184     }
1185
1186     public void mouseExited(MouseEvent e)
1187     {
1188       // TODO Auto-generated method stub
1189
1190     }
1191
1192   }
1193
1194   Map<String, OptionBox> optSet = new Hashtable<String, OptionBox>();
1195
1196   public class OptionBox extends JPanel implements MouseListener,
1197           ActionListener
1198   {
1199     JComboBox val = new JComboBox();
1200
1201     JCheckBox enabled = new JCheckBox();
1202
1203     JLabel optlabel = new JLabel();
1204
1205     final URL finfo;
1206
1207     boolean hasLink = false;
1208
1209     OptionI option;
1210
1211     public OptionBox(OptionI opt)
1212     {
1213       option = opt;
1214       setLayout(new BorderLayout());
1215       enabled.setSelected(opt.isRequired()); // TODO: lock required options
1216       enabled.setFont(new Font("Verdana", Font.PLAIN, 11));
1217       enabled.setText("");
1218       enabled.setText(opt.getName());
1219       enabled.addActionListener(this);
1220       finfo = option.getFurtherDetails();
1221       if (finfo != null)
1222       {
1223         hasLink = true;
1224         // optlabel.setToolTipText("<html><p>"+opt.getDescription()+"</p><img src=\""+linkImageURL+"\"/></html>");
1225         enabled.setToolTipText("<html>" + JvSwingUtils.wrapTooltip(opt.getDescription()+"<br><img src=\"" + linkImageURL + "\"/>")
1226                 + "</html>");
1227         // optlabel.addMouseListener(this);
1228         enabled.addMouseListener(this);
1229       }
1230       else
1231       {
1232         // optlabel.setToolTipText(opt.getDescription());
1233         enabled.setToolTipText("<html>"+JvSwingUtils.wrapTooltip(opt.getDescription())+"</html>");
1234       }
1235       add(enabled, BorderLayout.NORTH);
1236       if (opt.getPossibleValues().size() > 1)
1237       {
1238         setLayout(new GridLayout(1, 2));
1239         for (Object str : opt.getPossibleValues())
1240         {
1241           val.addItem((String) str);
1242         }
1243         val.setSelectedItem((String) opt.getDefaultValue());
1244         val.addActionListener(this);
1245         add(val, BorderLayout.SOUTH);
1246       }
1247       // TODO: add actionListeners for popup (to open further info),
1248       // and to update list of parameters if an option is enabled
1249       // that takes a value.
1250       setInitialValue();
1251     }
1252
1253     public void resetToDefault()
1254     {
1255       enabled.setSelected(false);
1256       if (option.isRequired())
1257       {
1258         // Apply default value
1259         selectOption(option, option.getDefaultValue());
1260       }
1261     }
1262
1263     boolean initEnabled = false;
1264
1265     String initVal = null;
1266
1267     public void setInitialValue()
1268     {
1269       initEnabled = enabled.isSelected();
1270       if (option.getPossibleValues() != null
1271               && option.getPossibleValues().size() > 1)
1272       {
1273         initVal = (String) val.getSelectedItem();
1274       }
1275       else
1276       {
1277         initVal = (initEnabled) ? option.getDefaultValue() : null;
1278       }
1279     }
1280
1281     public OptionI getOptionIfEnabled()
1282     {
1283       if (!enabled.isSelected())
1284       {
1285         return null;
1286       }
1287       OptionI opt = option.copy();
1288
1289       if (val.getSelectedItem() != null)
1290       {
1291         opt.setDefaultValue((String) val.getSelectedItem());
1292       }
1293       return opt;
1294     }
1295
1296     public void actionPerformed(ActionEvent e)
1297     {
1298       if (e.getSource() != enabled)
1299       {
1300         enabled.setSelected(true);
1301       }
1302       checkIfModified();
1303     }
1304
1305     private void checkIfModified()
1306     {
1307       boolean notmod = (initEnabled == enabled.isSelected());
1308       if (enabled.isSelected())
1309       {
1310         if (initVal != null)
1311         {
1312           notmod &= initVal.equals(val.getSelectedItem());
1313         }
1314         else
1315         {
1316           // compare against default service setting
1317           notmod &= option.getDefaultValue() == null
1318                   || option.getDefaultValue().equals(val.getSelectedItem());
1319         }
1320       }
1321       else
1322       {
1323         notmod &= initVal == null;
1324       }
1325       argSetModified(this, !notmod);
1326     }
1327
1328     public void mouseClicked(MouseEvent e)
1329     {
1330       if (javax.swing.SwingUtilities.isRightMouseButton(e))
1331       {
1332         showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
1333       }
1334     }
1335
1336     public void mousePressed(MouseEvent e)
1337     {
1338       // TODO Auto-generated method stub
1339
1340     }
1341
1342     public void mouseReleased(MouseEvent e)
1343     {
1344       // TODO Auto-generated method stub
1345
1346     }
1347
1348     public void mouseEntered(MouseEvent e)
1349     {
1350       // TODO Auto-generated method stub
1351
1352     }
1353
1354     public void mouseExited(MouseEvent e)
1355     {
1356       // TODO Auto-generated method stub
1357
1358     }
1359
1360   }
1361
1362   private OptionBox addOption(OptionI opt)
1363   {
1364     OptionBox cb = optSet.get(opt.getName());
1365     if (cb == null)
1366     {
1367       cb = new OptionBox(opt);
1368       optSet.put(opt.getName(), cb);
1369       jobOptions.add(cb);
1370     }
1371     return cb;
1372   }
1373
1374   public static void showUrlPopUp(JComponent invoker, final String finfo,
1375           int x, int y)
1376   {
1377
1378     JPopupMenu mnu = new JPopupMenu();
1379     JMenuItem mitem = new JMenuItem("View " + finfo);
1380     mitem.addActionListener(new ActionListener()
1381     {
1382
1383       @Override
1384       public void actionPerformed(ActionEvent e)
1385       {
1386         Desktop.showUrl(finfo);
1387
1388       }
1389     });
1390     mnu.add(mitem);
1391     mnu.show(invoker, x, y);
1392   }
1393
1394   protected void refreshParamLayout()
1395   {
1396     FlowLayout fl = new FlowLayout();
1397     paramList.setLayout(fl);
1398     int s = 2 * fl.getVgap();
1399     for (ParamBox pbox : paramSet.values())
1400     {
1401       s += fl.getVgap() + pbox.getBoxHeight(); // getBoxHeight();
1402     }
1403     paramList.setPreferredSize(new Dimension(PARAM_WIDTH, s));
1404     validate();
1405   }
1406
1407   /**
1408    * testing method - grab a service and parameter set and show the window
1409    * 
1410    * @param args
1411    */
1412   public static void main(String[] args)
1413   {
1414     jalview.ws.jws2.Jws2Discoverer disc = jalview.ws.jws2.Jws2Discoverer
1415             .getDiscoverer();
1416     int p = 0;
1417     if (args.length > 3)
1418     {
1419       Vector<String> services = new Vector<String>();
1420       services.addElement(args[p++]);
1421       Jws2Discoverer.setServiceUrls(services);
1422     }
1423     try
1424     {
1425       disc.run();
1426     } catch (Exception e)
1427     {
1428       System.err.println("Aborting. Problem discovering services.");
1429       e.printStackTrace();
1430       return;
1431     }
1432     Jws2Discoverer.Jws2Instance lastserv = null;
1433     for (Jws2Discoverer.Jws2Instance service : disc.getServices())
1434     {
1435       lastserv = service;
1436       if (p >= args.length || service.serviceType.equalsIgnoreCase(args[p]))
1437       {
1438         if (lastserv != null)
1439         {
1440           List<Preset> prl = null;
1441           Preset pr = null;
1442           if (++p < args.length)
1443           {
1444             PresetManager prman = lastserv.getPresets();
1445             if (prman != null)
1446             {
1447               pr = prman.getPresetByName(args[p]);
1448               if (pr == null)
1449               {
1450                 // just grab the last preset.
1451                 prl = prman.getPresets();
1452               }
1453             }
1454           }
1455           else
1456           {
1457             PresetManager prman = lastserv.getPresets();
1458             if (prman != null)
1459             {
1460               prl = prman.getPresets();
1461             }
1462           }
1463           Iterator<Preset> en = (prl == null) ? null : prl.iterator();
1464           while (en != null && en.hasNext())
1465           {
1466             if (en != null)
1467             {
1468               if (!en.hasNext())
1469               {
1470                 en = prl.iterator();
1471               }
1472               pr = en.next();
1473             }
1474             {
1475               System.out.println("Testing opts dupes for "
1476                       + lastserv.getUri() + " : "
1477                       + lastserv.getActionText() + ":" + pr.getName());
1478               List<Option> rg = lastserv.getRunnerConfig().getOptions();
1479               for (Option o : rg)
1480               {
1481                 try
1482                 {
1483                   Option cpy = jalview.ws.jws2.ParameterUtils.copyOption(o);
1484                 } catch (Exception e)
1485                 {
1486                   System.err.println("Failed to copy " + o.getName());
1487                   e.printStackTrace();
1488                 } catch (Error e)
1489                 {
1490                   System.err.println("Failed to copy " + o.getName());
1491                   e.printStackTrace();
1492                 }
1493               }
1494             }
1495             {
1496               System.out.println("Testing param dupes:");
1497               List<Parameter> rg = lastserv.getRunnerConfig()
1498                       .getParameters();
1499               for (Parameter o : rg)
1500               {
1501                 try
1502                 {
1503                   Parameter cpy = jalview.ws.jws2.ParameterUtils
1504                           .copyParameter(o);
1505                 } catch (Exception e)
1506                 {
1507                   System.err.println("Failed to copy " + o.getName());
1508                   e.printStackTrace();
1509                 } catch (Error e)
1510                 {
1511                   System.err.println("Failed to copy " + o.getName());
1512                   e.printStackTrace();
1513                 }
1514               }
1515             }
1516             {
1517               System.out.println("Testing param write:");
1518               List<String> writeparam = null, readparam = null;
1519               try
1520               {
1521                 writeparam = jalview.ws.jws2.ParameterUtils
1522                         .writeParameterSet(
1523                                 pr.getArguments(lastserv.getRunnerConfig()),
1524                                 " ");
1525                 System.out.println("Testing param read :");
1526                 List<Option> pset = jalview.ws.jws2.ParameterUtils
1527                         .processParameters(writeparam,
1528                                 lastserv.getRunnerConfig(), " ");
1529                 readparam = jalview.ws.jws2.ParameterUtils
1530                         .writeParameterSet(pset, " ");
1531                 Iterator<String> o = pr.getOptions().iterator(), s = writeparam
1532                         .iterator(), t = readparam.iterator();
1533                 boolean failed = false;
1534                 while (s.hasNext() && t.hasNext())
1535                 {
1536                   String on = o.next(), sn = s.next(), st = t.next();
1537                   if (!sn.equals(st))
1538                   {
1539                     System.out.println("Original was " + on
1540                             + " Phase 1 wrote " + sn + "\tPhase 2 wrote "
1541                             + st);
1542                     failed = true;
1543                   }
1544                 }
1545                 if (failed)
1546                 {
1547                   System.out.println("Original parameters:\n"
1548                           + pr.getOptions());
1549                   System.out.println("Wrote parameters in first set:\n"
1550                           + writeparam);
1551                   System.out.println("Wrote parameters in second set:\n"
1552                           + readparam);
1553
1554                 }
1555               } catch (Exception e)
1556               {
1557                 e.printStackTrace();
1558               }
1559             }
1560             WsJobParameters pgui = new WsJobParameters(lastserv,
1561                     new JabaPreset(lastserv, pr));
1562             JFrame jf = new JFrame("Parameters for "
1563                     + lastserv.getActionText());
1564             JPanel cont = new JPanel();
1565             // jf.setPreferredSize(new Dimension(600, 800));
1566             cont.add(pgui);
1567             jf.add(cont);
1568             final Thread thr = Thread.currentThread();
1569             jf.addWindowListener(new WindowListener()
1570             {
1571
1572               public void windowActivated(WindowEvent e)
1573               {
1574                 // TODO Auto-generated method stub
1575
1576               }
1577
1578               public void windowClosed(WindowEvent e)
1579               {
1580               }
1581
1582               public void windowClosing(WindowEvent e)
1583               {
1584                 thr.interrupt();
1585
1586               }
1587
1588               public void windowDeactivated(WindowEvent e)
1589               {
1590                 // TODO Auto-generated method stub
1591
1592               }
1593
1594               public void windowDeiconified(WindowEvent e)
1595               {
1596                 // TODO Auto-generated method stub
1597
1598               }
1599
1600               public void windowIconified(WindowEvent e)
1601               {
1602                 // TODO Auto-generated method stub
1603
1604               }
1605
1606               public void windowOpened(WindowEvent e)
1607               {
1608                 // TODO Auto-generated method stub
1609
1610               }
1611
1612             });
1613             jf.setVisible(true);
1614             boolean inter = false;
1615             while (!inter)
1616             {
1617               try
1618               {
1619                 Thread.sleep(10000);
1620               } catch (Exception e)
1621               {
1622                 inter = true;
1623               }
1624               ;
1625             }
1626             jf.dispose();
1627           }
1628         }
1629       }
1630     }
1631   }
1632
1633   public List<ArgumentI> getJobParams()
1634   {
1635     List<ArgumentI> argSet = new ArrayList<ArgumentI>();
1636     // recover options and parameters from GUI
1637     for (OptionBox opts : optSet.values())
1638     {
1639       OptionI opt = opts.getOptionIfEnabled();
1640       if (opt != null)
1641       {
1642         argSet.add(opt);
1643       }
1644     }
1645     for (ParamBox parambox : paramSet.values())
1646     {
1647       ParameterI parm = parambox.getParameter();
1648       if (parm != null)
1649       {
1650         argSet.add(parm);
1651       }
1652     }
1653
1654     return argSet;
1655   }
1656
1657   String lastParmSet = null;
1658
1659   /*
1660    * Hashtable<String, Object[]> editedParams = new Hashtable<String,
1661    * Object[]>();
1662    * 
1663    * store the given parameters in the user parameter set database.
1664    * 
1665    * @param storeSetName - lastParmSet
1666    * 
1667    * @param descr - setDescr.getText()
1668    * 
1669    * @param jobParams - getJobParams()
1670    * 
1671    * private void _storeUserPreset(String storeSetName, String descr,
1672    * List<ArgumentI> jobParams) { // this is a simple hash store. Object[] pset;
1673    * editedParams.put(storeSetName, pset = new Object[3]); pset[0] =
1674    * storeSetName; pset[1] = descr; pset[2] = jobParams; // writeParam("Saving "
1675    * + storeSetName + ": ", jobParams); }
1676    * 
1677    * private void writeParam(String nm, List<ArgumentI> params) { for (ArgumentI
1678    * p : params) { System.out.println(nm + ":" + System.identityHashCode(p) +
1679    * " Name: " + p.getName() + " Value: " + p.getDefaultValue()); } }
1680    * 
1681    * private Object[] _getUserPreset(String setName) { Object[] pset =
1682    * editedParams.get(setName); // if (pset != null) // writeParam("Retrieving "
1683    * + setName + ": ", (List<Argument>) pset[2]); return pset; }
1684    * 
1685    * * remove the given user preset from the preset stash
1686    * 
1687    * @param setName
1688    * 
1689    * private void _deleteUserPreset(String setName) {
1690    * editedParams.remove(setName); }
1691    */
1692
1693   private void syncSetNamesWithStore()
1694   {
1695     int n = 0;
1696     // remove any set names in the drop down menu that aren't either a reserved
1697     // setting, or a user defined or service preset.
1698     Vector items = new Vector();
1699     while (n < setName.getItemCount())
1700     {
1701       String item = (String) setName.getItemAt(n);
1702       if (!item.equals(SVC_DEF) && !paramStore.presetExists(item))
1703       {
1704         setName.removeItemAt(n);
1705       }
1706       else
1707       {
1708         items.addElement(item);
1709         n++;
1710       }
1711     }
1712     if (!items.contains(SVC_DEF))
1713     {
1714       setName.addItem(SVC_DEF);
1715     }
1716     for (WsParamSetI upn : paramStore.getPresets())
1717     {
1718       if (!items.contains(upn.getName()))
1719       {
1720         setName.addItem(upn.getName());
1721       }
1722     }
1723   }
1724
1725   /**
1726    * true if lastParmSet is a user preset
1727    */
1728   boolean isUserPreset = false;
1729
1730   private void reInitDialog(String nextPreset)
1731   {
1732     settingDialog = true;
1733     // updateTable(null,null); // first reset to defaults
1734     WsParamSetI pset = null;
1735     if (nextPreset != null && nextPreset.length() > 0)
1736     {
1737       pset = paramStore.getPreset(nextPreset);
1738     }
1739     if (pset != null)
1740     {
1741       if (pset.isModifiable())
1742       {
1743         isUserPreset = true;
1744         setDescr.setText(pset.getDescription());
1745         updateTable(null, pset.getArguments());
1746         lastParmSet = nextPreset;
1747       }
1748       else
1749       {
1750         isUserPreset = false;
1751         setDescr.setText("");
1752         // must be a default preset from service
1753         updateTable(pset, null);
1754         lastParmSet = nextPreset;
1755       }
1756     }
1757     else
1758     {
1759       isUserPreset = false;
1760       // Service defaults
1761       setDescr.setText("");
1762       updateTable(null, null);
1763       lastParmSet = SVC_DEF;
1764     }
1765
1766     initArgSetModified();
1767     syncSetNamesWithStore();
1768     setName.setSelectedItem(lastParmSet);
1769     validate();
1770     settingDialog = false;
1771
1772   }
1773
1774   String curSetName = null;
1775
1776   public void itemStateChanged(ItemEvent e)
1777   {
1778     if (e.getSource() == setName && e.getStateChange() == e.SELECTED)
1779     {
1780       final String setname = (String) setName.getSelectedItem();
1781       System.out.println("Item state changed for " + setname
1782               + " (handling ? " + !settingDialog + ")");
1783       if (settingDialog)
1784       {
1785         // ignore event
1786         return;
1787       }
1788       if (setname == null)
1789       {
1790         return;
1791       }
1792       javax.swing.SwingUtilities.invokeLater(new Runnable()
1793       {
1794         public void run()
1795         {
1796           doPreferenceComboStateChange(setname);
1797         }
1798       });
1799     }
1800   }
1801
1802   private void doPreferenceComboStateChange(String setname)
1803   {
1804     // user has selected a different item from combo-box
1805     if (isModified())
1806     {
1807       String lsetname = (curSetName != null) ? curSetName : lastParmSet;
1808       if (lsetname.equals(setname))
1809       {
1810         // setname was just edited - so ignore this event.
1811         return;
1812       }
1813       settingDialog = true;
1814       System.out.println("Prompting to save " + lsetname);
1815       if (javax.swing.JOptionPane
1816               .showConfirmDialog(
1817                       this,
1818                       "Parameter set '"
1819                               + lsetname
1820                               + "' is modifed, and your changes will be lost.\nReally change preset ?",
1821                       "Warning: Unsaved Changes",
1822                       javax.swing.JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION)
1823       {
1824         // revert the combobox to the current item
1825         settingDialog = true;
1826         setName.setSelectedItem(lsetname);
1827         settingDialog = false;
1828         // and leave.
1829         return;
1830         // System.out.println("Saving for " + lsetname);
1831         // _storeCurrentPreset(lsetname);
1832
1833       }
1834     }
1835     settingDialog = true;
1836     reInitDialog(setname);
1837     settingDialog = false;
1838
1839   }
1840
1841   private void _renameExistingPreset(String oldName, String curSetName2)
1842   {
1843     paramStore.updatePreset(oldName, curSetName2, setDescr.getText(),
1844             getJobParams());
1845   }
1846
1847   /**
1848    * store current settings as given name. You should then reset gui.
1849    * 
1850    * @param curSetName2
1851    */
1852   private void _storeCurrentPreset(String curSetName2)
1853   {
1854     paramStore.storePreset(curSetName2, setDescr.getText(), getJobParams());
1855   }
1856
1857   private void _updatePreset(String lastParmSet2, String curname)
1858   {
1859     paramStore.updatePreset(lastParmSet2, curname, setDescr.getText(),
1860             getJobParams());
1861
1862   }
1863
1864   /**
1865    * last saved name for this user preset
1866    */
1867   String lastSetName = null;
1868
1869   /**
1870    * last saved value of the description text for this user preset
1871    */
1872   String lastDescrText = null;
1873
1874   public void actionPerformed(ActionEvent e)
1875   {
1876     if (e.getSource() instanceof Component)
1877     {
1878       Component src = (Component) e.getSource();
1879       if (src.getParent() == setName)
1880       {
1881         // rename any existing records we know about for this set.
1882         String newname = (String) e.getActionCommand().trim();
1883         String msg = null;
1884         if (isServicePreset(newname))
1885         {
1886           final String oldname = curSetName!=null ? curSetName : lastParmSet;
1887           final Component ourframe=this;
1888           settingDialog=true;
1889           setName.getEditor().setItem(oldname);
1890           settingDialog=false;
1891           javax.swing.SwingUtilities.invokeLater(new Runnable() {public void run() {
1892             JOptionPane.showMessageDialog(ourframe, 
1893                     "Invalid name - preset already exists.", "Invalid name",
1894                     JOptionPane.WARNING_MESSAGE);
1895             }});
1896           
1897           return;
1898         }
1899         curSetName = newname;
1900         System.err.println("New name for user setting " + curSetName
1901                 + " (was " + setName.getSelectedItem() + ")");
1902         if (curSetName.equals(setName.getSelectedItem()))
1903         {
1904           curSetName = null;
1905         }
1906         if (curSetName != null)
1907         {
1908           argSetModified(setName, true);
1909           return;
1910         }
1911
1912       }
1913     }
1914   }
1915
1916   private void checkDescrModified()
1917   {
1918     if (!settingDialog)
1919     {
1920
1921       argSetModified(
1922               setDescr,
1923               (lastDescrText == null ? setDescr.getText().trim().length() > 0
1924                       : !setDescr.getText().equals(lastDescrText)));
1925
1926     }
1927   }
1928
1929   public void insertUpdate(DocumentEvent e)
1930   {
1931     checkDescrModified();
1932   }
1933
1934   public void removeUpdate(DocumentEvent e)
1935   {
1936     checkDescrModified();
1937   }
1938
1939   public void changedUpdate(DocumentEvent e)
1940   {
1941     checkDescrModified();
1942   }
1943
1944   /**
1945    * 
1946    * @return null or the service preset selected by the user
1947    */
1948   public WsParamSetI getPreset()
1949   {
1950     if (isUserPreset || isModified()
1951             || (lastParmSet != null && lastParmSet.equals(SVC_DEF)))
1952     {
1953       return null;
1954     }
1955     else
1956     {
1957       return paramStore.getPreset(lastParmSet);
1958     }
1959   }
1960 }