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