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