parameter set serialization/deserialization and preset/userdefined parameter set...
[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         }
1262         else
1263         {
1264           // compare against default service setting
1265           notmod &= option.getDefaultValue() == null
1266                   || option.getDefaultValue().equals(val.getSelectedItem());
1267         }
1268       }
1269       else
1270       {
1271         notmod &= initVal == null;
1272       }
1273       argSetModified(this, !notmod);
1274     }
1275
1276     public void mouseClicked(MouseEvent e)
1277     {
1278       if (javax.swing.SwingUtilities.isRightMouseButton(e))
1279       {
1280         showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
1281       }
1282     }
1283
1284     public void mousePressed(MouseEvent e)
1285     {
1286       // TODO Auto-generated method stub
1287
1288     }
1289
1290     public void mouseReleased(MouseEvent e)
1291     {
1292       // TODO Auto-generated method stub
1293
1294     }
1295
1296     public void mouseEntered(MouseEvent e)
1297     {
1298       // TODO Auto-generated method stub
1299
1300     }
1301
1302     public void mouseExited(MouseEvent e)
1303     {
1304       // TODO Auto-generated method stub
1305
1306     }
1307
1308   }
1309
1310   private OptionBox addOption(Option opt)
1311   {
1312     OptionBox cb = optSet.get(opt.getName());
1313     if (cb == null)
1314     {
1315       cb = new OptionBox(opt);
1316       optSet.put(opt.getName(), cb);
1317       jobOptions.add(cb);
1318     }
1319     return cb;
1320   }
1321
1322   public static void showUrlPopUp(JComponent invoker, final String finfo,
1323           int x, int y)
1324   {
1325
1326     JPopupMenu mnu = new JPopupMenu();
1327     JMenuItem mitem = new JMenuItem("View " + finfo);
1328     mitem.addActionListener(new ActionListener()
1329     {
1330
1331       @Override
1332       public void actionPerformed(ActionEvent e)
1333       {
1334         Desktop.showUrl(finfo);
1335
1336       }
1337     });
1338     mnu.add(mitem);
1339     mnu.show(invoker, x, y);
1340   }
1341
1342   protected void refreshParamLayout()
1343   {
1344     FlowLayout fl = new FlowLayout();
1345     paramList.setLayout(fl);
1346     int s = 2 * fl.getVgap();
1347     for (ParamBox pbox : paramSet.values())
1348     {
1349       s += fl.getVgap() + pbox.getBoxHeight(); // getBoxHeight();
1350     }
1351     paramList.setPreferredSize(new Dimension(PARAM_WIDTH, s));
1352     validate();
1353   }
1354
1355   /**
1356    * testing method - grab a service and parameter set and show the window
1357    * 
1358    * @param args
1359    */
1360   public static void main(String[] args)
1361   {
1362     jalview.ws.jws2.Jws2Discoverer disc = jalview.ws.jws2.Jws2Discoverer
1363             .getDiscoverer();
1364     int p = 0;
1365     if (args.length > 3)
1366     {
1367       Vector<String> services = new Vector<String>();
1368       services.addElement(args[p++]);
1369       Jws2Discoverer.setServiceUrls(services);
1370     }
1371     try
1372     {
1373       disc.run();
1374     } catch (Exception e)
1375     {
1376       System.err.println("Aborting. Problem discovering services.");
1377       e.printStackTrace();
1378       return;
1379     }
1380     Jws2Discoverer.Jws2Instance lastserv = null;
1381     for (Jws2Discoverer.Jws2Instance service : disc.getServices())
1382     {
1383       lastserv = service;
1384       if (p >= args.length || service.serviceType.equalsIgnoreCase(args[p]))
1385       {
1386         if (lastserv != null)
1387         {
1388           List<Preset> prl = null;
1389           Preset pr = null;
1390           if (++p < args.length)
1391           {
1392             PresetManager prman = lastserv.getPresets();
1393             if (prman != null)
1394             {
1395               pr = prman.getPresetByName(args[p]);
1396               if (pr == null)
1397               {
1398                 // just grab the last preset.
1399                 prl = prman.getPresets();
1400               }
1401             }
1402           }
1403           else
1404           {
1405             PresetManager prman = lastserv.getPresets();
1406             if (prman != null)
1407             {
1408               prl = prman.getPresets();
1409             }
1410           }
1411           Iterator<Preset> en = (prl == null) ? null : prl.iterator();
1412           while (en != null && en.hasNext())
1413           {
1414             if (en != null)
1415             {
1416               if (!en.hasNext())
1417               {
1418                 en = prl.iterator();
1419               }
1420               pr = en.next();
1421             }
1422             {
1423               System.out.println("Testing opts dupes for "
1424                       + lastserv.getHost() + " : "
1425                       + lastserv.getActionText() + ":" + pr.getName());
1426               List<Option> rg = lastserv.getRunnerConfig().getOptions();
1427               for (Option o : rg)
1428               {
1429                 try
1430                 {
1431                   Option cpy = jalview.ws.jws2.ParameterUtils.copyOption(o);
1432                 } catch (Exception e)
1433                 {
1434                   System.err.println("Failed to copy " + o.getName());
1435                   e.printStackTrace();
1436                 } catch (Error e)
1437                 {
1438                   System.err.println("Failed to copy " + o.getName());
1439                   e.printStackTrace();
1440                 }
1441               }
1442             }
1443             {
1444               System.out.println("Testing param dupes:");
1445               List<Parameter> rg = lastserv.getRunnerConfig()
1446                       .getParameters();
1447               for (Parameter o : rg)
1448               {
1449                 try
1450                 {
1451                   Parameter cpy = jalview.ws.jws2.ParameterUtils
1452                           .copyParameter(o);
1453                 } catch (Exception e)
1454                 {
1455                   System.err.println("Failed to copy " + o.getName());
1456                   e.printStackTrace();
1457                 } catch (Error e)
1458                 {
1459                   System.err.println("Failed to copy " + o.getName());
1460                   e.printStackTrace();
1461                 }
1462               }
1463             }
1464             {
1465               System.out.println("Testing param write:");
1466               List<String> writeparam = null, readparam = null;
1467               try
1468               {
1469                 writeparam = jalview.ws.jws2.ParameterUtils
1470                         .writeParameterSet(
1471                                 pr.getArguments(lastserv.getRunnerConfig()),
1472                                 " ");
1473                 System.out.println("Testing param read :");
1474                 List<Option> pset = jalview.ws.jws2.ParameterUtils
1475                         .processParameters(writeparam,
1476                                 lastserv.getRunnerConfig(), " ");
1477                 readparam = jalview.ws.jws2.ParameterUtils
1478                         .writeParameterSet(pset, " ");
1479                 Iterator<String> o=pr.getOptions().iterator(),s = writeparam.iterator(), t = readparam
1480                 .iterator();
1481                 boolean failed=false;
1482                 while (s.hasNext() && t.hasNext())
1483                 {
1484                   String on=o.next(),sn = s.next(),st=t.next();
1485                   if (!sn.equals(st))
1486                   {
1487                     System.out.println("Original was "+on+" Phase 1 wrote " + sn
1488                           + "\tPhase 2 wrote " + st);
1489                     failed=true;
1490                   }
1491                 }
1492                 if (failed)
1493                 {
1494                   System.out.println("Original parameters:\n"+pr.getOptions());
1495                   System.out.println("Wrote parameters in first set:\n"+writeparam);
1496                   System.out.println("Wrote parameters in second set:\n"+readparam);
1497
1498                 }
1499               } catch (Exception e)
1500               {
1501                 e.printStackTrace();
1502               }
1503             }
1504             WsJobParameters pgui = new WsJobParameters(lastserv, pr);
1505             JFrame jf = new JFrame("Parameters for "
1506                     + lastserv.getActionText());
1507             JPanel cont = new JPanel();
1508             // jf.setPreferredSize(new Dimension(600, 800));
1509             cont.add(pgui);
1510             jf.add(cont);
1511             final Thread thr = Thread.currentThread();
1512             jf.addWindowListener(new WindowListener()
1513             {
1514
1515               public void windowActivated(WindowEvent e)
1516               {
1517                 // TODO Auto-generated method stub
1518
1519               }
1520
1521               public void windowClosed(WindowEvent e)
1522               {
1523               }
1524
1525               public void windowClosing(WindowEvent e)
1526               {
1527                 thr.interrupt();
1528
1529               }
1530
1531               public void windowDeactivated(WindowEvent e)
1532               {
1533                 // TODO Auto-generated method stub
1534
1535               }
1536
1537               public void windowDeiconified(WindowEvent e)
1538               {
1539                 // TODO Auto-generated method stub
1540
1541               }
1542
1543               public void windowIconified(WindowEvent e)
1544               {
1545                 // TODO Auto-generated method stub
1546
1547               }
1548
1549               public void windowOpened(WindowEvent e)
1550               {
1551                 // TODO Auto-generated method stub
1552
1553               }
1554
1555             });
1556             jf.setVisible(true);
1557             boolean inter = false;
1558             while (!inter)
1559             {
1560               try
1561               {
1562                 Thread.sleep(10000);
1563               } catch (Exception e)
1564               {
1565                 inter = true;
1566               }
1567               ;
1568             }
1569             jf.dispose();
1570           }
1571         }
1572       }
1573     }
1574   }
1575
1576   public List<Argument> getJobParams()
1577   {
1578     List<Argument> argSet = new ArrayList<Argument>();
1579     // recover options and parameters from GUI
1580     for (OptionBox opts : optSet.values())
1581     {
1582       Option opt = opts.getOptionIfEnabled();
1583       if (opt != null)
1584       {
1585         argSet.add(opt);
1586       }
1587     }
1588     for (ParamBox parambox : paramSet.values())
1589     {
1590       Parameter parm = parambox.getParameter();
1591       if (parm != null)
1592       {
1593         argSet.add(parm);
1594       }
1595     }
1596
1597     return argSet;
1598   }
1599
1600   String lastParmSet = null;
1601
1602   Hashtable<String, Object[]> editedParams = new Hashtable<String, Object[]>();
1603
1604   /**
1605    * store the given parameters in the user parameter set database.
1606    * 
1607    * @param storeSetName
1608    *          - lastParmSet
1609    * @param descr
1610    *          - setDescr.getText()
1611    * @param jobParams
1612    *          - getJobParams()
1613    */
1614   private void _storeUserPreset(String storeSetName, String descr,
1615           List<Argument> jobParams)
1616   {
1617     // this is a simple hash store.
1618     Object[] pset;
1619     editedParams.put(storeSetName, pset = new Object[3]);
1620     pset[0] = storeSetName;
1621     pset[1] = descr;
1622     pset[2] = jobParams;
1623     // writeParam("Saving " + storeSetName + ": ", jobParams);
1624   }
1625
1626   private void writeParam(String nm, List<Argument> params)
1627   {
1628     for (Argument p : params)
1629     {
1630       System.out.println(nm + ":" + System.identityHashCode(p) + " Name: "
1631               + p.getName() + " Value: " + p.getDefaultValue());
1632     }
1633   }
1634
1635   private Object[] _getUserPreset(String setName)
1636   {
1637     Object[] pset = editedParams.get(setName);
1638     // if (pset != null)
1639     // writeParam("Retrieving " + setName + ": ", (List<Argument>) pset[2]);
1640     return pset;
1641   }
1642
1643   /**
1644    * remove the given user preset from the preset stash
1645    * 
1646    * @param setName
1647    */
1648   private void _deleteUserPreset(String setName)
1649   {
1650     editedParams.remove(setName);
1651   }
1652
1653   private void syncSetNamesWithStore()
1654   {
1655     int n = 0;
1656     // remove any set names in the drop down menu that aren't either a reserved
1657     // setting, or a user defined or service preset.
1658     Vector items = new Vector();
1659     while (n < setName.getItemCount())
1660     {
1661       String item = (String) setName.getItemAt(n);
1662       if (!isServicePreset(item) && _getUserPreset(item) == null)
1663       {
1664         setName.removeItemAt(n);
1665       }
1666       else
1667       {
1668         items.addElement(item);
1669         n++;
1670       }
1671     }
1672     for (String upn : editedParams.keySet())
1673     {
1674       if (!items.contains(upn))
1675       {
1676         setName.addItem(upn);
1677       }
1678     }
1679   }
1680
1681   /**
1682    * true if lastParmSet is a user preset
1683    */
1684   boolean isUserPreset = false;
1685
1686   private void reInitDialog(String nextPreset)
1687   {
1688     settingDialog = true;
1689     // updateTable(null,null); // first reset to defaults
1690     Object[] pset = null;
1691     if (nextPreset != null && nextPreset.length() > 0)
1692     {
1693       pset = _getUserPreset(nextPreset);
1694     }
1695     if (pset != null)
1696     {
1697       isUserPreset = true;
1698       setDescr.setText((String) pset[1]);
1699       updateTable(null, (List<Argument>) pset[2]);
1700       lastParmSet = nextPreset;
1701     }
1702     else
1703     {
1704       isUserPreset = false;
1705       setDescr.setText("");
1706       // must be a default preset from service
1707       Preset p = null;
1708       try
1709       {
1710         PresetManager prman = service.getPresets();
1711         if (prman != null)
1712         {
1713           isUserPreset = false;
1714           p = prman.getPresetByName(nextPreset);
1715         }
1716       } catch (Exception ex)
1717       {
1718         ex.printStackTrace();
1719       }
1720       if (p != null)
1721       {
1722         updateTable(p, null);
1723         lastParmSet = nextPreset;
1724       }
1725       else
1726       {
1727         updateTable(null, null);
1728         lastParmSet = SVC_DEF;
1729       }
1730     }
1731     initArgSetModified();
1732     syncSetNamesWithStore();
1733     setName.setSelectedItem(lastParmSet);
1734     validate();
1735     settingDialog = false;
1736
1737   }
1738
1739   String curSetName = null;
1740
1741   public void itemStateChanged(ItemEvent e)
1742   {
1743     if (e.getSource() == setName && e.getStateChange() == e.SELECTED)
1744     {
1745       String setname = (String) setName.getSelectedItem();
1746       System.out.println("Item state changed for " + setname
1747               + " (handling ? " + !settingDialog + ")");
1748       if (settingDialog)
1749       {
1750         // ignore event
1751         return;
1752       }
1753       if (setname == null)
1754       {
1755         return;
1756       }
1757       // user has selected a different item from combo-box
1758       if (isModified())
1759       {
1760         String lsetname = (curSetName != null) ? curSetName : lastParmSet;
1761         if (lsetname.equals(setname))
1762         {
1763           // setname was just edited - so ignore this event.
1764           return;
1765         }
1766         settingDialog = true;
1767         System.out.println("Prompting to save " + lsetname);
1768         if (javax.swing.JOptionPane.showConfirmDialog(this,
1769                 "Parameter set '" + lsetname + "' is modifed\nsave ?",
1770                 "Save changes ?", javax.swing.JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION)
1771         {
1772           System.out.println("Saving for " + lsetname);
1773           _storeCurrentPreset(lsetname);
1774
1775         }
1776       }
1777       settingDialog = true;
1778       reInitDialog(setname);
1779       settingDialog = false;
1780
1781     }
1782   }
1783
1784   /**
1785    * store current settings as given name. You should then reset gui.
1786    * 
1787    * @param curSetName2
1788    */
1789   private void _storeCurrentPreset(String curSetName2)
1790   {
1791     _storeUserPreset(curSetName2, setDescr.getText(), getJobParams());
1792   }
1793
1794   /**
1795    * last saved name for this user preset
1796    */
1797   String lastSetName = null;
1798
1799   /**
1800    * last saved value of the description text for this user preset
1801    */
1802   String lastDescrText = null;
1803
1804   public void actionPerformed(ActionEvent e)
1805   {
1806     if (e.getSource() instanceof Component)
1807     {
1808       Component src = (Component) e.getSource();
1809       if (src.getParent() == setName)
1810       {
1811         // rename any existing records we know about for this set.
1812         String newname = (String) e.getActionCommand().trim();
1813         String msg = null;
1814         if (isServicePreset(newname))
1815         {
1816           JOptionPane.showConfirmDialog(this,
1817                   "Invalid name - preset already exists.", "Invalid name",
1818                   JOptionPane.OK_OPTION);
1819           // reset name
1820           setName.setSelectedItem(curSetName);
1821           return;
1822         }
1823         curSetName = newname;
1824         System.err.println("New name for user setting " + curSetName
1825                 + " (was " + setName.getSelectedItem() + ")");
1826         if (curSetName.equals(setName.getSelectedItem()))
1827         {
1828           curSetName = null;
1829         }
1830         if (curSetName != null)
1831         {
1832           argSetModified(setName, true);
1833           return;
1834         }
1835
1836       }
1837     }
1838   }
1839
1840   private void checkDescrModified()
1841   {
1842     if (!settingDialog)
1843     {
1844
1845       argSetModified(
1846               setDescr,
1847               (lastDescrText == null ? setDescr.getText().trim().length() > 0
1848                       : !setDescr.getText().equals(lastDescrText)));
1849
1850     }
1851   }
1852
1853   public void insertUpdate(DocumentEvent e)
1854   {
1855     checkDescrModified();
1856   }
1857
1858   public void removeUpdate(DocumentEvent e)
1859   {
1860     checkDescrModified();
1861   }
1862
1863   public void changedUpdate(DocumentEvent e)
1864   {
1865     checkDescrModified();
1866   }
1867
1868   public Preset getPreset()
1869   {
1870     if (isUserPreset || isModified()
1871             || (lastParmSet != null && lastParmSet.equals(SVC_DEF)))
1872     {
1873       return null;
1874     }
1875     else
1876     {
1877       Preset p = null;
1878       try
1879       {
1880         return (Preset) service.getPresets().getPresetByName(lastParmSet);
1881       } catch (Exception e)
1882       {
1883         e.printStackTrace();
1884         return null;
1885       }
1886     }
1887   }
1888 }