JAL-2416 allow space in score matrix name
[jalview.git] / src / jalview / gui / WsJobParameters.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
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
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import jalview.gui.OptsAndParamsPage.OptionBox;
24 import jalview.gui.OptsAndParamsPage.ParamBox;
25 import jalview.util.MessageManager;
26 import jalview.ws.jws2.JabaParamStore;
27 import jalview.ws.jws2.JabaPreset;
28 import jalview.ws.jws2.Jws2Discoverer;
29 import jalview.ws.jws2.jabaws2.Jws2Instance;
30 import jalview.ws.params.ArgumentI;
31 import jalview.ws.params.OptionI;
32 import jalview.ws.params.ParamDatastoreI;
33 import jalview.ws.params.ParameterI;
34 import jalview.ws.params.WsParamSetI;
35
36 import java.awt.BorderLayout;
37 import java.awt.Component;
38 import java.awt.Dimension;
39 import java.awt.FlowLayout;
40 import java.awt.Font;
41 import java.awt.GridBagConstraints;
42 import java.awt.GridBagLayout;
43 import java.awt.GridLayout;
44 import java.awt.Rectangle;
45 import java.awt.event.ActionEvent;
46 import java.awt.event.ActionListener;
47 import java.awt.event.HierarchyBoundsListener;
48 import java.awt.event.HierarchyEvent;
49 import java.awt.event.ItemEvent;
50 import java.awt.event.ItemListener;
51 import java.awt.event.WindowEvent;
52 import java.awt.event.WindowListener;
53 import java.net.URL;
54 import java.util.Hashtable;
55 import java.util.Iterator;
56 import java.util.List;
57 import java.util.Vector;
58
59 import javax.swing.JButton;
60 import javax.swing.JComboBox;
61 import javax.swing.JDialog;
62 import javax.swing.JFrame;
63 import javax.swing.JLabel;
64 import javax.swing.JPanel;
65 import javax.swing.JScrollPane;
66 import javax.swing.JSplitPane;
67 import javax.swing.JTextArea;
68 import javax.swing.border.TitledBorder;
69 import javax.swing.event.DocumentEvent;
70 import javax.swing.event.DocumentListener;
71
72 import net.miginfocom.swing.MigLayout;
73
74 import compbio.metadata.Argument;
75 import compbio.metadata.Option;
76 import compbio.metadata.Parameter;
77 import compbio.metadata.Preset;
78 import compbio.metadata.PresetManager;
79 import compbio.metadata.RunnerConfig;
80
81 /**
82  * job parameter editing/browsing dialog box. User can browse existing settings
83  * (user + presets + Defaults), and any changes to parameters creates a modified
84  * user parameter set. LOGIC: If the parameter set is modified, and its name is
85  * a valid, non-existant user parameter set, then a save button is shown. If the
86  * parameter set is modified and its name is a valid, extant user parameter set,
87  * then an update button is shown. If user parameter set's name is edited, and
88  * old name exists as a writable user parameter set, then rename button is
89  * shown. If current parameter set is associated with a user defined parameter
90  * set, then : if set is modifed, a 'revert' button is shown. if set is not
91  * modified, a 'delete' button is shown.
92  * 
93  * @author JimP
94  * 
95  */
96 public class WsJobParameters extends JPanel implements ItemListener,
97         ActionListener, DocumentListener, OptsParametersContainerI
98 {
99   URL linkImageURL = getClass().getResource("/images/link.gif");
100
101   private static final String SVC_DEF = "Defaults"; // this is the null
102                                                     // parameter set as shown to
103                                                     // user
104
105   /**
106    * manager for options and parameters.
107    */
108   OptsAndParamsPage opanp = new OptsAndParamsPage(this);
109
110   /**
111    * panel containing job options
112    */
113   JPanel jobOptions = new JPanel();
114
115   /**
116    * panel containing job parameters
117    */
118   JPanel paramList = new JPanel();
119
120   JPanel SetNamePanel = new JPanel();
121
122   JPanel setDetails = new JPanel();
123
124   JSplitPane settingsPanel = new JSplitPane();
125
126   JPanel jobPanel = new JPanel();
127
128   JScrollPane jobOptionsPane = new JScrollPane();
129
130   JButton createpref = new JButton();
131
132   JButton deletepref = new JButton();
133
134   JButton revertpref = new JButton();
135
136   JButton updatepref = new JButton();
137
138   JButton startjob = new JButton();
139
140   JButton canceljob = new JButton();
141
142   JComboBox setName = new JComboBox();
143
144   JTextArea setDescr = new JTextArea();
145
146   JScrollPane paramPane = new JScrollPane();
147
148   // ScrollablePanel optsAndparams = new ScrollablePanel();
149   JPanel optsAndparams = new JPanel();
150
151   RunnerConfig serviceOptions;
152
153   ParamDatastoreI paramStore;
154
155   private int MAX_OPTWIDTH = 200;
156
157   WsJobParameters(Jws2Instance service)
158   {
159     this(service, null);
160   }
161
162   public WsJobParameters(Jws2Instance service, WsParamSetI preset)
163   {
164     this(null, service, preset, null);
165   }
166
167   /**
168    * 
169    * @param desktop
170    *          - if null, create new JFrame outside of desktop
171    * @param service
172    * @param preset
173    */
174   public WsJobParameters(JFrame parent, Jws2Instance service,
175           WsParamSetI preset, List<Argument> jobArgset)
176   {
177     this(parent, null, service, preset, jobArgset);
178   }
179
180   /**
181    * 
182    * @param parent
183    * @param paramStorei
184    * @param service
185    * @param preset
186    * @param jobArgset
187    */
188   public WsJobParameters(JFrame parent, ParamDatastoreI paramStorei,
189           Jws2Instance service, WsParamSetI preset, List<Argument> jobArgset)
190   {
191     super();
192     jbInit();
193     this.paramStore = paramStorei;
194     if (paramStore == null)
195     {
196       paramStore = service.getParamStore();
197     }
198     this.service = service;
199     // argSetModified(false);
200     // populate parameter table
201     initForService(service, preset, jobArgset);
202     // display in new JFrame attached to parent.
203     validate();
204   }
205
206   int response = -1;
207
208   JDialog frame = null;
209
210   /**
211    * shows a modal dialog containing the parameters.
212    * 
213    * @return
214    */
215   public boolean showRunDialog()
216   {
217
218     frame = new JDialog(Desktop.instance, true);
219
220     frame.setTitle(MessageManager.formatMessage("label.edit_params_for",
221             new String[] { service.getActionText() }));
222     Rectangle deskr = Desktop.instance.getBounds();
223     Dimension pref = this.getPreferredSize();
224     frame.setBounds(new Rectangle(
225             (int) (deskr.getCenterX() - pref.width / 2), (int) (deskr
226                     .getCenterY() - pref.height / 2), pref.width,
227             pref.height));
228     frame.setContentPane(this);
229
230     // should perhaps recover defaults from user prefs.
231
232     frame.validate();
233     javax.swing.SwingUtilities.invokeLater(new Runnable()
234     {
235       @Override
236       public void run()
237       {
238         // jobPanel.setDividerLocation(0.25);
239
240       }
241     });
242     frame.setVisible(true);
243
244     if (response > 0)
245     {
246       return true;
247     }
248     return false;
249   }
250
251   private void jbInit()
252   {
253     this.addHierarchyBoundsListener(new HierarchyBoundsListener()
254     {
255
256       @Override
257       public void ancestorResized(HierarchyEvent arg0)
258       {
259         refreshParamLayout();
260       }
261
262       @Override
263       public void ancestorMoved(HierarchyEvent arg0)
264       {
265         // TODO Auto-generated method stub
266
267       }
268     });
269     updatepref = JvSwingUtils.makeButton(
270             MessageManager.getString("action.update"),
271             MessageManager.getString("label.update_user_parameter_set"),
272             new ActionListener()
273             {
274
275               @Override
276               public void actionPerformed(ActionEvent e)
277               {
278                 update_actionPerformed(e);
279               }
280             });
281     deletepref = JvSwingUtils.makeButton(
282             MessageManager.getString("action.delete"),
283             MessageManager.getString("label.delete_user_parameter_set"),
284             new ActionListener()
285             {
286
287               @Override
288               public void actionPerformed(ActionEvent e)
289               {
290                 delete_actionPerformed(e);
291               }
292             });
293     createpref = JvSwingUtils.makeButton(
294             MessageManager.getString("action.create"),
295             MessageManager.getString("label.create_user_parameter_set"),
296             new ActionListener()
297             {
298
299               @Override
300               public void actionPerformed(ActionEvent e)
301               {
302                 create_actionPerformed(e);
303               }
304             });
305     revertpref = JvSwingUtils.makeButton(MessageManager
306             .getString("action.revert"), MessageManager
307             .getString("label.revert_changes_user_parameter_set"),
308             new ActionListener()
309             {
310
311               @Override
312               public void actionPerformed(ActionEvent e)
313               {
314                 revert_actionPerformed(e);
315               }
316             });
317     startjob = JvSwingUtils.makeButton(
318             MessageManager.getString("action.start_job"),
319             MessageManager.getString("label.start_job_current_settings"),
320             new ActionListener()
321             {
322               @Override
323               public void actionPerformed(ActionEvent e)
324               {
325                 startjob_actionPerformed(e);
326               }
327             });
328     canceljob = JvSwingUtils.makeButton(
329             MessageManager.getString("action.cancel_job"),
330             MessageManager.getString("label.cancel_job_close_dialog"),
331             new ActionListener()
332             {
333               @Override
334               public void actionPerformed(ActionEvent e)
335               {
336                 canceljob_actionPerformed(e);
337               }
338             });
339
340     setDetails.setBorder(new TitledBorder(MessageManager
341             .getString("label.details")));
342     setDetails.setLayout(new BorderLayout());
343     setDescr.setColumns(40);
344     setDescr.setWrapStyleWord(true);
345     setDescr.setLineWrap(true);
346     setDescr.setBackground(getBackground());
347     setDescr.setEditable(true);
348     setDescr.getDocument().addDocumentListener(this);
349     setDescr.setToolTipText(MessageManager
350             .getString("label.edit_notes_parameter_set"));
351     JScrollPane setDescrView = new JScrollPane();
352     setDescrView.getViewport().setView(setDescr);
353     setName.setEditable(true);
354     setName.addItemListener(this);
355     setName.getEditor().addActionListener(this);
356     JPanel setNameInfo = new JPanel(new FlowLayout(FlowLayout.LEFT));
357     GridBagLayout gbl = new GridBagLayout();
358     SetNamePanel.setLayout(gbl);
359
360     JLabel setNameLabel = new JLabel(
361             MessageManager.getString("label.current_parameter_set_name"));
362     setNameLabel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
363
364     setNameInfo.add(setNameLabel);
365     setNameInfo.add(setName);
366
367     // initial button visibility
368     updatepref.setVisible(false);
369     deletepref.setVisible(false);
370     revertpref.setVisible(false);
371     createpref.setVisible(false);
372     JPanel setsavebuts = new JPanel();
373     setsavebuts.setLayout(new FlowLayout(FlowLayout.LEFT)); // GridLayout(1,2));
374     ((FlowLayout) setsavebuts.getLayout()).setHgap(10);
375     ((FlowLayout) setsavebuts.getLayout()).setVgap(0);
376     JPanel spacer = new JPanel();
377     spacer.setPreferredSize(new Dimension(2, 30));
378     setsavebuts.add(spacer);
379     setsavebuts.add(deletepref);
380     setsavebuts.add(revertpref);
381     setsavebuts.add(createpref);
382     setsavebuts.add(updatepref);
383     // setsavebuts.setSize(new Dimension(150, 30));
384     JPanel buttonArea = new JPanel(new GridLayout(1, 1));
385     buttonArea.add(setsavebuts);
386     SetNamePanel.add(setNameInfo);
387     GridBagConstraints gbc = new GridBagConstraints();
388     gbc.gridheight = 2;
389     gbl.setConstraints(setNameInfo, gbc);
390     SetNamePanel.add(buttonArea);
391     gbc = new GridBagConstraints();
392     gbc.gridx = 0;
393     gbc.gridy = 2;
394     gbc.gridheight = 1;
395     gbl.setConstraints(buttonArea, gbc);
396     setDetails.add(setDescrView, BorderLayout.CENTER);
397
398     // paramPane.setPreferredSize(new Dimension(360, 400));
399     // paramPane.setPreferredSize(null);
400     jobOptions.setBorder(new TitledBorder(MessageManager
401             .getString("label.options")));
402     jobOptions.setOpaque(true);
403     paramList.setBorder(new TitledBorder(MessageManager
404             .getString("label.parameters")));
405     paramList.setOpaque(true);
406     JPanel bjo = new JPanel(new BorderLayout()), bjp = new JPanel(
407             new BorderLayout());
408     bjo.add(jobOptions, BorderLayout.CENTER);
409     bjp.add(paramList, BorderLayout.CENTER);
410     bjp.setOpaque(true);
411     bjo.setOpaque(true);
412     // optsAndparams.setScrollableWidth(ScrollableSizeHint.FIT);
413     // optsAndparams.setScrollableHeight(ScrollableSizeHint.NONE);
414     // optsAndparams.setLayout(new BorderLayout());
415     optsAndparams.setLayout(new BorderLayout());
416     optsAndparams.add(jobOptions, BorderLayout.NORTH);
417     optsAndparams.add(paramList, BorderLayout.CENTER);
418     JPanel jp = new JPanel(new BorderLayout());
419     jp.add(optsAndparams, BorderLayout.CENTER);
420     paramPane.getViewport().setView(jp);
421     paramPane.setBorder(null);
422     setLayout(new BorderLayout());
423     jobPanel.setPreferredSize(null);
424     jobPanel.setLayout(new BorderLayout());
425     jobPanel.add(setDetails, BorderLayout.NORTH);
426     jobPanel.add(paramPane, BorderLayout.CENTER);
427     // jobPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
428
429     add(SetNamePanel, BorderLayout.NORTH);
430     add(jobPanel, BorderLayout.CENTER);
431
432     JPanel dialogpanel = new JPanel();
433     dialogpanel.add(startjob);
434     dialogpanel.add(canceljob);
435     // JAL-1580: setMaximumSize() doesn't work, so just size for the worst case:
436     // check for null is for JUnit usage
437     final int windowHeight = Desktop.instance == null ? 540
438             : Desktop.instance.getHeight();
439     setPreferredSize(new Dimension(540, windowHeight));
440     add(dialogpanel, BorderLayout.SOUTH);
441     validate();
442   }
443
444   protected void revert_actionPerformed(ActionEvent e)
445   {
446     reInitDialog(lastParmSet);
447     updateWebServiceMenus();
448   }
449
450   protected void update_actionPerformed(ActionEvent e)
451   {
452     if (isUserPreset)
453     {
454       String curname = ((String) setName.getSelectedItem()).trim();
455       _updatePreset(lastParmSet, curname);
456       lastParmSet = curname;
457       isUserPreset = true;
458       initArgSetModified();
459       syncSetNamesWithStore();
460     }
461   }
462
463   private void _deleteUserPreset(String lastParmSet2)
464   {
465     paramStore.deletePreset(lastParmSet2);
466   }
467
468   protected void delete_actionPerformed(ActionEvent e)
469   {
470     if (isUserPreset)
471     {
472       // delete current preset's saved entry
473       _deleteUserPreset(lastParmSet);
474     }
475     reInitDialog(null); // service default
476     updateWebServiceMenus();
477   }
478
479   protected void create_actionPerformed(ActionEvent e)
480   {
481     String curname = ((String) setName.getSelectedItem()).trim();
482     if (curname.length() > 0)
483     {
484       _storeCurrentPreset(curname);
485       lastParmSet = curname;
486       isUserPreset = true;
487       reInitDialog(curname);
488       initArgSetModified();
489       updateWebServiceMenus();
490     }
491     else
492     {
493       // TODO: show warning
494       System.err.println("Invalid name. Not saved.");
495     }
496   }
497
498   protected void canceljob_actionPerformed(ActionEvent e)
499   {
500     response = 0;
501     if (frame != null)
502     {
503       frame.setVisible(false);
504     }
505   }
506
507   protected void startjob_actionPerformed(ActionEvent e)
508   {
509     response = 1;
510     if (frame != null)
511     {
512       frame.setVisible(false);
513     }
514   }
515
516   Jws2Instance service;
517
518   /**
519    * list of service presets in the gui
520    */
521   Hashtable servicePresets = null;
522
523   /**
524    * set if dialog is being set - so handlers will avoid spurious events
525    */
526   boolean settingDialog = false;
527
528   void initForService(Jws2Instance service, WsParamSetI jabap,
529           List<Argument> jabajobArgset)
530   {
531     WsParamSetI p = null;
532     List<ArgumentI> jobArgset = null;
533     settingDialog = true;
534     { // instantiate the abstract proxy for Jaba objects
535       jobArgset = jabajobArgset == null ? null : JabaParamStore
536               .getJwsArgsfromJaba(jabajobArgset);
537       p = jabap; // (jabap != null) ? paramStore.getPreset(jabap.getName()) :
538                  // null;
539     }
540
541     Hashtable exnames = new Hashtable();
542     for (int i = 0, iSize = setName.getItemCount(); i < iSize; i++)
543     {
544       exnames.put(setName.getItemAt(i), setName.getItemAt(i));
545     }
546     servicePresets = new Hashtable();
547     // Add the default entry - if not present already.
548     if (!exnames.contains(SVC_DEF))
549     {
550       setName.addItem(SVC_DEF);
551       exnames.put(SVC_DEF, SVC_DEF);
552       servicePresets.put(SVC_DEF, SVC_DEF);
553     }
554     String curname = (p == null ? "" : p.getName());
555     for (WsParamSetI pr : paramStore.getPresets())
556     {
557       if (!pr.isModifiable())
558       {
559         servicePresets.put(pr.getName(), "preset");
560       }
561       else
562       {
563       }
564       if (!exnames.contains(pr.getName()))
565       {
566         setName.addItem(pr.getName());
567       }
568     }
569     // TODO: if initial jobArgset matches a given user setting or preset then
570     // should recover setting accordingly
571     // updateTable(p, jobArgset);
572     if (p != null)
573     {
574       reInitDialog(p.getName());
575       initArgSetModified();
576     }
577     else
578     {
579       if (jobArgset != null && jobArgset.size() > 0)
580       {
581         curSetName = "Supplied Settings";
582         isUserPreset = false;
583         updateTable(p, jobArgset);
584         setName.setSelectedItem(curSetName);
585         updateButtonDisplay();
586       }
587       else
588       {
589         curSetName = null;
590         reInitDialog(null);
591       }
592     }
593     settingDialog = false;
594
595   }
596
597   @SuppressWarnings("unchecked")
598   private void updateTable(WsParamSetI p, List<ArgumentI> jobArgset)
599   {
600     boolean setDefaultParams = false;
601     if (lastParmSet == null)
602     {
603       isUserPreset = false;
604       // First call - so provide Service default settings
605       setName.setSelectedItem(lastSetName = SVC_DEF);
606     }
607     if (p == null && SVC_DEF.equals("" + setName.getSelectedItem()))
608     {
609       // indicate that service defaults should be set if available
610       setDefaultParams = true;
611     }
612     // populate table from default parameter set.
613     List<ArgumentI> args = paramStore.getServiceParameters();
614
615     // split to params and required arguments
616     {
617       int cw = 0;
618       boolean optset = false;
619       for (ArgumentI myarg : args)
620       {
621         // Ideally, Argument would implement isRequired !
622         if (myarg instanceof ParameterI)
623         {
624           ParameterI parm = (ParameterI) myarg;
625           opanp.addParameter(parm).validate();
626         }
627         else
628         {
629           if (myarg instanceof OptionI)
630           {
631             OptionI opt = (OptionI) myarg;
632             OptionBox ob = opanp.addOption(opt);
633             ob.resetToDefault(setDefaultParams);
634             if (MAX_OPTWIDTH < ob.getPreferredSize().width)
635             {
636               MAX_OPTWIDTH = ob.getPreferredSize().width;
637             }
638             ob.validate();
639             cw += ob.getPreferredSize().width + 5;
640           }
641           else
642           {
643             System.err.println("Ignoring unknown service argument type "
644                     + myarg.getClass().getName());
645           }
646         }
647       }
648       args = null; // no more args to process.
649     }
650     if (p != null)
651     {
652       isUserPreset = false;
653       // initialise setname
654       setName.setSelectedItem(lastSetName = p.getName());
655       setDescr.setText(lastDescrText = p.getDescription());
656       // TODO - URL link
657       try
658       {
659         args = p.getArguments();
660       } catch (Exception e)
661       {
662         e.printStackTrace();
663       }
664       // TODO: check if args should be unselected prior to resetting using the
665       // preset
666     }
667
668     if (jobArgset != null)
669     {
670       argSetModified(jobArgset, true);
671       args = jobArgset;
672     }
673     // get setargs from current object
674     if (args != null)
675     {
676       for (ArgumentI arg : args)
677       {
678         if (arg instanceof ParameterI)
679         {
680           opanp.setParameter((ParameterI) arg);
681         }
682         else
683         {
684           if (arg instanceof OptionI)
685           {
686             // System.out.println("Setting option "
687             // + System.identityHashCode(arg) + ":" + arg.getName()
688             // + " with " + arg.getDefaultValue());
689             opanp.selectOption((OptionI) arg, arg.getValue());
690           }
691         }
692
693       }
694     }
695
696     refreshParamLayout();
697     revalidate();
698   }
699
700   private boolean isModified()
701   {
702     return modifiedElements.size() > 0;
703   }
704
705   private Hashtable modifiedElements = new Hashtable();
706
707   /**
708    * reset gui and modification state settings
709    */
710   private void initArgSetModified()
711   {
712     curSetName = null;
713     modifiedElements.clear();
714     updateButtonDisplay();
715   }
716
717   private void updateButtonDisplay()
718   {
719     boolean _update = false, _create = false, _delete = false, _revert = false;
720     if (modifiedElements.size() > 0)
721     {
722       // set modified
723       _revert = true;
724       _update = isUserPreset; // can only update user presets
725       if (!isUserPreset || modifiedElements.containsKey(setName))
726       {
727         // name modified - can create new preset
728         _create = true;
729       }
730     }
731     else
732     {
733       // set unmodified
734     }
735     // can still delete a user preset
736     _delete = isUserPreset;
737
738     createpref.setVisible(_create);
739     updatepref.setVisible(_update);
740     deletepref.setVisible(_delete);
741     revertpref.setVisible(_revert);
742     validate();
743   }
744
745   @Override
746   public void argSetModified(Object modifiedElement, boolean b)
747   {
748     if (settingDialog)
749     {
750       return;
751     }
752     if (!b)
753     {
754       modifiedElements.remove(modifiedElement);
755     }
756     else
757     {
758       if (b && modifiedElement == setName
759               && modifiedElements.contains(modifiedElement))
760       {
761         // HACK! prevents iteration on makeSetNameValid
762         b = false;
763       }
764       modifiedElements.put(modifiedElement, modifiedElement);
765     }
766     // set mod status based on presence of elements in table
767     if (b && modifiedElements.size() > 0)
768     {
769       makeSetNameValid(!isUserPreset);
770       SetNamePanel.revalidate();
771     }
772     updateButtonDisplay();
773   }
774
775   private boolean isServicePreset(String selectedItem)
776   {
777     return selectedItem.equals(SVC_DEF)
778             || servicePresets.containsKey(selectedItem);
779   }
780
781   /**
782    * check if the current set name is a valid set name for saving, if not, then
783    * fix it.
784    */
785   private void makeSetNameValid(boolean newuserset)
786   {
787     boolean stn = settingDialog;
788     boolean renamed = false;
789     settingDialog = true;
790     String nm = (curSetName != null ? curSetName : (String) setName
791             .getSelectedItem());
792     // check if the name is reserved - if it is, rename it.
793     if (isServicePreset(nm))
794     {
795       nm = "User " + nm;
796       renamed = true;
797     }
798     String tnm = nm;
799     if (newuserset)
800     {
801       int i = 0;
802       while (paramStore.getPreset(tnm) != null)
803       {
804         tnm = nm + " (" + (++i) + ")";
805         renamed = true;
806       }
807       if (i > 0)
808       {
809         nm = tnm;
810       }
811     }
812
813     boolean makeupdate = false;
814     // sync the gui with the preset database
815     for (int i = 0, iS = setName.getItemCount(); i < iS; i++)
816     {
817       String snm = (String) setName.getItemAt(i);
818       if (snm.equals(nm))
819       {
820         makeupdate = true;
821         // setName.setSelectedIndex(i);
822       }
823     }
824     if (!makeupdate)
825     {
826       setName.addItem(curSetName = nm);
827       setName.setSelectedItem(curSetName);
828     }
829     if (renamed)
830     {
831       settingDialog = false; // we need this name change to be registered.
832       argSetModified(setName, renamed);
833     }
834     settingDialog = stn;
835   }
836
837   @Override
838   public void refreshParamLayout()
839   {
840     // optsAndparams.setPreferredSize(null);
841     FlowLayout fl = new FlowLayout(FlowLayout.LEFT);
842     int sep = fl.getVgap();
843     boolean fh = true;
844     int os = 0, s = jobOptions.getBorder().getBorderInsets(jobOptions).bottom
845             + jobOptions.getBorder().getBorderInsets(jobOptions).top
846             + 2
847             * sep;
848     /**
849      * final height for viewport
850      */
851     int finalh = s;
852     int panewidth = paramPane.getViewport().getSize().width - 120
853             - jobOptions.getBorder().getBorderInsets(jobOptions).left
854             + jobOptions.getBorder().getBorderInsets(jobOptions).right;
855
856     int w = 2
857             * fl.getHgap()
858             + (MAX_OPTWIDTH > OptsAndParamsPage.PARAM_WIDTH ? MAX_OPTWIDTH
859                     : OptsAndParamsPage.PARAM_WIDTH);
860     int hgap = fl.getHgap(), cw = hgap;
861
862     if (opanp.getOptSet().size() > 0)
863     {
864
865       jobOptions.setLayout(new MigLayout("", "", ""));
866       jobOptions.removeAll();
867
868       for (OptionBox pbox : opanp.getOptSet().values())
869       {
870         pbox.validate();
871         cw += pbox.getSize().width + hgap;
872         if (cw + 120 > panewidth)
873         {
874           jobOptions.add(pbox, "wrap");
875           // System.out.println("Wrap on "+pbox.option.getName());
876           cw = hgap + pbox.getSize().width;
877           fh = true;
878         }
879         else
880         {
881           jobOptions.add(pbox);
882         }
883         if (fh)
884         {
885           finalh += pbox.getSize().height + fl.getVgap();
886           fh = false;
887         }
888       }
889       jobOptions.revalidate();
890     }
891     else
892     {
893       jobOptions.setVisible(false);
894     }
895
896     // Now layout the parameters assuming they occupy one column - to calculate
897     // total height of options+parameters
898     fl = new FlowLayout(FlowLayout.LEFT);
899     // helpful hint from
900     // http://stackoverflow.com/questions/2743177/top-alignment-for-flowlayout
901     fl.setAlignOnBaseline(true);
902     if (opanp.getParamSet().size() > 0)
903     {
904       paramList.removeAll();
905       paramList.setLayout(new MigLayout("", "", ""));
906       fh = true;
907       for (ParamBox pbox : opanp.getParamSet().values())
908       {
909         pbox.validate();
910         cw += pbox.getSize().width + hgap;
911         if (cw + 160 > panewidth)
912         {
913           paramList.add(pbox, "wrap");
914           cw = pbox.getSize().width + hgap;
915           fh = true;
916         }
917         else
918         {
919           paramList.add(pbox);
920         }
921         if (fh)
922         {
923           finalh += pbox.getSize().height + fl.getVgap();
924           fh = false;
925         }
926
927       }
928       /*
929        * s = 2 * sep; for (ParamBox pbox : opanp.getParamSet().values()) {
930        * pbox.validate(); s += sep +
931        * pbox.getPreferredSize().height+pbox.getBorder
932        * ().getBorderInsets(pbox).bottom; }
933        * 
934        * // paramList.setPreferredSize(new Dimension(w, s));
935        * os+=s+2*sep+paramList
936        * .getBorder().getBorderInsets(paramList).bottom+paramList
937        * .getBorder().getBorderInsets(paramList).top;
938        */
939       paramList.revalidate();
940     }
941     else
942     {
943       paramList.setVisible(false);
944     }
945     // TODO: waste some time trying to eliminate any unnecessary .validate calls
946     // here
947     // System.out.println("Size will be : "+w+","+os);
948     // optsAndparams.setPreferredSize(null);
949     // paramPane.getViewport().setView(optsAndparams);
950     paramPane.getViewport().setAutoscrolls(true);
951     paramPane.revalidate();
952     revalidate();
953   }
954
955   /**
956    * testing method - grab a service and parameter set and show the window
957    * 
958    * @param args
959    */
960   public static void main(String[] args)
961   {
962     jalview.ws.jws2.Jws2Discoverer disc = jalview.ws.jws2.Jws2Discoverer
963             .getDiscoverer();
964     int p = 0;
965     if (args.length > 0)
966     {
967       Vector<String> services = new Vector<String>();
968       services.addElement(args[p++]);
969       Jws2Discoverer.getDiscoverer().setServiceUrls(services);
970     }
971     try
972     {
973       disc.run();
974     } catch (Exception e)
975     {
976       System.err.println("Aborting. Problem discovering services.");
977       e.printStackTrace();
978       return;
979     }
980     Jws2Instance lastserv = null;
981     for (Jws2Instance service : disc.getServices())
982     {
983       lastserv = service;
984       if (p >= args.length || service.serviceType.equalsIgnoreCase(args[p]))
985       {
986         if (lastserv != null)
987         {
988           List<Preset> prl = null;
989           Preset pr = null;
990           if (++p < args.length)
991           {
992             PresetManager prman = lastserv.getPresets();
993             if (prman != null)
994             {
995               pr = prman.getPresetByName(args[p]);
996               if (pr == null)
997               {
998                 // just grab the last preset.
999                 prl = prman.getPresets();
1000               }
1001             }
1002           }
1003           else
1004           {
1005             PresetManager prman = lastserv.getPresets();
1006             if (prman != null)
1007             {
1008               prl = prman.getPresets();
1009             }
1010           }
1011           Iterator<Preset> en = (prl == null) ? null : prl.iterator();
1012           while (en != null && en.hasNext())
1013           {
1014             if (en != null)
1015             {
1016               if (!en.hasNext())
1017               {
1018                 en = prl.iterator();
1019               }
1020               pr = en.next();
1021             }
1022             {
1023               System.out.println("Testing opts dupes for "
1024                       + lastserv.getUri() + " : "
1025                       + lastserv.getActionText() + ":" + pr.getName());
1026               List<Option> rg = lastserv.getRunnerConfig().getOptions();
1027               for (Option o : rg)
1028               {
1029                 try
1030                 {
1031                   Option cpy = jalview.ws.jws2.ParameterUtils.copyOption(o);
1032                 } catch (Exception e)
1033                 {
1034                   System.err.println("Failed to copy " + o.getName());
1035                   e.printStackTrace();
1036                 } catch (Error e)
1037                 {
1038                   System.err.println("Failed to copy " + o.getName());
1039                   e.printStackTrace();
1040                 }
1041               }
1042             }
1043             {
1044               System.out.println("Testing param dupes:");
1045               List<Parameter> rg = lastserv.getRunnerConfig()
1046                       .getParameters();
1047               for (Parameter o : rg)
1048               {
1049                 try
1050                 {
1051                   Parameter cpy = jalview.ws.jws2.ParameterUtils
1052                           .copyParameter(o);
1053                 } catch (Exception e)
1054                 {
1055                   System.err.println("Failed to copy " + o.getName());
1056                   e.printStackTrace();
1057                 } catch (Error e)
1058                 {
1059                   System.err.println("Failed to copy " + o.getName());
1060                   e.printStackTrace();
1061                 }
1062               }
1063             }
1064             {
1065               System.out.println("Testing param write:");
1066               List<String> writeparam = null, readparam = null;
1067               try
1068               {
1069                 writeparam = jalview.ws.jws2.ParameterUtils
1070                         .writeParameterSet(
1071                                 pr.getArguments(lastserv.getRunnerConfig()),
1072                                 " ");
1073                 System.out.println("Testing param read :");
1074                 List<Option> pset = jalview.ws.jws2.ParameterUtils
1075                         .processParameters(writeparam,
1076                                 lastserv.getRunnerConfig(), " ");
1077                 readparam = jalview.ws.jws2.ParameterUtils
1078                         .writeParameterSet(pset, " ");
1079                 Iterator<String> o = pr.getOptions().iterator(), s = writeparam
1080                         .iterator(), t = readparam.iterator();
1081                 boolean failed = false;
1082                 while (s.hasNext() && t.hasNext())
1083                 {
1084                   String on = o.next(), sn = s.next(), st = t.next();
1085                   if (!sn.equals(st))
1086                   {
1087                     System.out.println("Original was " + on
1088                             + " Phase 1 wrote " + sn + "\tPhase 2 wrote "
1089                             + st);
1090                     failed = true;
1091                   }
1092                 }
1093                 if (failed)
1094                 {
1095                   System.out.println("Original parameters:\n"
1096                           + pr.getOptions());
1097                   System.out.println("Wrote parameters in first set:\n"
1098                           + writeparam);
1099                   System.out.println("Wrote parameters in second set:\n"
1100                           + readparam);
1101
1102                 }
1103               } catch (Exception e)
1104               {
1105                 e.printStackTrace();
1106               }
1107             }
1108             WsJobParameters pgui = new WsJobParameters(lastserv,
1109                     new JabaPreset(lastserv, pr));
1110             JFrame jf = new JFrame(MessageManager.formatMessage(
1111                     "label.ws_parameters_for",
1112                     new String[] { lastserv.getActionText() }));
1113             JPanel cont = new JPanel(new BorderLayout());
1114             pgui.validate();
1115             cont.setPreferredSize(pgui.getPreferredSize());
1116             cont.add(pgui, BorderLayout.CENTER);
1117             jf.setLayout(new BorderLayout());
1118             jf.add(cont, BorderLayout.CENTER);
1119             jf.validate();
1120             final Thread thr = Thread.currentThread();
1121             jf.addWindowListener(new WindowListener()
1122             {
1123
1124               @Override
1125               public void windowActivated(WindowEvent e)
1126               {
1127                 // TODO Auto-generated method stub
1128
1129               }
1130
1131               @Override
1132               public void windowClosed(WindowEvent e)
1133               {
1134               }
1135
1136               @Override
1137               public void windowClosing(WindowEvent e)
1138               {
1139                 thr.interrupt();
1140
1141               }
1142
1143               @Override
1144               public void windowDeactivated(WindowEvent e)
1145               {
1146                 // TODO Auto-generated method stub
1147
1148               }
1149
1150               @Override
1151               public void windowDeiconified(WindowEvent e)
1152               {
1153                 // TODO Auto-generated method stub
1154
1155               }
1156
1157               @Override
1158               public void windowIconified(WindowEvent e)
1159               {
1160                 // TODO Auto-generated method stub
1161
1162               }
1163
1164               @Override
1165               public void windowOpened(WindowEvent e)
1166               {
1167                 // TODO Auto-generated method stub
1168
1169               }
1170
1171             });
1172             jf.setVisible(true);
1173             boolean inter = false;
1174             while (!inter)
1175             {
1176               try
1177               {
1178                 Thread.sleep(10000);
1179               } catch (Exception e)
1180               {
1181                 inter = true;
1182               }
1183               ;
1184             }
1185             jf.dispose();
1186           }
1187         }
1188       }
1189     }
1190   }
1191
1192   public boolean isServiceDefaults()
1193   {
1194     return (!isModified() && (lastParmSet != null && lastParmSet
1195             .equals(SVC_DEF)));
1196   }
1197
1198   public List<ArgumentI> getJobParams()
1199   {
1200     return opanp.getCurrentSettings();
1201   }
1202
1203   String lastParmSet = null;
1204
1205   /*
1206    * Hashtable<String, Object[]> editedParams = new Hashtable<String,
1207    * Object[]>();
1208    * 
1209    * store the given parameters in the user parameter set database.
1210    * 
1211    * @param storeSetName - lastParmSet
1212    * 
1213    * @param descr - setDescr.getText()
1214    * 
1215    * @param jobParams - getJobParams()
1216    * 
1217    * private void _storeUserPreset(String storeSetName, String descr,
1218    * List<ArgumentI> jobParams) { // this is a simple hash store. Object[] pset;
1219    * editedParams.put(storeSetName, pset = new Object[3]); pset[0] =
1220    * storeSetName; pset[1] = descr; pset[2] = jobParams; // writeParam("Saving "
1221    * + storeSetName + ": ", jobParams); }
1222    * 
1223    * private void writeParam(String nm, List<ArgumentI> params) { for (ArgumentI
1224    * p : params) { System.out.println(nm + ":" + System.identityHashCode(p) +
1225    * " Name: " + p.getName() + " Value: " + p.getDefaultValue()); } }
1226    * 
1227    * private Object[] _getUserPreset(String setName) { Object[] pset =
1228    * editedParams.get(setName); // if (pset != null) // writeParam("Retrieving "
1229    * + setName + ": ", (List<Argument>) pset[2]); return pset; }
1230    * 
1231    * * remove the given user preset from the preset stash
1232    * 
1233    * @param setName
1234    * 
1235    * private void _deleteUserPreset(String setName) {
1236    * editedParams.remove(setName); }
1237    */
1238
1239   private void syncSetNamesWithStore()
1240   {
1241     int n = 0;
1242     // remove any set names in the drop down menu that aren't either a reserved
1243     // setting, or a user defined or service preset.
1244     Vector items = new Vector();
1245     while (n < setName.getItemCount())
1246     {
1247       String item = (String) setName.getItemAt(n);
1248       if (!item.equals(SVC_DEF) && !paramStore.presetExists(item))
1249       {
1250         setName.removeItemAt(n);
1251       }
1252       else
1253       {
1254         items.addElement(item);
1255         n++;
1256       }
1257     }
1258     if (!items.contains(SVC_DEF))
1259     {
1260       setName.addItem(SVC_DEF);
1261     }
1262     for (WsParamSetI upn : paramStore.getPresets())
1263     {
1264       if (!items.contains(upn.getName()))
1265       {
1266         setName.addItem(upn.getName());
1267       }
1268     }
1269   }
1270
1271   /**
1272    * true if lastParmSet is a user preset
1273    */
1274   boolean isUserPreset = false;
1275
1276   private void reInitDialog(String nextPreset)
1277   {
1278     settingDialog = true;
1279     // updateTable(null,null); // first reset to defaults
1280     WsParamSetI pset = null;
1281     if (nextPreset != null && nextPreset.length() > 0)
1282     {
1283       pset = paramStore.getPreset(nextPreset);
1284     }
1285     if (pset != null)
1286     {
1287       if (pset.isModifiable())
1288       {
1289         isUserPreset = true;
1290         setDescr.setText(pset.getDescription());
1291         updateTable(null, pset.getArguments());
1292         lastParmSet = nextPreset;
1293       }
1294       else
1295       {
1296         isUserPreset = false;
1297         setDescr.setText("");
1298         // must be a default preset from service
1299         updateTable(pset, null);
1300         lastParmSet = nextPreset;
1301       }
1302     }
1303     else
1304     {
1305       isUserPreset = false;
1306       // Service defaults
1307       setDescr.setText("");
1308       updateTable(null, null);
1309       lastParmSet = SVC_DEF;
1310     }
1311
1312     initArgSetModified();
1313     syncSetNamesWithStore();
1314     setName.setSelectedItem(lastParmSet);
1315     SetNamePanel.validate();
1316     validate();
1317     settingDialog = false;
1318   }
1319
1320   /**
1321    * Rebuild the AlignFrame web service menus (after add/delete of a preset
1322    * option).
1323    */
1324   protected void updateWebServiceMenus()
1325   {
1326     for (AlignFrame alignFrame : Desktop.getAlignFrames())
1327     {
1328       alignFrame.BuildWebServiceMenu();
1329     }
1330   }
1331
1332   String curSetName = null;
1333
1334   @Override
1335   public void itemStateChanged(ItemEvent e)
1336   {
1337     if (e.getSource() == setName && e.getStateChange() == e.SELECTED)
1338     {
1339       final String setname = (String) setName.getSelectedItem();
1340       System.out.println("Item state changed for " + setname
1341               + " (handling ? " + !settingDialog + ")");
1342       if (settingDialog)
1343       {
1344         // ignore event
1345         return;
1346       }
1347       if (setname == null)
1348       {
1349         return;
1350       }
1351       javax.swing.SwingUtilities.invokeLater(new Runnable()
1352       {
1353         @Override
1354         public void run()
1355         {
1356           doPreferenceComboStateChange(setname);
1357         }
1358       });
1359     }
1360   }
1361
1362   private void doPreferenceComboStateChange(String setname)
1363   {
1364     // user has selected a different item from combo-box
1365     if (isModified())
1366     {
1367       String lsetname = (curSetName != null) ? curSetName : lastParmSet;
1368       if (lsetname.equals(setname))
1369       {
1370         // setname was just edited - so ignore this event.
1371         return;
1372       }
1373       settingDialog = true;
1374       System.out.println("Prompting to save " + lsetname);
1375       if (JvOptionPane
1376               .showConfirmDialog(
1377                       this,
1378                       "Parameter set '"
1379                               + lsetname
1380                               + "' is modifed, and your changes will be lost.\nReally change preset ?",
1381                       "Warning: Unsaved Changes",
1382                       JvOptionPane.OK_CANCEL_OPTION) != JvOptionPane.OK_OPTION)
1383       {
1384         // revert the combobox to the current item
1385         settingDialog = true;
1386         setName.setSelectedItem(lsetname);
1387         settingDialog = false;
1388         // and leave.
1389         return;
1390         // System.out.println("Saving for " + lsetname);
1391         // _storeCurrentPreset(lsetname);
1392
1393       }
1394     }
1395     settingDialog = true;
1396     reInitDialog(setname);
1397     settingDialog = false;
1398
1399   }
1400
1401   private void _renameExistingPreset(String oldName, String curSetName2)
1402   {
1403     paramStore.updatePreset(oldName, curSetName2, setDescr.getText(),
1404             getJobParams());
1405   }
1406
1407   /**
1408    * store current settings as given name. You should then reset gui.
1409    * 
1410    * @param curSetName2
1411    */
1412   private void _storeCurrentPreset(String curSetName2)
1413   {
1414     paramStore.storePreset(curSetName2, setDescr.getText(), getJobParams());
1415   }
1416
1417   private void _updatePreset(String lastParmSet2, String curname)
1418   {
1419     paramStore.updatePreset(lastParmSet2, curname, setDescr.getText(),
1420             getJobParams());
1421
1422   }
1423
1424   /**
1425    * last saved name for this user preset
1426    */
1427   String lastSetName = null;
1428
1429   /**
1430    * last saved value of the description text for this user preset
1431    */
1432   String lastDescrText = null;
1433
1434   @Override
1435   public void actionPerformed(ActionEvent e)
1436   {
1437     if (e.getSource() instanceof Component)
1438     {
1439       Component src = (Component) e.getSource();
1440       if (src.getParent() == setName)
1441       {
1442         // rename any existing records we know about for this set.
1443         String newname = e.getActionCommand().trim();
1444         String msg = null;
1445         if (isServicePreset(newname))
1446         {
1447           final String oldname = curSetName != null ? curSetName
1448                   : lastParmSet;
1449           final Component ourframe = this;
1450           settingDialog = true;
1451           setName.getEditor().setItem(oldname);
1452           settingDialog = false;
1453           javax.swing.SwingUtilities.invokeLater(new Runnable()
1454           {
1455             @Override
1456             public void run()
1457             {
1458               JvOptionPane.showMessageDialog(ourframe, MessageManager
1459                       .getString("label.invalid_name_preset_exists"),
1460                       MessageManager.getString("label.invalid_name"),
1461                       JvOptionPane.WARNING_MESSAGE);
1462             }
1463           });
1464
1465           return;
1466         }
1467         curSetName = newname;
1468         System.err.println("New name for user setting " + curSetName
1469                 + " (was " + setName.getSelectedItem() + ")");
1470         if (curSetName.equals(setName.getSelectedItem()))
1471         {
1472           curSetName = null;
1473         }
1474         if (curSetName != null)
1475         {
1476           argSetModified(setName, true);
1477           return;
1478         }
1479
1480       }
1481     }
1482   }
1483
1484   private void checkDescrModified()
1485   {
1486     if (!settingDialog)
1487     {
1488
1489       argSetModified(
1490               setDescr,
1491               (lastDescrText == null ? setDescr.getText().trim().length() > 0
1492                       : !setDescr.getText().equals(lastDescrText)));
1493
1494     }
1495   }
1496
1497   @Override
1498   public void insertUpdate(DocumentEvent e)
1499   {
1500     checkDescrModified();
1501   }
1502
1503   @Override
1504   public void removeUpdate(DocumentEvent e)
1505   {
1506     checkDescrModified();
1507   }
1508
1509   @Override
1510   public void changedUpdate(DocumentEvent e)
1511   {
1512     checkDescrModified();
1513   }
1514
1515   /**
1516    * 
1517    * @return null or the service preset selected by the user
1518    */
1519   public WsParamSetI getPreset()
1520   {
1521     if (isUserPreset || isModified()
1522             || (lastParmSet != null && lastParmSet.equals(SVC_DEF)))
1523     {
1524       return null;
1525     }
1526     else
1527     {
1528       return paramStore.getPreset(lastParmSet);
1529     }
1530   }
1531 }