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