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