719b7d929e72619e6dee9affadc529c5078edab4
[jalview.git] / src / jalview / gui / WsJobParameters.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import jalview.gui.OptsAndParamsPage.OptionBox;
24 import jalview.gui.OptsAndParamsPage.ParamBox;
25 import jalview.util.MessageManager;
26 import jalview.ws.api.UIinfo;
27 import jalview.ws.params.ArgumentI;
28 import jalview.ws.params.OptionI;
29 import jalview.ws.params.ParamDatastoreI;
30 import jalview.ws.params.ParameterI;
31 import jalview.ws.params.WsParamSetI;
32
33 import java.awt.BorderLayout;
34 import java.awt.Component;
35 import java.awt.Dimension;
36 import java.awt.FlowLayout;
37 import java.awt.Font;
38 import java.awt.GridBagConstraints;
39 import java.awt.GridBagLayout;
40 import java.awt.GridLayout;
41 import java.awt.Rectangle;
42 import java.awt.event.ActionEvent;
43 import java.awt.event.ActionListener;
44 import java.awt.event.HierarchyBoundsListener;
45 import java.awt.event.HierarchyEvent;
46 import java.awt.event.ItemEvent;
47 import java.awt.event.ItemListener;
48 import java.util.Hashtable;
49 import java.util.List;
50 import java.util.Vector;
51
52 import javax.swing.JButton;
53 import javax.swing.JComboBox;
54 import javax.swing.JDialog;
55 import javax.swing.JLabel;
56 import javax.swing.JPanel;
57 import javax.swing.JScrollPane;
58 import javax.swing.JTextArea;
59 import javax.swing.border.TitledBorder;
60 import javax.swing.event.DocumentEvent;
61 import javax.swing.event.DocumentListener;
62
63 import net.miginfocom.swing.MigLayout;
64
65 /**
66  * job parameter editing/browsing dialog box. User can browse existing settings
67  * (user + presets + Defaults), and any changes to parameters creates a modified
68  * user parameter set. LOGIC: If the parameter set is modified, and its name is
69  * a valid, non-existant user parameter set, then a save button is shown. If the
70  * parameter set is modified and its name is a valid, extant user parameter set,
71  * then an update button is shown. If user parameter set's name is edited, and
72  * old name exists as a writable user parameter set, then rename button is
73  * shown. If current parameter set is associated with a user defined parameter
74  * set, then : if set is modifed, a 'revert' button is shown. if set is not
75  * modified, a 'delete' button is shown.
76  * 
77  * @author JimP
78  * 
79  */
80 public class WsJobParameters extends JPanel implements ItemListener,
81         ActionListener, DocumentListener, OptsParametersContainerI
82 {
83   private static final int PREFERRED_WIDTH = 540;
84
85   private static final int DEFAULT_HEIGHT = 640;
86
87   // the default parameter set shown to the user
88   private static final String SVC_DEF = "Defaults";
89
90   private int maxOptWidth = 200;
91
92   // URL linkImageURL = getClass().getResource("/images/link.gif");
93
94   // TODO ABSRACT FROM JABAWS CLASSES
95
96   /**
97    * manager for options and parameters.
98    */
99   OptsAndParamsPage opanp;
100
101   /*
102    * panel containing job options
103    */
104   JPanel optionsPanel = new JPanel();
105
106   /*
107    * panel containing job parameters
108    */
109   JPanel paramsPanel = new JPanel();
110
111   JPanel setNamePanel = new JPanel();
112
113   JButton createpref = new JButton();
114
115   JButton deletepref = new JButton();
116
117   JButton revertpref = new JButton();
118
119   JButton updatepref = new JButton();
120
121   JComboBox<String> setName = new JComboBox<>();
122
123   JTextArea setDescr = new JTextArea();
124
125   JScrollPane paramPane = new JScrollPane();
126
127   ParamDatastoreI paramStore;
128
129   // set true when 'Start Job' is clicked
130   boolean startJob = false;
131
132   JDialog frame = null;
133
134   UIinfo service;
135
136   /*
137    * list of service presets in the gui
138    */
139   Hashtable<String, String> servicePresets = null;
140
141   /*
142    * set if dialog is being set - so handlers will avoid spurious events
143    */
144   boolean settingDialog = false;
145
146   private Hashtable<Object, Object> modifiedElements = new Hashtable<>();
147
148   String lastParmSet = null;
149
150   public WsJobParameters(ParamDatastoreI store, WsParamSetI preset,
151           List<ArgumentI> args)
152   {
153     super();
154
155     // parameters dialog in 'compact' format (help as tooltips)
156     opanp = new OptsAndParamsPage(this, true);
157     jbInit();
158     this.paramStore = store;
159     this.service = null;
160     init(preset, args);
161     validate();
162   }
163
164   /**
165    * Constructor given a set of parameters and presets, a service to be invoked,
166    * and a list of (Jabaws client) arguments
167    * 
168    * @param paramStorei
169    * @param service
170    * @param preset
171    * @param jobArgset
172    */
173   public WsJobParameters(ParamDatastoreI paramStorei, UIinfo service,
174           WsParamSetI preset, List<ArgumentI> jobArgset)
175   {
176     super();
177
178     // parameters dialog in 'expanded' format (help text boxes)
179     opanp = new OptsAndParamsPage(this, false);
180
181     jbInit();
182     this.paramStore = paramStorei;
183     if (paramStore == null && service != null)
184     {
185       paramStore = service.getParamStore();
186     }
187     this.service = service;
188     initForService(preset, jobArgset);
189     validate();
190   }
191
192   /**
193    * Shows a modal dialog containing the parameters and Start or Cancel options.
194    * Answers true if the job is started, false if cancelled.
195    * 
196    * @return
197    */
198   public boolean showRunDialog()
199   {
200
201     frame = new JDialog(Desktop.getInstance(), true);
202     if (service != null)
203     {
204       frame.setTitle(MessageManager.formatMessage("label.edit_params_for",
205               new String[]
206       { service.getActionText() }));
207     }
208     frame.setTitle(MessageManager.formatMessage("label.edit_params_for",
209             new String[]
210             { service.getActionText() }));
211     Rectangle deskr = Desktop.getInstance().getBounds();
212     Dimension pref = this.getPreferredSize();
213     frame.setBounds(
214             new Rectangle((int) (deskr.getCenterX() - pref.width / 2),
215                     (int) (deskr.getCenterY() - pref.height / 2),
216                     pref.width, pref.height));
217     frame.setContentPane(this);
218
219     // should perhaps recover defaults from user prefs.
220
221     frame.validate();
222     javax.swing.SwingUtilities.invokeLater(new Runnable()
223     {
224       @Override
225       public void run()
226       {
227         // jobPanel.setDividerLocation(0.25);
228
229       }
230     });
231     frame.setVisible(true);
232
233     return startJob;
234   }
235
236   private void jbInit()
237   {
238     this.addHierarchyBoundsListener(new HierarchyBoundsListener()
239     {
240
241       @Override
242       public void ancestorResized(HierarchyEvent arg0)
243       {
244         refreshParamLayout();
245       }
246
247       @Override
248       public void ancestorMoved(HierarchyEvent arg0)
249       {
250         // TODO Auto-generated method stub
251
252       }
253     });
254     updatepref = JvSwingUtils.makeButton(
255             MessageManager.getString("action.update"),
256             MessageManager.getString("label.update_user_parameter_set"),
257             new ActionListener()
258             {
259
260               @Override
261               public void actionPerformed(ActionEvent e)
262               {
263                 update_actionPerformed();
264               }
265             });
266     deletepref = JvSwingUtils.makeButton(
267             MessageManager.getString("action.delete"),
268             MessageManager.getString("label.delete_user_parameter_set"),
269             new ActionListener()
270             {
271
272               @Override
273               public void actionPerformed(ActionEvent e)
274               {
275                 delete_actionPerformed();
276               }
277             });
278     createpref = JvSwingUtils.makeButton(
279             MessageManager.getString("action.create"),
280             MessageManager.getString("label.create_user_parameter_set"),
281             new ActionListener()
282             {
283
284               @Override
285               public void actionPerformed(ActionEvent e)
286               {
287                 create_actionPerformed();
288               }
289             });
290     revertpref = JvSwingUtils.makeButton(
291             MessageManager.getString("action.revert"),
292             MessageManager
293                     .getString("label.revert_changes_user_parameter_set"),
294             new ActionListener()
295             {
296
297               @Override
298               public void actionPerformed(ActionEvent e)
299               {
300                 revert_actionPerformed();
301               }
302             });
303
304     JButton startjob = JvSwingUtils.makeButton(
305             MessageManager.getString("action.start_job"),
306             MessageManager.getString("label.start_job_current_settings"),
307             new ActionListener()
308             {
309               @Override
310               public void actionPerformed(ActionEvent e)
311               {
312                 startjob_actionPerformed();
313               }
314             });
315     JButton canceljob = JvSwingUtils.makeButton(
316             MessageManager.getString("action.cancel_job"),
317             MessageManager.getString("label.cancel_job_close_dialog"),
318             new ActionListener()
319             {
320               @Override
321               public void actionPerformed(ActionEvent e)
322               {
323                 canceljob_actionPerformed();
324               }
325             });
326
327     JPanel setDetails = new JPanel();
328     setDetails.setBorder(
329             new TitledBorder(MessageManager.getString("label.details")));
330     setDetails.setLayout(new BorderLayout());
331     setDescr.setColumns(40);
332     setDescr.setWrapStyleWord(true);
333     setDescr.setLineWrap(true);
334     setDescr.setBackground(getBackground());
335     setDescr.setEditable(true);
336     setDescr.getDocument().addDocumentListener(this);
337     setDescr.setToolTipText(
338             MessageManager.getString("label.edit_notes_parameter_set"));
339     JScrollPane setDescrView = new JScrollPane();
340     setDescrView.getViewport().setView(setDescr);
341     setName.setEditable(true);
342     setName.addItemListener(this);
343     setName.getEditor().addActionListener(this);
344     JPanel setNameInfo = new JPanel(new FlowLayout(FlowLayout.LEFT));
345     GridBagLayout gbl = new GridBagLayout();
346     setNamePanel.setLayout(gbl);
347
348     JLabel setNameLabel = new JLabel(
349             MessageManager.getString("label.current_parameter_set_name"));
350     setNameLabel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
351
352     setNameInfo.add(setNameLabel);
353     setNameInfo.add(setName);
354
355     // initial button visibility
356     updatepref.setVisible(false);
357     deletepref.setVisible(false);
358     revertpref.setVisible(false);
359     createpref.setVisible(false);
360     JPanel setsavebuts = new JPanel();
361     setsavebuts.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0)); // GridLayout(1,2));
362     JPanel spacer = new JPanel();
363     spacer.setPreferredSize(new Dimension(2, 30));
364     setsavebuts.add(spacer);
365     setsavebuts.add(deletepref);
366     setsavebuts.add(revertpref);
367     setsavebuts.add(createpref);
368     setsavebuts.add(updatepref);
369     // setsavebuts.setSize(new Dimension(150, 30));
370     JPanel buttonArea = new JPanel(new GridLayout(1, 1));
371     buttonArea.add(setsavebuts);
372     setNamePanel.add(setNameInfo);
373     GridBagConstraints gbc = new GridBagConstraints();
374     gbc.gridheight = 2;
375     gbl.setConstraints(setNameInfo, gbc);
376     setNamePanel.add(buttonArea);
377     gbc = new GridBagConstraints();
378     gbc.gridx = 0;
379     gbc.gridy = 2;
380     gbc.gridheight = 1;
381     gbl.setConstraints(buttonArea, gbc);
382     setDetails.add(setDescrView, BorderLayout.CENTER);
383
384     // paramPane.setPreferredSize(new Dimension(360, 400));
385     // paramPane.setPreferredSize(null);
386     optionsPanel.setBorder(
387             new TitledBorder(MessageManager.getString("label.options")));
388     optionsPanel.setOpaque(true);
389     paramsPanel.setBorder(
390             new TitledBorder(MessageManager.getString("label.parameters")));
391     paramsPanel.setOpaque(true);
392     // optsAndparams.setScrollableWidth(ScrollableSizeHint.FIT);
393     // optsAndparams.setScrollableHeight(ScrollableSizeHint.NONE);
394     // optsAndparams.setLayout(new BorderLayout());
395     JPanel optsAndparams = new JPanel();
396     optsAndparams.setLayout(new BorderLayout());
397     optsAndparams.add(optionsPanel, BorderLayout.NORTH);
398     optsAndparams.add(paramsPanel, BorderLayout.CENTER);
399     JPanel jp = new JPanel(new BorderLayout());
400     jp.add(optsAndparams, BorderLayout.CENTER);
401     paramPane.getViewport().setView(jp);
402     paramPane.setBorder(null);
403     setLayout(new BorderLayout());
404
405     JPanel jobPanel = new JPanel();
406     jobPanel.setPreferredSize(null);
407     jobPanel.setLayout(new BorderLayout());
408     jobPanel.add(setDetails, BorderLayout.NORTH);
409     jobPanel.add(paramPane, BorderLayout.CENTER);
410     // jobPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
411
412     add(setNamePanel, BorderLayout.NORTH);
413     add(jobPanel, BorderLayout.CENTER);
414
415     JPanel dialogpanel = new JPanel();
416     dialogpanel.add(startjob);
417     dialogpanel.add(canceljob);
418     // JAL-1580: setMaximumSize() doesn't work, so just size for the worst case:
419     // check for null is for JUnit usage
420     final int windowHeight = Desktop.getInstance() == null ? DEFAULT_HEIGHT
421             : Desktop.getInstance().getHeight();
422     setPreferredSize(new Dimension(540, windowHeight));
423     add(dialogpanel, BorderLayout.SOUTH);
424     validate();
425   }
426
427   protected void revert_actionPerformed()
428   {
429     reInitDialog(lastParmSet);
430     updateWebServiceMenus();
431   }
432
433   protected void update_actionPerformed()
434   {
435     if (isUserPreset)
436     {
437       String curname = ((String) setName.getSelectedItem()).trim();
438       _updatePreset(lastParmSet, curname);
439       lastParmSet = curname;
440       isUserPreset = true;
441       initArgSetModified();
442       syncSetNamesWithStore();
443     }
444   }
445
446   private void _deleteUserPreset(String lastParmSet2)
447   {
448     paramStore.deletePreset(lastParmSet2);
449   }
450
451   protected void delete_actionPerformed()
452   {
453     if (isUserPreset)
454     {
455       // delete current preset's saved entry
456       _deleteUserPreset(lastParmSet);
457     }
458     reInitDialog(null); // service default
459     updateWebServiceMenus();
460   }
461
462   protected void create_actionPerformed()
463   {
464     String curname = ((String) setName.getSelectedItem()).trim();
465     if (curname.length() > 0)
466     {
467       _storeCurrentPreset(curname);
468       lastParmSet = curname;
469       isUserPreset = true;
470       reInitDialog(curname);
471       initArgSetModified();
472       updateWebServiceMenus();
473     }
474     else
475     {
476       // TODO: show warning
477       System.err.println("Invalid name. Not saved.");
478     }
479   }
480
481   protected void canceljob_actionPerformed()
482   {
483     startJob = false;
484     if (frame != null)
485     {
486       frame.setVisible(false);
487     }
488   }
489
490   protected void startjob_actionPerformed()
491   {
492     startJob = true;
493     if (frame != null)
494     {
495       frame.setVisible(false);
496     }
497   }
498
499   void initForService(WsParamSetI paramSet, List<ArgumentI> jobArgset)
500   {
501     settingDialog = true;
502
503     init(paramSet, jobArgset);
504
505   }
506
507   void init(WsParamSetI p, List<ArgumentI> jobArgset)
508   {
509     Hashtable<String, String> exnames = new Hashtable<>();
510     for (int i = 0, iSize = setName.getItemCount(); i < iSize; i++)
511     {
512       exnames.put(setName.getItemAt(i), setName.getItemAt(i));
513     }
514     servicePresets = new Hashtable<>();
515     // Add the default entry - if not present already.
516     if (!exnames.contains(SVC_DEF))
517     {
518       setName.addItem(SVC_DEF);
519       exnames.put(SVC_DEF, SVC_DEF);
520       servicePresets.put(SVC_DEF, SVC_DEF);
521     }
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   private void updateTable(WsParamSetI p, List<ArgumentI> jobArgset)
566   {
567     boolean setDefaultParams = false;
568     if (lastParmSet == null)
569     {
570       isUserPreset = false;
571       // First call - so provide Service default settings
572       setName.setSelectedItem(lastSetName = SVC_DEF);
573     }
574     if (p == null && SVC_DEF.equals("" + setName.getSelectedItem()))
575     {
576       // indicate that service defaults should be set if available
577       setDefaultParams = true;
578     }
579     // populate table from default parameter set.
580     List<ArgumentI> args = paramStore.getServiceParameters();
581
582     // split to params and required arguments
583     {
584       int cw = 0;
585       boolean optset = false;
586       for (ArgumentI myarg : args)
587       {
588         // Ideally, Argument would implement isRequired !
589         if (myarg instanceof ParameterI)
590         {
591           ParameterI parm = (ParameterI) myarg;
592           opanp.addParameter(parm).validate();
593         }
594         else
595         {
596           if (myarg instanceof OptionI)
597           {
598             OptionI opt = (OptionI) myarg;
599             OptionBox ob = opanp.addOption(opt);
600             ob.resetToDefault(setDefaultParams);
601             if (maxOptWidth < ob.getPreferredSize().width)
602             {
603               maxOptWidth = ob.getPreferredSize().width;
604             }
605             ob.validate();
606             cw += ob.getPreferredSize().width + 5;
607           }
608           else
609           {
610             System.err.println("Ignoring unknown service argument type "
611                     + myarg.getClass().getName());
612           }
613         }
614       }
615       args = null; // no more args to process.
616     }
617     if (p != null)
618     {
619       isUserPreset = false;
620       // initialise setname
621       setName.setSelectedItem(lastSetName = p.getName());
622       setDescr.setText(lastDescrText = p.getDescription());
623       // TODO - URL link
624       try
625       {
626         args = p.getArguments();
627       } catch (Exception e)
628       {
629         e.printStackTrace();
630       }
631       // TODO: check if args should be unselected prior to resetting using the
632       // preset
633     }
634
635     if (jobArgset != null)
636     {
637       argSetModified(jobArgset, true);
638       args = jobArgset;
639     }
640     // get setargs from current object
641     if (args != null)
642     {
643       for (ArgumentI arg : args)
644       {
645         if (arg instanceof ParameterI)
646         {
647           opanp.setParameter((ParameterI) arg);
648         }
649         else
650         {
651           if (arg instanceof OptionI)
652           {
653             // System.out.println("Setting option "
654             // + System.identityHashCode(arg) + ":" + arg.getName()
655             // + " with " + arg.getDefaultValue());
656             opanp.selectOption((OptionI) arg, arg.getValue());
657           }
658         }
659
660       }
661     }
662
663     refreshParamLayout();
664     revalidate();
665   }
666
667   private boolean isModified()
668   {
669     return modifiedElements.size() > 0;
670   }
671
672   /**
673    * reset gui and modification state settings
674    */
675   private void initArgSetModified()
676   {
677     curSetName = null;
678     modifiedElements.clear();
679     updateButtonDisplay();
680   }
681
682   private void updateButtonDisplay()
683   {
684     boolean _update = false, _create = false, _delete = false,
685             _revert = false;
686     if (modifiedElements.size() > 0)
687     {
688       // set modified
689       _revert = true;
690       _update = isUserPreset; // can only update user presets
691       if (!isUserPreset || modifiedElements.containsKey(setName))
692       {
693         // name modified - can create new preset
694         _create = true;
695       }
696     }
697     else
698     {
699       // set unmodified
700     }
701     // can still delete a user preset
702     _delete = isUserPreset;
703
704     createpref.setVisible(_create);
705     updatepref.setVisible(_update);
706     deletepref.setVisible(_delete);
707     revertpref.setVisible(_revert);
708     validate();
709   }
710
711   @Override
712   public void argSetModified(Object modifiedElement, boolean b)
713   {
714     if (settingDialog)
715     {
716       return;
717     }
718     if (!b)
719     {
720       modifiedElements.remove(modifiedElement);
721     }
722     else
723     {
724       if (b && modifiedElement == setName
725               && modifiedElements.contains(modifiedElement))
726       {
727         // HACK! prevents iteration on makeSetNameValid
728         b = false;
729       }
730       modifiedElements.put(modifiedElement, modifiedElement);
731     }
732     // set mod status based on presence of elements in table
733     if (b && modifiedElements.size() > 0)
734     {
735       makeSetNameValid(!isUserPreset);
736       setNamePanel.revalidate();
737     }
738     updateButtonDisplay();
739   }
740
741   private boolean isServicePreset(String selectedItem)
742   {
743     return selectedItem.equals(SVC_DEF)
744             || servicePresets.containsKey(selectedItem);
745   }
746
747   /**
748    * check if the current set name is a valid set name for saving, if not, then
749    * fix it.
750    */
751   private void makeSetNameValid(boolean newuserset)
752   {
753     boolean stn = settingDialog;
754     boolean renamed = false;
755     settingDialog = true;
756     String nm = (curSetName != null ? curSetName
757             : (String) setName.getSelectedItem());
758     // check if the name is reserved - if it is, rename it.
759     if (isServicePreset(nm))
760     {
761       nm = "User " + nm;
762       renamed = true;
763     }
764     String tnm = nm;
765     if (newuserset)
766     {
767       int i = 0;
768       while (paramStore.getPreset(tnm) != null)
769       {
770         tnm = nm + " (" + (++i) + ")";
771         renamed = true;
772       }
773       if (i > 0)
774       {
775         nm = tnm;
776       }
777     }
778
779     boolean makeupdate = false;
780     // sync the gui with the preset database
781     for (int i = 0, iS = setName.getItemCount(); i < iS; i++)
782     {
783       String snm = setName.getItemAt(i);
784       if (snm.equals(nm))
785       {
786         makeupdate = true;
787         // setName.setSelectedIndex(i);
788       }
789     }
790     if (!makeupdate)
791     {
792       setName.addItem(curSetName = nm);
793       setName.setSelectedItem(curSetName);
794     }
795     if (renamed)
796     {
797       settingDialog = false; // we need this name change to be registered.
798       argSetModified(setName, renamed);
799     }
800     settingDialog = stn;
801   }
802
803   /**
804    * Rebuilds the Options and Parameters panels
805    */
806   @Override
807   public void refreshParamLayout()
808   {
809     final int rightMargin = 40;
810     final int availableWidth = paramPane.getViewport().getSize().width
811             - rightMargin
812             - optionsPanel.getBorder().getBorderInsets(optionsPanel).left
813             + optionsPanel.getBorder().getBorderInsets(optionsPanel).right;
814
815     if (opanp.getOptSet().size() > 0)
816     {
817       int hgap = 5;
818       int currentWidth = hgap;
819
820       /*
821        * layout constraint 'nogrid' prevents vertical column alignment,
822        * allowing controls to flow without extra space inserted to align
823        */
824       optionsPanel.setLayout(new MigLayout("nogrid", "", ""));
825       optionsPanel.removeAll();
826       JPanel lastAdded = null;
827
828       /*
829        * add each control in turn; if adding would overflow the right margin,
830        * remove and re-add the previous parameter with "wrap" (after) 
831        * in order to start a new row
832        */
833       for (OptionBox pbox : opanp.getOptSet().values())
834       {
835         pbox.validate();
836         int boxWidth = pbox.getSize().width;
837         currentWidth += boxWidth + hgap;
838         boolean wrapAfterLast = currentWidth > availableWidth
839                 && lastAdded != null;
840         // System.out.println(String.format(
841         // "%s width=%d, paneWidth=%d, currentWidth=%d, wrapAfterLast=%s",
842         // pbox.toString(), boxWidth, panewidth, currentWidth,
843         // wrapAfterLast));
844         if (wrapAfterLast)
845         {
846           optionsPanel.remove(lastAdded);
847           optionsPanel.add(lastAdded, "wrap");
848           currentWidth = hgap + boxWidth;
849         }
850         optionsPanel.add(pbox);
851         lastAdded = pbox;
852       }
853       optionsPanel.revalidate();
854     }
855     else
856     {
857       optionsPanel.setVisible(false);
858     }
859
860     if (opanp.getParamSet().size() > 0)
861     {
862       paramsPanel.removeAll();
863       paramsPanel.setLayout(new MigLayout("", "", ""));
864       int hgap = 5;
865       int currentWidth = hgap;
866
867       JPanel lastAdded = null;
868       for (ParamBox pbox : opanp.getParamSet().values())
869       {
870         pbox.validate();
871         int boxWidth = pbox.getSize().width;
872         currentWidth += boxWidth + hgap;
873         boolean wrapAfterLast = currentWidth > availableWidth
874                 && lastAdded != null;
875         if (wrapAfterLast)
876         {
877           paramsPanel.remove(lastAdded);
878           paramsPanel.add(lastAdded, "wrap");
879           currentWidth = pbox.getSize().width + hgap;
880         }
881         paramsPanel.add(pbox);
882         lastAdded = pbox;
883       }
884
885       /*
886        * s = 2 * sep; for (ParamBox pbox : opanp.getParamSet().values()) {
887        * pbox.validate(); s += sep +
888        * pbox.getPreferredSize().height+pbox.getBorder
889        * ().getBorderInsets(pbox).bottom; }
890        * 
891        * // paramList.setPreferredSize(new Dimension(w, s));
892        * os+=s+2*sep+paramList
893        * .getBorder().getBorderInsets(paramList).bottom+paramList
894        * .getBorder().getBorderInsets(paramList).top;
895        */
896       paramsPanel.revalidate();
897     }
898     else
899     {
900       paramsPanel.setVisible(false);
901     }
902     // TODO: waste some time trying to eliminate any unnecessary .validate calls
903     // here
904     // System.out.println("Size will be : "+w+","+os);
905     // optsAndparams.setPreferredSize(null);
906     // paramPane.getViewport().setView(optsAndparams);
907     paramPane.getViewport().setAutoscrolls(true);
908     paramPane.revalidate();
909     revalidate();
910   }
911   public boolean isServiceDefaults()
912   {
913     return (!isModified()
914             && (lastParmSet != null && lastParmSet.equals(SVC_DEF)));
915   }
916
917   public List<ArgumentI> getJobParams()
918   {
919     return opanp.getCurrentSettings();
920   }
921
922   /*
923    * Hashtable<String, Object[]> editedParams = new Hashtable<String,
924    * Object[]>();
925    * 
926    * store the given parameters in the user parameter set database.
927    * 
928    * @param storeSetName - lastParmSet
929    * 
930    * @param descr - setDescr.getText()
931    * 
932    * @param jobParams - getJobParams()
933    * 
934    * private void _storeUserPreset(String storeSetName, String descr,
935    * List<ArgumentI> jobParams) { // this is a simple hash store. Object[] pset;
936    * editedParams.put(storeSetName, pset = new Object[3]); pset[0] =
937    * storeSetName; pset[1] = descr; pset[2] = jobParams; // writeParam("Saving "
938    * + storeSetName + ": ", jobParams); }
939    * 
940    * private void writeParam(String nm, List<ArgumentI> params) { for (ArgumentI
941    * p : params) { System.out.println(nm + ":" + System.identityHashCode(p) +
942    * " Name: " + p.getName() + " Value: " + p.getDefaultValue()); } }
943    * 
944    * private Object[] _getUserPreset(String setName) { Object[] pset =
945    * editedParams.get(setName); // if (pset != null) // writeParam("Retrieving "
946    * + setName + ": ", (List<Argument>) pset[2]); return pset; }
947    * 
948    * * remove the given user preset from the preset stash
949    * 
950    * @param setName
951    * 
952    * private void _deleteUserPreset(String setName) {
953    * editedParams.remove(setName); }
954    */
955
956   private void syncSetNamesWithStore()
957   {
958     int n = 0;
959     // remove any set names in the drop down menu that aren't either a reserved
960     // setting, or a user defined or service preset.
961     Vector<String> items = new Vector<>();
962     while (n < setName.getItemCount())
963     {
964       String item = setName.getItemAt(n);
965       if (!item.equals(SVC_DEF) && !paramStore.presetExists(item))
966       {
967         setName.removeItemAt(n);
968       }
969       else
970       {
971         items.addElement(item);
972         n++;
973       }
974     }
975     if (!items.contains(SVC_DEF))
976     {
977       setName.addItem(SVC_DEF);
978     }
979     for (WsParamSetI upn : paramStore.getPresets())
980     {
981       if (!items.contains(upn.getName()))
982       {
983         setName.addItem(upn.getName());
984       }
985     }
986   }
987
988   /**
989    * true if lastParmSet is a user preset
990    */
991   boolean isUserPreset = false;
992
993   private void reInitDialog(String nextPreset)
994   {
995     settingDialog = true;
996     // updateTable(null,null); // first reset to defaults
997     WsParamSetI pset = null;
998     if (nextPreset != null && nextPreset.length() > 0)
999     {
1000       pset = paramStore.getPreset(nextPreset);
1001     }
1002     if (pset != null)
1003     {
1004       if (pset.isModifiable())
1005       {
1006         isUserPreset = true;
1007         setDescr.setText(pset.getDescription());
1008         updateTable(null, pset.getArguments());
1009         lastParmSet = nextPreset;
1010       }
1011       else
1012       {
1013         isUserPreset = false;
1014         setDescr.setText("");
1015         // must be a default preset from service
1016         updateTable(pset, null);
1017         lastParmSet = nextPreset;
1018       }
1019     }
1020     else
1021     {
1022       isUserPreset = false;
1023       // Service defaults
1024       setDescr.setText("");
1025       updateTable(null, null);
1026       lastParmSet = SVC_DEF;
1027     }
1028
1029     initArgSetModified();
1030     syncSetNamesWithStore();
1031     setName.setSelectedItem(lastParmSet);
1032     setNamePanel.validate();
1033     validate();
1034     settingDialog = false;
1035   }
1036
1037   /**
1038    * Rebuild the AlignFrame web service menus (after add/delete of a preset
1039    * option).
1040    */
1041   protected void updateWebServiceMenus()
1042   {
1043     if (Desktop.getInstance() == null)
1044     {
1045       return;
1046     }
1047     for (AlignFrame alignFrame : Desktop.getAlignFrames())
1048     {
1049       alignFrame.buildWebServicesMenu();
1050     }
1051   }
1052
1053   String curSetName = null;
1054
1055   @Override
1056   public void itemStateChanged(ItemEvent e)
1057   {
1058     if (e.getSource() == setName
1059             && e.getStateChange() == ItemEvent.SELECTED)
1060     {
1061       final String setname = (String) setName.getSelectedItem();
1062       // System.out.println("Item state changed for " + setname
1063       // + " (handling ? " + !settingDialog + ")");
1064       if (settingDialog)
1065       {
1066         // ignore event
1067         return;
1068       }
1069       if (setname == null)
1070       {
1071         return;
1072       }
1073       javax.swing.SwingUtilities.invokeLater(new Runnable()
1074       {
1075         @Override
1076         public void run()
1077         {
1078           doPreferenceComboStateChange(setname);
1079         }
1080       });
1081     }
1082   }
1083
1084   private void doPreferenceComboStateChange(String setname)
1085   {
1086     // user has selected a different item from combo-box
1087     if (isModified())
1088     {
1089       String lsetname = (curSetName != null) ? curSetName : lastParmSet;
1090       if (lsetname.equals(setname))
1091       {
1092         // setname was just edited - so ignore this event.
1093         return;
1094       }
1095       settingDialog = true;
1096       System.out.println("Prompting to save " + lsetname);
1097       if (JvOptionPane.showConfirmDialog(this, "Parameter set '" + lsetname
1098               + "' is modifed, and your changes will be lost.\nReally change preset ?",
1099               "Warning: Unsaved Changes",
1100               JvOptionPane.OK_CANCEL_OPTION) != JvOptionPane.OK_OPTION)
1101       {
1102         // revert the combobox to the current item
1103         settingDialog = true;
1104         setName.setSelectedItem(lsetname);
1105         settingDialog = false;
1106         // and leave.
1107         return;
1108         // System.out.println("Saving for " + lsetname);
1109         // _storeCurrentPreset(lsetname);
1110
1111       }
1112     }
1113     settingDialog = true;
1114     reInitDialog(setname);
1115     settingDialog = false;
1116
1117   }
1118
1119   /**
1120    * store current settings as given name. You should then reset gui.
1121    * 
1122    * @param curSetName2
1123    */
1124   private void _storeCurrentPreset(String curSetName2)
1125   {
1126     paramStore.storePreset(curSetName2, setDescr.getText(), getJobParams());
1127   }
1128
1129   private void _updatePreset(String lastParmSet2, String curname)
1130   {
1131     paramStore.updatePreset(lastParmSet2, curname, setDescr.getText(),
1132             getJobParams());
1133
1134   }
1135
1136   /**
1137    * last saved name for this user preset
1138    */
1139   String lastSetName = null;
1140
1141   /**
1142    * last saved value of the description text for this user preset
1143    */
1144   String lastDescrText = null;
1145
1146   @Override
1147   public void actionPerformed(ActionEvent e)
1148   {
1149     if (e.getSource() instanceof Component)
1150     {
1151       Component src = (Component) e.getSource();
1152       if (src.getParent() == setName)
1153       {
1154         // rename any existing records we know about for this set.
1155         String newname = e.getActionCommand().trim();
1156         String msg = null;
1157         if (isServicePreset(newname))
1158         {
1159           final String oldname = curSetName != null ? curSetName
1160                   : lastParmSet;
1161           final Component ourframe = this;
1162           settingDialog = true;
1163           setName.getEditor().setItem(oldname);
1164           settingDialog = false;
1165           javax.swing.SwingUtilities.invokeLater(new Runnable()
1166           {
1167             @Override
1168             public void run()
1169             {
1170               JvOptionPane.showMessageDialog(ourframe,
1171                       MessageManager.getString(
1172                               "label.invalid_name_preset_exists"),
1173                       MessageManager.getString("label.invalid_name"),
1174                       JvOptionPane.WARNING_MESSAGE);
1175             }
1176           });
1177
1178           return;
1179         }
1180         curSetName = newname;
1181         System.err.println("New name for user setting " + curSetName
1182                 + " (was " + setName.getSelectedItem() + ")");
1183         if (curSetName.equals(setName.getSelectedItem()))
1184         {
1185           curSetName = null;
1186         }
1187         if (curSetName != null)
1188         {
1189           argSetModified(setName, true);
1190           return;
1191         }
1192
1193       }
1194     }
1195   }
1196
1197   private void checkDescrModified()
1198   {
1199     if (!settingDialog)
1200     {
1201
1202       argSetModified(setDescr,
1203               (lastDescrText == null
1204                       ? setDescr.getText().trim().length() > 0
1205                       : !setDescr.getText().equals(lastDescrText)));
1206
1207     }
1208   }
1209
1210   @Override
1211   public void insertUpdate(DocumentEvent e)
1212   {
1213     checkDescrModified();
1214   }
1215
1216   @Override
1217   public void removeUpdate(DocumentEvent e)
1218   {
1219     checkDescrModified();
1220   }
1221
1222   @Override
1223   public void changedUpdate(DocumentEvent e)
1224   {
1225     checkDescrModified();
1226   }
1227
1228   /**
1229    * 
1230    * @return null or the service preset selected by the user
1231    */
1232   public WsParamSetI getPreset()
1233   {
1234     if (isUserPreset || isModified()
1235             || (lastParmSet != null && lastParmSet.equals(SVC_DEF)))
1236     {
1237       return null;
1238     }
1239     else
1240     {
1241       return paramStore.getPreset(lastParmSet);
1242     }
1243   }
1244 }