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