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