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