debug warning / option dialog box display
[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.JTable;
53 import javax.swing.JTextArea;
54 import javax.swing.JTextField;
55 import javax.swing.ListSelectionModel;
56 import javax.swing.SwingConstants;
57 import javax.swing.SwingUtilities;
58 import javax.swing.border.TitledBorder;
59 import javax.swing.event.CellEditorListener;
60 import javax.swing.event.ChangeEvent;
61 import javax.swing.event.ChangeListener;
62 import javax.swing.event.DocumentEvent;
63 import javax.swing.event.DocumentListener;
64 import javax.swing.table.*;
65
66 import compbio.metadata.Argument;
67 import compbio.metadata.Option;
68 import compbio.metadata.Parameter;
69 import compbio.metadata.Preset;
70 import compbio.metadata.PresetManager;
71 import compbio.metadata.RunnerConfig;
72 import compbio.metadata.ValueConstrain;
73 import compbio.metadata.WrongParameterException;
74 import compbio.metadata.ValueConstrain.Type;
75
76 import jalview.util.jarInputStreamProvider;
77 import jalview.ws.jws2.JabaParamStore;
78 import jalview.ws.jws2.JabaPreset;
79 import jalview.ws.jws2.Jws2Discoverer;
80 import jalview.ws.jws2.ParameterUtils;
81 import jalview.ws.jws2.Jws2Discoverer.Jws2Instance;
82 import jalview.ws.jws2.dm.JabaOption;
83 import jalview.ws.jws2.dm.JabaParameter;
84 import jalview.ws.params.ArgumentI;
85 import jalview.ws.params.OptionI;
86 import jalview.ws.params.ParamDatastoreI;
87 import jalview.ws.params.ParameterI;
88 import jalview.ws.params.ValueConstrainI;
89 import jalview.ws.params.WsParamSetI;
90
91 /**
92  * job parameter editing/browsing dialog box. User can browse existing settings
93  * (user + presets + Defaults), and any changes to parameters creates a modified
94  * user parameter set. LOGIC: If the parameter set is modified, and its name is
95  * a valid, non-existant user parameter set, then a save button is shown. If the
96  * parameter set is modified and its name is a valid, extant user parameter set,
97  * then an update button is shown. If user parameter set's name is edited, and
98  * old name exists as a writable user parameter set, then rename button is
99  * shown. If current parameter set is associated with a user defined parameter
100  * set, then : if set is modifed, a 'revert' button is shown. if set is not
101  * modified, a 'delete' button is shown.
102  * 
103  * @author JimP
104  * 
105  */
106 public class WsJobParameters extends JPanel implements ItemListener,
107         ActionListener, DocumentListener
108 {
109   private static final String SVC_DEF = "Defaults"; // this is the null
110                                                     // parameter set as shown to
111                                                     // user
112
113   private static final int PARAM_WIDTH = 340, PARAM_HEIGHT = 150,
114           PARAM_CLOSEDHEIGHT = 80;
115
116   private static final int OPTSET_HEIGHT = 30;
117
118   JPanel SetNamePanel = new JPanel();
119
120   JPanel setDetails = new JPanel();
121
122   JSplitPane settingsPanel = new JSplitPane();
123
124   JSplitPane jobPanel = new JSplitPane();
125
126   JPanel jobOptions = new JPanel();
127
128   JScrollPane jobOptionsPane = new JScrollPane();
129
130   JPanel jobParameters = new JPanel();
131
132   JButton createpref = new JButton();
133
134   JButton deletepref = new JButton();
135
136   JButton revertpref = new JButton();
137
138   JButton updatepref = new JButton();
139
140   JButton startjob = new JButton();
141
142   JButton canceljob = new JButton();
143
144   JComboBox setName = new JComboBox();
145
146   JTextArea setDescr = new JTextArea();
147
148   JScrollPane paramPane = new JScrollPane();
149
150   JPanel paramList = new JPanel();
151
152   RunnerConfig serviceOptions;
153
154   ParamDatastoreI paramStore;
155
156   WsJobParameters(Jws2Instance service)
157   {
158     this(service, null);
159   }
160
161   public WsJobParameters(Jws2Instance service, WsParamSetI preset)
162   {
163     this(null, service, preset, null);
164   }
165
166   /**
167    * 
168    * @param desktop
169    *          - if null, create new JFrame outside of desktop
170    * @param service
171    * @param preset
172    */
173   public WsJobParameters(JFrame parent, Jws2Instance service,
174           WsParamSetI preset, List<Argument> jobArgset)
175   {
176     this(parent, null, service, preset, jobArgset);
177   }
178
179   /**
180    * 
181    * @param parent
182    * @param paramStorei
183    * @param service
184    * @param preset
185    * @param jobArgset
186    */
187   public WsJobParameters(JFrame parent, ParamDatastoreI paramStorei,
188           Jws2Instance service, WsParamSetI preset, List<Argument> jobArgset)
189   {
190     super();
191     jbInit();
192     this.paramStore = paramStorei;
193     if (paramStore == null)
194     {
195       paramStore = service.getParamStore();
196     }
197     this.service = service;
198     // argSetModified(false);
199     // populate parameter table
200     initForService(service, preset, jobArgset);
201     // display in new JFrame attached to parent.
202     validate();
203   }
204
205   int response = -1;
206
207   JDialog frame = null;
208
209   /**
210    * shows a modal dialog containing the parameters.
211    * 
212    * @return
213    */
214   public boolean showRunDialog()
215   {
216
217     frame = new JDialog(Desktop.instance, true);
218
219     frame.setTitle("Edit parameters for " + service.getActionText());
220     Rectangle deskr = Desktop.instance.getBounds();
221     frame.setBounds(new Rectangle((int) (deskr.getCenterX() - 240),
222             (int) (deskr.getCenterY() - 250), 480, 500));
223     frame.setContentPane(this);
224     // should recover defaults from user prefs.
225     frame.validate();
226     settingsPanel.setDividerLocation(0.4);
227     jobPanel.setDividerLocation(0.3);
228     frame.setVisible(true);
229
230     if (response > 0)
231     {
232       return true;
233     }
234     return false;
235   }
236
237   protected JButton makeButton(String label, String tooltip,
238           ActionListener action)
239   {
240     JButton button = new JButton();
241     button.setText(label);
242     button.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
243     button.setForeground(Color.black);
244     button.setHorizontalAlignment(SwingConstants.CENTER);
245     button.setToolTipText(tooltip);
246     button.addActionListener(action);
247     return button;
248   }
249
250   private void jbInit()
251   {
252     updatepref = makeButton("Update", "Update the stored user preference",
253             new ActionListener()
254             {
255
256               public void actionPerformed(ActionEvent e)
257               {
258                 update_actionPerformed(e);
259               }
260             });
261     deletepref = makeButton("Delete", "Delete the user preference",
262             new ActionListener()
263             {
264
265               public void actionPerformed(ActionEvent e)
266               {
267                 delete_actionPerformed(e);
268               }
269             });
270     createpref = makeButton("Create", "Create a new preference",
271             new ActionListener()
272             {
273
274               public void actionPerformed(ActionEvent e)
275               {
276                 create_actionPerformed(e);
277               }
278             });
279     revertpref = makeButton("Revert",
280             "Undo all changes to the current set", new ActionListener()
281             {
282
283               public void actionPerformed(ActionEvent e)
284               {
285                 revert_actionPerformed(e);
286               }
287             });
288     startjob.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
289     startjob.setText("Start");
290     startjob.setToolTipText("Start Job");
291     startjob.addActionListener(new ActionListener()
292     {
293       public void actionPerformed(ActionEvent e)
294       {
295         startjob_actionPerformed(e);
296       }
297     });
298     canceljob.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
299     canceljob.setText("Cancel");
300     canceljob.setToolTipText("Cancel Job");
301     canceljob.addActionListener(new ActionListener()
302     {
303       public void actionPerformed(ActionEvent e)
304       {
305         canceljob_actionPerformed(e);
306       }
307     });
308
309     setDetails.setBorder(new TitledBorder("Details"));
310     setDetails.setLayout(new BorderLayout());
311     setDescr.setColumns(40);
312     setDescr.setWrapStyleWord(true);
313     setDescr.setLineWrap(true);
314     setDescr.setBackground(getBackground());
315     setDescr.setEditable(true);
316     setDescr.getDocument().addDocumentListener(this);
317     JScrollPane setDescrView = new JScrollPane();
318     // setDescrView.setPreferredSize(new Dimension(350, 200));
319     setDescrView.getViewport().setView(setDescr);
320     setName.setEditable(true);
321     setName.addItemListener(this);
322     setName.getEditor().addActionListener(this);
323     JPanel setNameInfo = new JPanel(new FlowLayout(FlowLayout.LEFT));
324     SetNamePanel.setLayout(new GridLayout(2, 1));
325     SetNamePanel.setMinimumSize(new Dimension(300, 40));
326     JLabel setNameLabel = new JLabel("Parameter set: ");
327     setNameLabel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
328     // setNameLabel.setHorizontalAlignment(FlowLayout.LEFT);
329     setNameInfo.add(setNameLabel);
330     setNameInfo.add(setName);
331     // initial button visibility
332     updatepref.setVisible(false);
333     deletepref.setVisible(false);
334     revertpref.setVisible(false);
335     createpref.setVisible(false);
336     JPanel setsavebuts = new JPanel();
337     setsavebuts.setLayout(new FlowLayout(FlowLayout.LEFT)); // GridLayout(1,2));
338     ((FlowLayout) setsavebuts.getLayout()).setHgap(10);
339     ((FlowLayout) setsavebuts.getLayout()).setVgap(0);
340     setsavebuts.add(deletepref);
341     setsavebuts.add(revertpref);
342     setsavebuts.add(createpref);
343     setsavebuts.add(updatepref);
344     setsavebuts.setSize(new Dimension(150, 20));
345     JPanel buttonArea = new JPanel(new GridLayout(1, 1));
346     buttonArea.add(setsavebuts);
347     SetNamePanel.add(setNameInfo);
348     SetNamePanel.add(buttonArea);
349     setDetails.add(setDescrView, BorderLayout.CENTER);
350     // setDetails.setPreferredSize(new Dimension(360, 100));
351     jobParameters.setBorder(new TitledBorder("Parameters"));
352     jobParameters.setLayout(new BorderLayout());
353     paramPane.setPreferredSize(new Dimension(360, 300));
354     paramPane.getVerticalScrollBar().setUnitIncrement(20);
355     // paramPanel.setPreferredSize(new Dimension(360, 300));
356     // TODO: relayout buttons nicely
357     paramPane.getViewport().setView(paramList);
358     jobParameters.add(paramPane, BorderLayout.CENTER);
359     JPanel jobOptionsPanel = new JPanel();
360     jobOptionsPanel.setLayout(new BorderLayout());
361     jobOptionsPanel.setBorder(new TitledBorder("Options"));
362     jobOptionsPane.getViewport().setView(jobOptions);
363     jobOptionsPanel.add(jobOptionsPane, BorderLayout.CENTER);
364     settingsPanel.setLeftComponent(jobOptionsPanel);
365     settingsPanel.setRightComponent(jobParameters);
366     settingsPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
367
368     setLayout(new BorderLayout());
369     // setPreferredSize(new Dimension(400, 600));
370     // setSize(new Dimension(400, 600));
371     jobPanel.setLeftComponent(setDetails);
372     jobPanel.setRightComponent(settingsPanel);
373     jobPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
374     add(SetNamePanel, BorderLayout.NORTH);
375     add(jobPanel, BorderLayout.CENTER);
376     JPanel dialogpanel = new JPanel();
377     dialogpanel.add(startjob);
378     dialogpanel.add(canceljob);
379     add(dialogpanel, BorderLayout.SOUTH);
380   }
381
382   protected void revert_actionPerformed(ActionEvent e)
383   {
384     reInitDialog(lastParmSet);
385
386   }
387
388   protected void update_actionPerformed(ActionEvent e)
389   {
390     if (isUserPreset)
391     {
392       String curname = ((String) setName.getSelectedItem()).trim();
393       _updatePreset(lastParmSet, curname);
394       lastParmSet = curname;
395       isUserPreset = true;
396       initArgSetModified();
397       syncSetNamesWithStore();
398     }
399   }
400
401   private void _deleteUserPreset(String lastParmSet2)
402   {
403     paramStore.deletePreset(lastParmSet2);
404   }
405
406   protected void delete_actionPerformed(ActionEvent e)
407   {
408     if (isUserPreset)
409     {
410       // delete current preset's saved entry
411       _deleteUserPreset(lastParmSet);
412     }
413     reInitDialog(null); // service default
414   }
415
416   protected void create_actionPerformed(ActionEvent e)
417   {
418     String curname = ((String) setName.getSelectedItem()).trim();
419     if (curname.length() > 0)
420     {
421       _storeCurrentPreset(curname);
422       lastParmSet = curname;
423       isUserPreset = true;
424       initArgSetModified();
425     }
426     else
427     {
428       // TODO: show warning
429       System.err.println("Invalid name. Not saved.");
430     }
431   }
432
433   protected void canceljob_actionPerformed(ActionEvent e)
434   {
435     response = 0;
436     if (frame != null)
437     {
438       frame.setVisible(false);
439     }
440   }
441
442   protected void startjob_actionPerformed(ActionEvent e)
443   {
444     response = 1;
445     if (frame != null)
446     {
447       frame.setVisible(false);
448     }
449   }
450
451   Jws2Instance service;
452
453   /**
454    * list of service presets in the gui
455    */
456   Hashtable servicePresets = null;
457
458   /**
459    * set if dialog is being set - so handlers will avoid spurious events
460    */
461   boolean settingDialog = false;
462
463   void initForService(Jws2Instance service, WsParamSetI jabap,
464           List<Argument> jabajobArgset)
465   {
466     WsParamSetI p = null;
467     List<ArgumentI> jobArgset = null;
468     settingDialog = true;
469     { // instantiate the abstract proxy for Jaba objects
470       jobArgset = jabajobArgset == null ? null : JabaParamStore
471               .getJwsArgsfromJaba(jabajobArgset);
472       p = jabap; // (jabap != null) ? paramStore.getPreset(jabap.getName()) :
473                  // null;
474     }
475     // TODO: Recover window geometry prefs for this service
476     // jobPanel.setDividerLocation(proportionalLocation)
477     // settingsPanel.setDividerLocation(proportionalLocation)
478     Hashtable exnames = new Hashtable();
479     for (int i = 0, iSize = setName.getItemCount(); i < iSize; i++)
480     {
481       exnames.put((String) setName.getItemAt(i), setName.getItemAt(i));
482     }
483     servicePresets = new Hashtable();
484     // Add the default entry - if not present already.
485     if (!exnames.contains(SVC_DEF))
486     {
487       setName.addItem(SVC_DEF);
488       exnames.put(SVC_DEF, SVC_DEF);
489       servicePresets.put(SVC_DEF, SVC_DEF);
490     }
491     String curname = (p == null ? "" : p.getName());
492     for (WsParamSetI pr : paramStore.getPresets())
493     {
494       if (!pr.isModifiable())
495       {
496         servicePresets.put(pr.getName(), "preset");
497       }
498       else
499       {
500       }
501       if (!exnames.contains(pr.getName()))
502       {
503         setName.addItem(pr.getName());
504       }
505     }
506     // TODO: if initial jobArgset matches a given user setting or preset then
507     // should recover setting accordingly
508     // updateTable(p, jobArgset);
509     if (p != null)
510     {
511       reInitDialog(p.getName());
512       initArgSetModified();
513     }
514     else
515     {
516       if (jobArgset != null && jobArgset.size() > 0)
517       {
518         curSetName = "Supplied Settings";
519         updateTable(p, jobArgset);
520       }
521       else
522       {
523         curSetName = null;
524         reInitDialog(null);
525       }
526     }
527     settingDialog = false;
528
529   }
530
531   @SuppressWarnings("unchecked")
532   private void updateTable(WsParamSetI p, List<ArgumentI> jobArgset)
533   {
534     // populate table from default parameter set.
535     List<ArgumentI> args = paramStore.getServiceParameters();
536
537     // split to params and required arguments
538     {
539       for (ArgumentI myarg : args)
540       {
541         // Ideally, Argument would implement isRequired !
542         if (myarg instanceof ParameterI)
543         {
544           ParameterI parm = (ParameterI) myarg;
545           addParameter(parm);
546         }
547         else
548         {
549           if (myarg instanceof OptionI)
550           {
551             OptionI opt = (OptionI) myarg;
552             addOption(opt).resetToDefault();
553           }
554           else
555           {
556             System.err.println("Ignoring unknown service argument type "
557                     + myarg.getClass().getName());
558           }
559         }
560       }
561       args = null; // no more args to process.
562     }
563     if (p != null)
564     {
565       isUserPreset = false;
566       // initialise setname
567       setName.setSelectedItem(lastSetName = p.getName());
568       setDescr.setText(lastDescrText = p.getDescription());
569       // TODO - URL link
570       try
571       {
572         args = p.getArguments();
573       } catch (Exception e)
574       {
575         e.printStackTrace();
576       }
577       // TODO: check if args should be unselected prior to resetting using the
578       // preset
579     }
580     else
581     {
582       if (lastParmSet == null)
583       {
584         isUserPreset = false;
585         // first call - so create a dummy name
586
587         setName.setSelectedItem(lastSetName = SVC_DEF);
588       }
589     }
590
591     if (jobArgset != null)
592     {
593       argSetModified(jobArgset, true);
594       args = jobArgset;
595     }
596     // get setargs from current object
597     if (args != null)
598     {
599       for (ArgumentI arg : args)
600       {
601         if (arg instanceof ParameterI)
602         {
603           setParameter((ParameterI) arg);
604         }
605         else
606         {
607           if (arg instanceof OptionI)
608           {
609             // System.out.println("Setting option "
610             // + System.identityHashCode(arg) + ":" + arg.getName()
611             // + " with " + arg.getDefaultValue());
612             selectOption((OptionI) arg, arg.getDefaultValue());
613           }
614         }
615
616       }
617     }
618
619     jobOptions.setPreferredSize(new Dimension(PARAM_WIDTH, optSet.size()
620             * OPTSET_HEIGHT));
621     jobOptions.setLayout(new GridLayout(optSet.size(), 1));
622     refreshParamLayout();
623     paramPane.validate();
624     revalidate();
625   }
626
627   private boolean isModified()
628   {
629     return modifiedElements.size() > 0;
630   }
631
632   private Hashtable modifiedElements = new Hashtable();
633
634   /**
635    * reset gui and modification state settings
636    */
637   private void initArgSetModified()
638   {
639     curSetName = null;
640     modifiedElements.clear();
641     updateButtonDisplay();
642   }
643
644   private void updateButtonDisplay()
645   {
646     boolean _update = false, _create = false, _delete = false, _revert = false;
647     if (modifiedElements.size() > 0)
648     {
649       // set modified
650       _revert = true;
651       _update = isUserPreset; // can only update user presets
652       if (!isUserPreset || modifiedElements.containsKey(setName))
653       {
654         // name modified - can create new preset
655         _create = true;
656       }
657     }
658     else
659     {
660       // set unmodified
661     }
662     // can still delete a user preset
663     _delete = isUserPreset;
664
665     createpref.setVisible(_create);
666     updatepref.setVisible(_update);
667     deletepref.setVisible(_delete);
668     revertpref.setVisible(_revert);
669     validate();
670   }
671
672   private void argSetModified(Object modifiedElement, boolean b)
673   {
674     if (settingDialog)
675     {
676       return;
677     }
678     if (!b)
679     {
680       modifiedElements.remove(modifiedElement);
681     }
682     else
683     {
684       if (b && modifiedElement == setName
685               && modifiedElements.contains(modifiedElement))
686       {
687         // HACK! prevents iteration on makeSetNameValid
688         b = false;
689       }
690       modifiedElements.put(modifiedElement, modifiedElement);
691     }
692     // set mod status based on presence of elements in table
693     if (b && modifiedElements.size() > 0)
694     {
695       makeSetNameValid(!isUserPreset);
696       SetNamePanel.revalidate();
697     }
698     updateButtonDisplay();
699   }
700
701   private boolean isServicePreset(String selectedItem)
702   {
703     return selectedItem.equals(SVC_DEF)
704             || servicePresets.containsKey(selectedItem);
705   }
706
707   /**
708    * check if the current set name is a valid set name for saving, if not, then
709    * fix it.
710    */
711   private void makeSetNameValid(boolean newuserset)
712   {
713     boolean stn = settingDialog;
714     boolean renamed = false;
715     settingDialog = true;
716     String nm = (curSetName != null ? curSetName : (String) setName
717             .getSelectedItem());
718     // check if the name is reserved - if it is, rename it.
719     if (isServicePreset(nm))
720     {
721       nm = "User " + nm;
722       renamed = true;
723     }
724     String tnm = nm;
725     if (newuserset)
726     {
727       int i = 0;
728       while (paramStore.getPreset(tnm) != null)
729       {
730         tnm = nm + " (" + (++i) + ")";
731         renamed = true;
732       }
733       if (i > 0)
734       {
735         nm = tnm;
736       }
737     }
738
739     boolean makeupdate = false;
740     // sync the gui with the preset database
741     for (int i = 0, iS = setName.getItemCount(); i < iS; i++)
742     {
743       String snm = (String) setName.getItemAt(i);
744       if (snm.equals(nm))
745       {
746         makeupdate = true;
747         // setName.setSelectedIndex(i);
748       }
749     }
750     if (!makeupdate)
751     {
752       setName.addItem(curSetName = nm);
753       setName.setSelectedItem(curSetName);
754     }
755     if (renamed)
756     {
757       settingDialog = false; // we need this name change to be registered.
758       argSetModified(setName, renamed);
759     }
760     settingDialog = stn;
761   }
762
763   private void addParameter(ParameterI arg)
764   {
765     ParamBox pb = paramSet.get(arg.getName());
766     if (pb == null)
767     {
768       pb = new ParamBox(this, arg);
769       paramSet.put(arg.getName(), pb);
770       paramList.add(pb);
771     }
772     pb.init();
773     // take the defaults from the parameter
774     pb.updateControls(arg);
775   }
776
777   private void setParameter(ParameterI arg)
778   {
779     ParamBox pb = paramSet.get(arg.getName());
780     if (pb == null)
781     {
782       addParameter(arg);
783     }
784     else
785     {
786       pb.updateControls(arg);
787     }
788
789   }
790
791   private void selectOption(OptionI option, String string)
792   {
793     OptionBox cb = optSet.get(option.getName());
794     if (cb == null)
795     {
796       cb = addOption(option);
797     }
798     cb.enabled.setSelected(string != null); // initial state for an option.
799     if (string != null)
800     {
801       if (option.getPossibleValues().contains(string))
802       {
803         cb.val.setSelectedItem(string);
804       }
805       else
806       {
807         throw new Error("Invalid value " + string + " for option " + option);
808       }
809
810     }
811     if (option.isRequired() && !cb.enabled.isSelected())
812     {
813       // TODO: indicate paramset is not valid.. option needs to be selected!
814     }
815     cb.setInitialValue();
816   }
817
818   Map<String, ParamBox> paramSet = new Hashtable<String, ParamBox>();
819
820   public class ParamBox extends JPanel implements ChangeListener,
821           ActionListener, MouseListener
822   {
823     JButton showDesc = new JButton();
824
825     JTextArea string = new JTextArea();
826
827     JScrollPane descPanel = new JScrollPane();
828
829     JSlider slider = null;
830
831     JTextField valueField = null;
832
833     ValueConstrainI validator = null;
834
835     JPanel settingPanel = new JPanel();
836
837     JPanel controlPanel = new JPanel();
838
839     boolean integ = false;
840
841     boolean choice = false;
842
843     boolean descisvisible = false;
844
845     final WsJobParameters pmdialogbox;
846
847     final URL finfo;
848
849     public ParamBox(final WsJobParameters pmlayout, ParameterI parm)
850     {
851       pmdialogbox = pmlayout;
852       setPreferredSize(new Dimension(PARAM_WIDTH, PARAM_CLOSEDHEIGHT));
853       setBorder(new TitledBorder(parm.getName()));
854       setLayout(null);
855       showDesc.setFont(new Font("Verdana", Font.PLAIN, 6));
856       showDesc.setText("+");
857       string.setFont(new Font("Verdana", Font.PLAIN, 11));
858       string.setBackground(getBackground());
859       // string.setSize(new Dimension(PARAM_WIDTH, 80));
860       string.setEditable(false);
861       descPanel.getViewport().setView(string);
862       // descPanel.setLocation(2,17);
863       descPanel.setVisible(false);
864       // string.setMinimumSize(new Dimension(140,80));
865       // string.setMaximumSize(new Dimension(280,80));
866       final ParamBox me = this;
867       finfo = parm.getFurtherDetails();
868       if (finfo != null)
869       {
870         showDesc.setToolTipText("<html><p>Click to show brief description, and right click to open link for further information.</p></html>");
871         showDesc.addMouseListener(this);
872       }
873       else
874       {
875         showDesc.setToolTipText("<html><p>Click to show brief description.</p></html>");
876       }
877       showDesc.addActionListener(new ActionListener()
878       {
879
880         public void actionPerformed(ActionEvent e)
881         {
882           descisvisible = !descisvisible;
883           descPanel.setVisible(descisvisible);
884           me.setPreferredSize(new Dimension(PARAM_WIDTH,
885                   (descisvisible) ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT));
886           me.validate();
887           pmlayout.refreshParamLayout();
888         }
889       });
890       string.setWrapStyleWord(true);
891       string.setLineWrap(true);
892       string.setColumns(32);
893       string.setText(parm.getDescription());
894       JPanel firstrow = new JPanel();
895       firstrow.setLayout(null);
896       controlPanel.setLayout(new BorderLayout());
897       controlPanel.setBounds(new Rectangle(39, 10, PARAM_WIDTH - 70,
898               PARAM_CLOSEDHEIGHT - 50));
899       showDesc.setBounds(new Rectangle(10, 10, 16, 16));
900       firstrow.add(showDesc);
901       firstrow.add(controlPanel);
902       firstrow.setBounds(new Rectangle(10, 20, PARAM_WIDTH - 30,
903               PARAM_CLOSEDHEIGHT - 30));
904       add(firstrow);
905       validator = parm.getValidValue();
906       parameter = parm;
907       if (validator != null)
908       {
909         integ = validator.getType() == Type.Integer;
910       }
911       else
912       {
913         if (parameter.getPossibleValues() != null)
914         {
915           choice = true;
916         }
917       }
918       updateControls(parm);
919       descPanel.setBounds(new Rectangle(10, PARAM_CLOSEDHEIGHT,
920               PARAM_WIDTH - 20, PARAM_HEIGHT - PARAM_CLOSEDHEIGHT - 5));
921       add(descPanel);
922       validate();
923     }
924
925     public void init()
926     {
927       // reset the widget's initial value.
928       lastVal = null;
929     }
930
931     boolean adjusting = false;
932
933     ParameterI parameter;
934
935     JComboBox choicebox;
936
937     public int getBoxHeight()
938     {
939       return (descisvisible ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT);
940     }
941
942     public void updateControls(ParameterI parm)
943     {
944       adjusting = true;
945       boolean init = (choicebox == null && valueField == null);
946       float fVal = 0f;
947       int iVal = 0;
948       if (init)
949       {
950         if (choice)
951         {
952           choicebox = new JComboBox();
953           choicebox.addActionListener(this);
954           controlPanel.add(choicebox, BorderLayout.CENTER);
955         }
956         else
957         {
958           slider = new JSlider();
959           slider.addChangeListener(this);
960           valueField = new JTextField();
961           valueField.addActionListener(this);
962           valueField.setPreferredSize(new Dimension(60, 25));
963           controlPanel.add(slider, BorderLayout.WEST);
964           controlPanel.add(valueField, BorderLayout.EAST);
965
966         }
967       }
968
969       if (parm != null)
970       {
971         if (choice)
972         {
973           if (init)
974           {
975             List vals = parm.getPossibleValues();
976             for (Object val : vals)
977             {
978               choicebox.addItem(val);
979             }
980           }
981
982           if (parm.getDefaultValue() != null)
983           {
984             choicebox.setSelectedItem(parm.getDefaultValue());
985           }
986         }
987         else
988         {
989           valueField.setText(parm.getDefaultValue());
990         }
991       }
992       lastVal = updateSliderFromValueField();
993       adjusting = false;
994     }
995
996     Object lastVal;
997
998     public ParameterI getParameter()
999     {
1000       ParameterI prm = parameter.copy();
1001       if (choice)
1002       {
1003         prm.setDefaultValue((String) choicebox.getSelectedItem());
1004       }
1005       else
1006       {
1007         prm.setDefaultValue(valueField.getText());
1008       }
1009       return prm;
1010     }
1011
1012     public Object updateSliderFromValueField()
1013     {
1014       int iVal;
1015       float fVal;
1016       if (validator != null)
1017       {
1018         if (integ)
1019         {
1020           iVal = 0;
1021           try
1022           {
1023             valueField.setText(valueField.getText().trim());
1024             iVal = Integer.valueOf(valueField.getText());
1025             if (validator.getMin() != null
1026                     && validator.getMin().intValue() > iVal)
1027             {
1028               iVal = validator.getMin().intValue();
1029               // TODO: provide visual indication that hard limit was reached for
1030               // this parameter
1031             }
1032             if (validator.getMax() != null
1033                     && validator.getMax().intValue() < iVal)
1034             {
1035               iVal = validator.getMax().intValue();
1036               // TODO: provide visual indication that hard limit was reached for
1037               // this parameter
1038             }
1039           } catch (Exception e)
1040           {
1041           }
1042           ;
1043           if (validator.getMin() != null && validator.getMax() != null)
1044           {
1045             slider.getModel().setRangeProperties(iVal, 1,
1046                     validator.getMin().intValue(),
1047                     validator.getMax().intValue(), true);
1048           }
1049           else
1050           {
1051             slider.setVisible(false);
1052           }
1053           return new int[]
1054           { iVal };
1055         }
1056         else
1057         {
1058           fVal = 0f;
1059           try
1060           {
1061             fVal = Float.valueOf(valueField.getText());
1062             if (validator.getMin() != null
1063                     && validator.getMin().floatValue() > fVal)
1064             {
1065               fVal = validator.getMin().floatValue();
1066               // TODO: provide visual indication that hard limit was reached for
1067               // this parameter
1068             }
1069             if (validator.getMax() != null
1070                     && validator.getMax().floatValue() < fVal)
1071             {
1072               fVal = validator.getMax().floatValue();
1073               // TODO: provide visual indication that hard limit was reached for
1074               // this parameter
1075             }
1076           } catch (Exception e)
1077           {
1078           }
1079           ;
1080           if (validator.getMin() != null && validator.getMax() != null)
1081           {
1082             slider.getModel().setRangeProperties((int) fVal * 1000, 1,
1083                     (int) validator.getMin().floatValue() * 1000,
1084                     (int) validator.getMax().floatValue() * 1000, true);
1085           }
1086           else
1087           {
1088             slider.setVisible(false);
1089           }
1090           return new float[]
1091           { fVal };
1092         }
1093       }
1094       else
1095       {
1096         if (!choice)
1097         {
1098           slider.setVisible(false);
1099           return new String[]
1100           { valueField.getText().trim() };
1101         }
1102         else
1103         {
1104           return new String[]
1105           { (String) choicebox.getSelectedItem() };
1106         }
1107       }
1108
1109     }
1110
1111     public void stateChanged(ChangeEvent e)
1112     {
1113       if (!adjusting)
1114       {
1115         valueField.setText(""
1116                 + ((integ) ? ("" + (int) slider.getValue())
1117                         : ("" + (float) (slider.getValue() / 1000f))));
1118         checkIfModified();
1119       }
1120
1121     }
1122
1123     public void actionPerformed(ActionEvent e)
1124     {
1125       if (adjusting)
1126       {
1127         return;
1128       }
1129       if (!choice)
1130       {
1131         updateSliderFromValueField();
1132       }
1133       checkIfModified();
1134     }
1135
1136     private void checkIfModified()
1137     {
1138       Object cstate = updateSliderFromValueField();
1139       boolean notmod = false;
1140       if (cstate.getClass() == lastVal.getClass())
1141       {
1142         if (cstate instanceof int[])
1143         {
1144           notmod = (((int[]) cstate)[0] == ((int[]) lastVal)[0]);
1145         }
1146         else if (cstate instanceof float[])
1147         {
1148           notmod = (((float[]) cstate)[0] == ((float[]) lastVal)[0]);
1149         }
1150         else if (cstate instanceof String[])
1151         {
1152           notmod = (((String[]) cstate)[0].equals(((String[]) lastVal)[0]));
1153         }
1154       }
1155       pmdialogbox.argSetModified(this, !notmod);
1156     }
1157
1158     public void mouseClicked(MouseEvent e)
1159     {
1160       if (javax.swing.SwingUtilities.isRightMouseButton(e))
1161       {
1162         Desktop.showUrl(finfo.toString());
1163       }
1164     }
1165
1166     public void mousePressed(MouseEvent e)
1167     {
1168       // TODO Auto-generated method stub
1169
1170     }
1171
1172     public void mouseReleased(MouseEvent e)
1173     {
1174       // TODO Auto-generated method stub
1175
1176     }
1177
1178     public void mouseEntered(MouseEvent e)
1179     {
1180       // TODO Auto-generated method stub
1181
1182     }
1183
1184     public void mouseExited(MouseEvent e)
1185     {
1186       // TODO Auto-generated method stub
1187
1188     }
1189
1190   }
1191
1192   Map<String, OptionBox> optSet = new Hashtable<String, OptionBox>();
1193
1194   public class OptionBox extends JPanel implements MouseListener,
1195           ActionListener
1196   {
1197     JComboBox val = new JComboBox();
1198
1199     JCheckBox enabled = new JCheckBox();
1200
1201     JLabel optlabel = new JLabel();
1202
1203     URL linkImageURL = getClass().getResource("/images/link.gif");
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><p>" + opt.getDescription()
1226                 + "</p><img src=\"" + linkImageURL + "\"/></html>");
1227         // optlabel.addMouseListener(this);
1228         enabled.addMouseListener(this);
1229       }
1230       else
1231       {
1232         // optlabel.setToolTipText(opt.getDescription());
1233         enabled.setToolTipText(opt.getDescription());
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       updateTable(null, null);
1762       lastParmSet = SVC_DEF;
1763     }
1764
1765     initArgSetModified();
1766     syncSetNamesWithStore();
1767     setName.setSelectedItem(lastParmSet);
1768     validate();
1769     settingDialog = false;
1770
1771   }
1772
1773   String curSetName = null;
1774
1775   public void itemStateChanged(ItemEvent e)
1776   {
1777     if (e.getSource() == setName && e.getStateChange() == e.SELECTED)
1778     {
1779       final String setname = (String) setName.getSelectedItem();
1780       System.out.println("Item state changed for " + setname
1781               + " (handling ? " + !settingDialog + ")");
1782       if (settingDialog)
1783       {
1784         // ignore event
1785         return;
1786       }
1787       if (setname == null)
1788       {
1789         return;
1790       }
1791       javax.swing.SwingUtilities.invokeLater(new Runnable()
1792       {
1793         public void run()
1794         {
1795           doPreferenceComboStateChange(setname);
1796         }
1797       });
1798     }
1799   }
1800
1801   private void doPreferenceComboStateChange(String setname)
1802   {
1803     // user has selected a different item from combo-box
1804     if (isModified())
1805     {
1806       String lsetname = (curSetName != null) ? curSetName : lastParmSet;
1807       if (lsetname.equals(setname))
1808       {
1809         // setname was just edited - so ignore this event.
1810         return;
1811       }
1812       settingDialog = true;
1813       System.out.println("Prompting to save " + lsetname);
1814       if (javax.swing.JOptionPane
1815               .showConfirmDialog(
1816                       this,
1817                       "Parameter set '"
1818                               + lsetname
1819                               + "' is modifed, and your changes will be lost.\nReally change preset ?",
1820                       "Warning: Unsaved Changes",
1821                       javax.swing.JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION)
1822       {
1823         // revert the combobox to the current item
1824         settingDialog = true;
1825         setName.setSelectedItem(lsetname);
1826         settingDialog = false;
1827         // and leave.
1828         return;
1829         // System.out.println("Saving for " + lsetname);
1830         // _storeCurrentPreset(lsetname);
1831
1832       }
1833     }
1834     settingDialog = true;
1835     reInitDialog(setname);
1836     settingDialog = false;
1837
1838   }
1839
1840   private void _renameExistingPreset(String oldName, String curSetName2)
1841   {
1842     paramStore.updatePreset(oldName, curSetName2, setDescr.getText(),
1843             getJobParams());
1844   }
1845
1846   /**
1847    * store current settings as given name. You should then reset gui.
1848    * 
1849    * @param curSetName2
1850    */
1851   private void _storeCurrentPreset(String curSetName2)
1852   {
1853     paramStore.storePreset(curSetName2, setDescr.getText(), getJobParams());
1854   }
1855
1856   private void _updatePreset(String lastParmSet2, String curname)
1857   {
1858     paramStore.updatePreset(lastParmSet2, curname, setDescr.getText(),
1859             getJobParams());
1860
1861   }
1862
1863   /**
1864    * last saved name for this user preset
1865    */
1866   String lastSetName = null;
1867
1868   /**
1869    * last saved value of the description text for this user preset
1870    */
1871   String lastDescrText = null;
1872
1873   public void actionPerformed(ActionEvent e)
1874   {
1875     if (e.getSource() instanceof Component)
1876     {
1877       Component src = (Component) e.getSource();
1878       if (src.getParent() == setName)
1879       {
1880         // rename any existing records we know about for this set.
1881         String newname = (String) e.getActionCommand().trim();
1882         String msg = null;
1883         if (isServicePreset(newname))
1884         {
1885           final String oldname = curSetName!=null ? curSetName : lastParmSet;
1886           final Component ourframe=this;
1887           settingDialog=true;
1888           setName.getEditor().setItem(oldname);
1889           settingDialog=false;
1890           javax.swing.SwingUtilities.invokeLater(new Runnable() {public void run() {
1891             JOptionPane.showMessageDialog(ourframe, 
1892                     "Invalid name - preset already exists.", "Invalid name",
1893                     JOptionPane.WARNING_MESSAGE);
1894             }});
1895           
1896           return;
1897         }
1898         curSetName = newname;
1899         System.err.println("New name for user setting " + curSetName
1900                 + " (was " + setName.getSelectedItem() + ")");
1901         if (curSetName.equals(setName.getSelectedItem()))
1902         {
1903           curSetName = null;
1904         }
1905         if (curSetName != null)
1906         {
1907           argSetModified(setName, true);
1908           return;
1909         }
1910
1911       }
1912     }
1913   }
1914
1915   private void checkDescrModified()
1916   {
1917     if (!settingDialog)
1918     {
1919
1920       argSetModified(
1921               setDescr,
1922               (lastDescrText == null ? setDescr.getText().trim().length() > 0
1923                       : !setDescr.getText().equals(lastDescrText)));
1924
1925     }
1926   }
1927
1928   public void insertUpdate(DocumentEvent e)
1929   {
1930     checkDescrModified();
1931   }
1932
1933   public void removeUpdate(DocumentEvent e)
1934   {
1935     checkDescrModified();
1936   }
1937
1938   public void changedUpdate(DocumentEvent e)
1939   {
1940     checkDescrModified();
1941   }
1942
1943   /**
1944    * 
1945    * @return null or the service preset selected by the user
1946    */
1947   public WsParamSetI getPreset()
1948   {
1949     if (isUserPreset || isModified()
1950             || (lastParmSet != null && lastParmSet.equals(SVC_DEF)))
1951     {
1952       return null;
1953     }
1954     else
1955     {
1956       return paramStore.getPreset(lastParmSet);
1957     }
1958   }
1959 }