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