3e09a35d6272ac4e433afee21b5842831061c3c4
[jalview.git] / src / jalview / gui / OptsAndParamsPage.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 static jalview.ws.params.simple.LogarithmicParameter.LOGSLIDERSCALE;
24
25 import jalview.util.MessageManager;
26 import jalview.ws.params.ArgumentI;
27 import jalview.ws.params.OptionI;
28 import jalview.ws.params.ParameterI;
29 import jalview.ws.params.ValueConstrainI;
30 import jalview.ws.params.ValueConstrainI.ValueType;
31 import jalview.ws.params.simple.LogarithmicParameter;
32
33 import java.awt.BorderLayout;
34 import java.awt.Component;
35 import java.awt.Dimension;
36 import java.awt.Font;
37 import java.awt.GridLayout;
38 import java.awt.Rectangle;
39 import java.awt.event.ActionEvent;
40 import java.awt.event.ActionListener;
41 import java.awt.event.KeyAdapter;
42 import java.awt.event.KeyEvent;
43 import java.awt.event.MouseEvent;
44 import java.awt.event.MouseListener;
45 import java.net.URL;
46 import java.util.ArrayList;
47 import java.util.LinkedHashMap;
48 import java.util.List;
49 import java.util.Map;
50
51 import javax.swing.JButton;
52 import javax.swing.JCheckBox;
53 import javax.swing.JComboBox;
54 import javax.swing.JComponent;
55 import javax.swing.JLabel;
56 import javax.swing.JMenuItem;
57 import javax.swing.JPanel;
58 import javax.swing.JPopupMenu;
59 import javax.swing.JScrollPane;
60 import javax.swing.JSlider;
61 import javax.swing.JTextArea;
62 import javax.swing.JTextField;
63 import javax.swing.border.TitledBorder;
64 import javax.swing.event.ChangeEvent;
65 import javax.swing.event.ChangeListener;
66
67 import net.miginfocom.swing.MigLayout;
68
69 /**
70  * GUI generator/manager for options and parameters. Originally abstracted from
71  * the WsJobParameters dialog box.
72  * 
73  * @author jprocter
74  * 
75  */
76 public class OptsAndParamsPage
77 {
78   public static final int PARAM_WIDTH = 340;
79
80   public static final int PARAM_HEIGHT = 150;
81
82   public static final int PARAM_CLOSEDHEIGHT = 80;
83
84   URL linkImageURL = getClass().getResource("/images/link.gif");
85
86   Map<String, OptionBox> optSet = new LinkedHashMap<>();
87
88   Map<String, ParamBox> paramSet = new LinkedHashMap<>();
89
90   /*
91    * compact or verbose style parameters
92    */
93   boolean compact = false;
94
95   OptsParametersContainerI poparent;
96
97   /**
98    * A class that models a panel rendering a single option (checkbox or choice
99    * list)
100    */
101   public class OptionBox extends JPanel
102           implements MouseListener, ActionListener
103   {
104     JCheckBox enabled = new JCheckBox();
105
106     final URL finfo;
107
108     boolean hasLink = false;
109
110     boolean initEnabled = false;
111
112     String initVal = null;
113
114     OptionI option;
115
116     JLabel optlabel = new JLabel();
117
118     JComboBox<String> val = new JComboBox<>();
119
120     public OptionBox(OptionI opt)
121     {
122       option = opt;
123       setLayout(new BorderLayout());
124       enabled.setSelected(opt.isRequired()); // TODO: lock required options
125       // enabled.setEnabled(!opt.isRequired());
126       enabled.setFont(new Font("Verdana", Font.PLAIN, 11));
127       enabled.setText("");
128       enabled.setText(opt.getName());
129       enabled.addActionListener(this);
130       finfo = option.getFurtherDetails();
131       String desc = opt.getDescription();
132       if (finfo != null)
133       {
134         hasLink = true;
135
136         enabled.setToolTipText(JvSwingUtils.wrapTooltip(true,
137                 ((desc == null || desc.trim().length() == 0)
138                         ? MessageManager.getString(
139                                 "label.opt_and_params_further_details")
140                         : desc) + "<br><img src=\"" + linkImageURL
141                         + "\"/>"));
142         enabled.addMouseListener(this);
143       }
144       else
145       {
146         if (desc != null && desc.trim().length() > 0)
147         {
148           enabled.setToolTipText(
149                   JvSwingUtils.wrapTooltip(true, opt.getDescription()));
150         }
151       }
152       add(enabled, BorderLayout.NORTH);
153       for (String str : opt.getPossibleValues())
154       {
155         val.addItem(str);
156       }
157       val.setSelectedItem(opt.getValue());
158       if (opt.getPossibleValues().size() > 1)
159       {
160         setLayout(new GridLayout(1, 2));
161         val.addActionListener(this);
162         add(val, BorderLayout.SOUTH);
163       }
164       // TODO: add actionListeners for popup (to open further info),
165       // and to update list of parameters if an option is enabled
166       // that takes a value. JBPNote: is this TODO still valid ?
167       setInitialValue();
168     }
169
170     @Override
171     public void actionPerformed(ActionEvent e)
172     {
173       if (e.getSource() != enabled)
174       {
175         enabled.setSelected(true);
176       }
177       checkIfModified();
178     }
179
180     private void checkIfModified()
181     {
182       boolean notmod = (initEnabled == enabled.isSelected());
183       if (enabled.isSelected())
184       {
185         if (initVal != null)
186         {
187           notmod &= initVal.equals(val.getSelectedItem());
188         }
189         else
190         {
191           // compare against default service setting
192           notmod &= option.getValue() == null
193                   || option.getValue().equals(val.getSelectedItem());
194         }
195       }
196       else
197       {
198         notmod &= (initVal != null) ? initVal.equals(val.getSelectedItem())
199                 : val.getSelectedItem() != initVal;
200       }
201       poparent.argSetModified(this, !notmod);
202     }
203
204     public OptionI getOptionIfEnabled()
205     {
206       if (!enabled.isSelected())
207       {
208         return null;
209       }
210       OptionI opt = option.copy();
211       if (opt.getPossibleValues() != null
212               && opt.getPossibleValues().size() == 1)
213       {
214         // Hack to make sure the default value for an enabled option with only
215         // one value is actually returned
216         opt.setValue(opt.getPossibleValues().get(0));
217       }
218       if (val.getSelectedItem() != null)
219       {
220         opt.setValue((String) val.getSelectedItem());
221       }
222       else
223       {
224         if (option.getValue() != null)
225         {
226           opt.setValue(option.getValue());
227         }
228       }
229       return opt;
230     }
231
232     @Override
233     public void mouseClicked(MouseEvent e)
234     {
235       if (e.isPopupTrigger()) // for Windows
236       {
237         showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
238       }
239     }
240
241     @Override
242     public void mouseEntered(MouseEvent e)
243     {
244       // TODO Auto-generated method stub
245
246     }
247
248     @Override
249     public void mouseExited(MouseEvent e)
250     {
251       // TODO Auto-generated method stub
252
253     }
254
255     @Override
256     public void mousePressed(MouseEvent e)
257     {
258       if (e.isPopupTrigger()) // Mac
259       {
260         showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
261       }
262     }
263
264     @Override
265     public void mouseReleased(MouseEvent e)
266     {
267     }
268
269     public void resetToDefault(boolean setDefaultParams)
270     {
271       enabled.setSelected(false);
272       if (option.isRequired()
273               || (setDefaultParams && option.getValue() != null))
274       {
275         // Apply default value
276         selectOption(option, option.getValue());
277       }
278     }
279
280     public void setInitialValue()
281     {
282       initEnabled = enabled.isSelected();
283       if (option.getPossibleValues() != null
284               && option.getPossibleValues().size() > 1)
285       {
286         initVal = (String) val.getSelectedItem();
287       }
288       else
289       {
290         initVal = (initEnabled) ? (String) val.getSelectedItem() : null;
291       }
292     }
293
294   }
295
296   /**
297    * A class that models a panel rendering a single parameter
298    */
299   public class ParamBox extends JPanel
300           implements ChangeListener, ActionListener, MouseListener
301   {
302     private static final float SLIDERSCALE = 1000f;
303
304     boolean isLogarithmic;
305
306     boolean adjusting = false;
307
308     boolean choice = false;
309
310     JComboBox<String> choicebox;
311
312     JPanel controlPanel = new JPanel();
313
314     boolean descisvisible = false;
315
316     JScrollPane descPanel = new JScrollPane();
317
318     final URL finfo;
319
320     boolean integ = false;
321
322     Object lastVal;
323
324     ParameterI parameter;
325
326     final OptsParametersContainerI pmdialogbox;
327
328     JPanel settingPanel = new JPanel();
329
330     JButton showDesc = new JButton();
331
332     JSlider slider = null;
333
334     JTextArea string = new JTextArea();
335
336     ValueConstrainI validator = null;
337
338     JTextField valueField = null;
339
340     public ParamBox(final OptsParametersContainerI pmlayout,
341             ParameterI parm)
342     {
343       pmdialogbox = pmlayout;
344       finfo = parm.getFurtherDetails();
345       validator = parm.getValidValue();
346       parameter = parm;
347       if (validator != null)
348       {
349         integ = validator.getType() == ValueType.Integer;
350       }
351       else
352       {
353         if (parameter.getPossibleValues() != null)
354         {
355           choice = true;
356         }
357       }
358       if (parm instanceof LogarithmicParameter)
359       {
360         isLogarithmic = true;
361       }
362
363       if (!compact)
364       {
365         makeExpanderParam(parm);
366       }
367       else
368       {
369         makeCompactParam(parm);
370
371       }
372     }
373
374     private void makeCompactParam(ParameterI parm)
375     {
376       setLayout(new MigLayout("", "[][grow]"));
377
378       String ttipText = null;
379
380       controlPanel.setLayout(new BorderLayout());
381
382       if (parm.getDescription() != null
383               && parm.getDescription().trim().length() > 0)
384       {
385         // Only create description boxes if there actually is a description.
386         ttipText = (JvSwingUtils.wrapTooltip(true,
387                 parm.getDescription() + (finfo != null ? "<br><img src=\""
388                         + linkImageURL + "\"/>"
389                         + MessageManager.getString(
390                                 "label.opt_and_params_further_details")
391                         : "")));
392       }
393
394       JvSwingUtils.mgAddtoLayout(this, ttipText, new JLabel(parm.getName()),
395               controlPanel, "");
396       updateControls(parm);
397       validate();
398     }
399
400     private void makeExpanderParam(ParameterI parm)
401     {
402       setPreferredSize(new Dimension(PARAM_WIDTH, PARAM_CLOSEDHEIGHT));
403       setBorder(new TitledBorder(parm.getName()));
404       setLayout(null);
405       showDesc.setFont(new Font("Verdana", Font.PLAIN, 6));
406       showDesc.setText("+");
407       string.setFont(new Font("Verdana", Font.PLAIN, 11));
408       string.setBackground(getBackground());
409
410       string.setEditable(false);
411       descPanel.getViewport().setView(string);
412
413       descPanel.setVisible(false);
414
415       JPanel firstrow = new JPanel();
416       firstrow.setLayout(null);
417       controlPanel.setLayout(new BorderLayout());
418       controlPanel.setBounds(new Rectangle(39, 10, PARAM_WIDTH - 70,
419               PARAM_CLOSEDHEIGHT - 50));
420       firstrow.add(controlPanel);
421       firstrow.setBounds(new Rectangle(10, 20, PARAM_WIDTH - 30,
422               PARAM_CLOSEDHEIGHT - 30));
423
424       final ParamBox me = this;
425
426       if (parm.getDescription() != null
427               && parm.getDescription().trim().length() > 0)
428       {
429         // Only create description boxes if there actually is a description.
430         if (finfo != null)
431         {
432           showDesc.setToolTipText(JvSwingUtils.wrapTooltip(true,
433                   MessageManager.formatMessage(
434                           "label.opt_and_params_show_brief_desc_image_link",
435                           new String[]
436                           { linkImageURL.toExternalForm() })));
437           showDesc.addMouseListener(this);
438         }
439         else
440         {
441           showDesc.setToolTipText(
442                   JvSwingUtils.wrapTooltip(true, MessageManager.getString(
443                           "label.opt_and_params_show_brief_desc")));
444         }
445         showDesc.addActionListener(new ActionListener()
446         {
447
448           @Override
449           public void actionPerformed(ActionEvent e)
450           {
451             descisvisible = !descisvisible;
452             descPanel.setVisible(descisvisible);
453             descPanel.getVerticalScrollBar().setValue(0);
454             me.setPreferredSize(new Dimension(PARAM_WIDTH,
455                     (descisvisible) ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT));
456             me.validate();
457             pmdialogbox.refreshParamLayout();
458           }
459         });
460         string.setWrapStyleWord(true);
461         string.setLineWrap(true);
462         string.setColumns(32);
463         string.setText(parm.getDescription());
464         showDesc.setBounds(new Rectangle(10, 10, 16, 16));
465         firstrow.add(showDesc);
466       }
467       add(firstrow);
468       validator = parm.getValidValue();
469       parameter = parm;
470       if (validator != null)
471       {
472         integ = validator.getType() == ValueType.Integer;
473       }
474       else
475       {
476         if (parameter.getPossibleValues() != null)
477         {
478           choice = true;
479         }
480       }
481       updateControls(parm);
482       descPanel.setBounds(new Rectangle(10, PARAM_CLOSEDHEIGHT,
483               PARAM_WIDTH - 20, PARAM_HEIGHT - PARAM_CLOSEDHEIGHT - 5));
484       add(descPanel);
485       validate();
486     }
487
488     @Override
489     public void actionPerformed(ActionEvent e)
490     {
491       if (adjusting)
492       {
493         return;
494       }
495       if (!choice)
496       {
497         updateSliderFromValueField();
498       }
499       checkIfModified();
500     }
501
502     private void checkIfModified()
503     {
504       Object cstate = updateSliderFromValueField();
505       boolean notmod = false;
506       if (cstate.getClass() == lastVal.getClass())
507       {
508         if (cstate instanceof int[])
509         {
510           notmod = (((int[]) cstate)[0] == ((int[]) lastVal)[0]);
511         }
512         else if (cstate instanceof float[])
513         {
514           notmod = (((float[]) cstate)[0] == ((float[]) lastVal)[0]);
515         }
516         else if (cstate instanceof String[])
517         {
518           notmod = (((String[]) cstate)[0].equals(((String[]) lastVal)[0]));
519         }
520       }
521       pmdialogbox.argSetModified(this, !notmod);
522     }
523
524     @Override
525     public int getBaseline(int width, int height)
526     {
527       return 0;
528     }
529
530     // from
531     // http://stackoverflow.com/questions/2743177/top-alignment-for-flowlayout
532     // helpful hint of using the Java 1.6 alignBaseLine property of FlowLayout
533     @Override
534     public Component.BaselineResizeBehavior getBaselineResizeBehavior()
535     {
536       return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
537     }
538
539     public int getBoxHeight()
540     {
541       return (descisvisible ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT);
542     }
543
544     public ParameterI getParameter()
545     {
546       ParameterI prm = parameter.copy();
547       if (choice)
548       {
549         prm.setValue((String) choicebox.getSelectedItem());
550       }
551       else
552       {
553         prm.setValue(valueField.getText());
554       }
555       return prm;
556     }
557
558     public void init()
559     {
560       // reset the widget's initial value.
561       lastVal = null;
562     }
563
564     @Override
565     public void mouseClicked(MouseEvent e)
566     {
567       if (e.isPopupTrigger()) // for Windows
568       {
569         showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
570       }
571     }
572
573     @Override
574     public void mouseEntered(MouseEvent e)
575     {
576       // TODO Auto-generated method stub
577
578     }
579
580     @Override
581     public void mouseExited(MouseEvent e)
582     {
583       // TODO Auto-generated method stub
584
585     }
586
587     @Override
588     public void mousePressed(MouseEvent e)
589     {
590       if (e.isPopupTrigger()) // for Mac
591       {
592         showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
593       }
594     }
595
596     @Override
597     public void mouseReleased(MouseEvent e)
598     {
599       // TODO Auto-generated method stub
600
601     }
602
603     @Override
604     public void stateChanged(ChangeEvent e)
605     {
606       if (!adjusting)
607       {
608         if (!isLogarithmic)
609         {
610           /*
611            * set (int or float formatted) text field value
612            */
613           valueField.setText(integ ? String.valueOf(slider.getValue())
614                   : String.valueOf(slider.getValue() / SLIDERSCALE));
615         }
616         else
617         {
618           double base = ((LogarithmicParameter) parameter).getBase();
619           double value = Math.pow(base, slider.getValue() / LOGSLIDERSCALE);
620           valueField.setText(formatDouble(value));
621         }
622         checkIfModified();
623       }
624
625     }
626
627     /**
628      * Answers the value formatted as a string to 3 decimal places - in
629      * scientific notation if the value is less than 0.001
630      * 
631      * @param value
632      * @return
633      */
634     public String formatDouble(double value)
635     {
636       String format = value < 0.001 ? "%3.3e" : "%3.3f";
637       return String.format(format, value);
638     }
639
640     public void updateControls(ParameterI parm)
641     {
642       adjusting = true;
643       boolean init = (choicebox == null && valueField == null);
644       if (init)
645       {
646         if (choice)
647         {
648           choicebox = new JComboBox<>();
649           choicebox.addActionListener(this);
650           controlPanel.add(choicebox, BorderLayout.CENTER);
651         }
652         else
653         {
654           slider = new JSlider();
655           slider.addChangeListener(this);
656           valueField = new JTextField();
657           valueField.addActionListener(this);
658           valueField.addKeyListener(new KeyAdapter()
659           {
660             @Override
661             public void keyReleased(KeyEvent e)
662             {
663               if (e.isActionKey())
664               {
665                 if (valueField.getText().trim().length() > 0)
666                 {
667                   actionPerformed(null);
668                 }
669               }
670             }
671           });
672           valueField.setPreferredSize(new Dimension(80, 25));
673           controlPanel.add(slider, BorderLayout.WEST);
674           controlPanel.add(valueField, BorderLayout.EAST);
675         }
676       }
677
678       if (parm != null)
679       {
680         if (choice)
681         {
682           if (init)
683           {
684             for (String val : parm.getPossibleValues())
685             {
686               choicebox.addItem(val);
687             }
688           }
689
690           if (parm.getValue() != null)
691           {
692             choicebox.setSelectedItem(parm.getValue());
693           }
694         }
695         else
696         {
697           if (parm instanceof LogarithmicParameter)
698           {
699             double base = ((LogarithmicParameter) parm).getBase();
700             // double value = Math.pow(base,
701             // Double.parseDouble(parm.getValue()) / LOGSLIDERSCALE);
702             double value = Double.parseDouble(parm.getValue());
703             valueField.setText(formatDouble(value));
704           }
705           else
706           {
707             valueField.setText(parm.getValue());
708           }
709         }
710       }
711       lastVal = updateSliderFromValueField();
712       adjusting = false;
713     }
714
715     public Object updateSliderFromValueField()
716     {
717       int iVal;
718       float fVal;
719       double dVal;
720       if (validator != null)
721       {
722         if (integ)
723         {
724           iVal = 0;
725           try
726           {
727             valueField.setText(valueField.getText().trim());
728             iVal = Integer.valueOf(valueField.getText());
729             if (validator.getMin() != null
730                     && validator.getMin().intValue() > iVal)
731             {
732               iVal = validator.getMin().intValue();
733               // TODO: provide visual indication that hard limit was reached for
734               // this parameter
735             }
736             if (validator.getMax() != null
737                     && validator.getMax().intValue() < iVal)
738             {
739               iVal = validator.getMax().intValue();
740               // TODO: provide visual indication that hard limit was reached for
741               // this parameter
742             }
743           } catch (Exception e)
744           {
745             System.err.println(e.getMessage());
746           }
747           // update value field to reflect any bound checking we performed.
748           valueField.setText("" + iVal);
749           if (validator.getMin() != null && validator.getMax() != null)
750           {
751             slider.getModel().setRangeProperties(iVal, 1,
752                     validator.getMin().intValue(),
753                     validator.getMax().intValue() + 1, true);
754           }
755           else
756           {
757             slider.setVisible(false);
758           }
759           return new int[] { iVal };
760         }
761         else if (isLogarithmic)
762         {
763           dVal = 0d;
764           try
765           {
766             valueField.setText(valueField.getText().trim());
767             double eValue = Double.valueOf(valueField.getText());
768
769             dVal = Math.log(eValue) / Math
770                     .log(((LogarithmicParameter) parameter).getBase())
771                     * LOGSLIDERSCALE;
772
773             if (validator.getMin() != null
774                     && validator.getMin().doubleValue() > dVal)
775             {
776               dVal = validator.getMin().doubleValue();
777               // TODO: provide visual indication that hard limit was reached for
778               // this parameter
779               // update value field to reflect any bound checking we performed.
780               valueField.setText(formatDouble(eValue));
781             }
782             if (validator.getMax() != null
783                     && validator.getMax().doubleValue() < dVal)
784             {
785               dVal = validator.getMax().doubleValue();
786               // TODO: provide visual indication that hard limit was reached for
787               // this parameter
788               // update value field to reflect any bound checking we performed.
789               valueField.setText(formatDouble(eValue));
790             }
791           } catch (Exception e)
792           {
793           }
794
795           if (validator.getMin() != null && validator.getMax() != null)
796           {
797             slider.getModel().setRangeProperties((int) (dVal), 1,
798                     (int) (validator.getMin().doubleValue()),
799                     1 + (int) (validator.getMax().doubleValue()),
800                     true);
801           }
802           else
803           {
804             slider.setVisible(false);
805           }
806           return new double[] { dVal };
807         }
808         else
809         {
810           fVal = 0f;
811           try
812           {
813             valueField.setText(valueField.getText().trim());
814             fVal = Float.valueOf(valueField.getText());
815             if (validator.getMin() != null
816                     && validator.getMin().floatValue() > fVal)
817             {
818               fVal = validator.getMin().floatValue();
819               // TODO: provide visual indication that hard limit was reached for
820               // this parameter
821               // update value field to reflect any bound checking we performed.
822               valueField.setText("" + fVal);
823             }
824             if (validator.getMax() != null
825                     && validator.getMax().floatValue() < fVal)
826             {
827               fVal = validator.getMax().floatValue();
828               // TODO: provide visual indication that hard limit was reached for
829               // this parameter
830               // update value field to reflect any bound checking we performed.
831               valueField.setText("" + fVal);
832             }
833           } catch (Exception e)
834           {
835           }
836
837           if (validator.getMin() != null && validator.getMax() != null)
838           {
839             slider.getModel().setRangeProperties((int) (fVal * SLIDERSCALE), 1,
840                     (int) (validator.getMin().floatValue() * SLIDERSCALE),
841                     1 + (int) (validator.getMax().floatValue() * SLIDERSCALE),
842                     true);
843           }
844           else
845           {
846             slider.setVisible(false);
847           }
848           return new float[] { fVal };
849         }
850       }
851       else
852       {
853         if (!choice)
854         {
855           slider.setVisible(false);
856           return new String[] { valueField.getText().trim() };
857         }
858         else
859         {
860           return new String[] { (String) choicebox.getSelectedItem() };
861         }
862       }
863
864     }
865   }
866
867   public OptsAndParamsPage(OptsParametersContainerI paramContainer)
868   {
869     this(paramContainer, false);
870   }
871
872   public OptsAndParamsPage(OptsParametersContainerI paramContainer,
873           boolean compact)
874   {
875     poparent = paramContainer;
876     this.compact = compact;
877   }
878
879   public static void showUrlPopUp(JComponent invoker, final String finfo,
880           int x, int y)
881   {
882
883     JPopupMenu mnu = new JPopupMenu();
884     JMenuItem mitem = new JMenuItem(
885             MessageManager.formatMessage("label.view_params", new String[]
886             { finfo }));
887     mitem.addActionListener(new ActionListener()
888     {
889
890       @Override
891       public void actionPerformed(ActionEvent e)
892       {
893         Desktop.showUrl(finfo);
894
895       }
896     });
897     mnu.add(mitem);
898     mnu.show(invoker, x, y);
899   }
900
901   public Map<String, OptionBox> getOptSet()
902   {
903     return optSet;
904   }
905
906   public void setOptSet(Map<String, OptionBox> optSet)
907   {
908     this.optSet = optSet;
909   }
910
911   public Map<String, ParamBox> getParamSet()
912   {
913     return paramSet;
914   }
915
916   public void setParamSet(Map<String, ParamBox> paramSet)
917   {
918     this.paramSet = paramSet;
919   }
920
921   OptionBox addOption(OptionI opt)
922   {
923     OptionBox cb = optSet.get(opt.getName());
924     if (cb == null)
925     {
926       cb = new OptionBox(opt);
927       optSet.put(opt.getName(), cb);
928       // jobOptions.add(cb, FlowLayout.LEFT);
929     }
930     return cb;
931   }
932
933   ParamBox addParameter(ParameterI arg)
934   {
935     ParamBox pb = paramSet.get(arg.getName());
936     if (pb == null)
937     {
938       pb = new ParamBox(poparent, arg);
939       paramSet.put(arg.getName(), pb);
940       // paramList.add(pb);
941     }
942     pb.init();
943     // take the defaults from the parameter
944     pb.updateControls(arg);
945     return pb;
946   }
947
948   void selectOption(OptionI option, String string)
949   {
950     OptionBox cb = optSet.get(option.getName());
951     if (cb == null)
952     {
953       cb = addOption(option);
954     }
955     cb.enabled.setSelected(string != null); // initial state for an option.
956     if (string != null)
957     {
958       if (option.getPossibleValues().contains(string))
959       {
960         cb.val.setSelectedItem(string);
961       }
962       else
963       {
964         throw new Error(String.format("Invalid value '%s' for option '%s'",
965                 string, option.getName()));
966       }
967     }
968     if (option.isRequired() && !cb.enabled.isSelected())
969     {
970       // TODO: indicate paramset is not valid.. option needs to be selected!
971     }
972     cb.setInitialValue();
973   }
974
975   void setParameter(ParameterI arg)
976   {
977     ParamBox pb = paramSet.get(arg.getName());
978     if (pb == null)
979     {
980       addParameter(arg);
981     }
982     else
983     {
984       pb.updateControls(arg);
985     }
986
987   }
988
989   /**
990    * recover options and parameters from GUI
991    * 
992    * @return
993    */
994   public List<ArgumentI> getCurrentSettings()
995   {
996     List<ArgumentI> argSet = new ArrayList<>();
997     for (OptionBox opts : getOptSet().values())
998     {
999       OptionI opt = opts.getOptionIfEnabled();
1000       if (opt != null)
1001       {
1002         argSet.add(opt);
1003       }
1004     }
1005     for (ParamBox parambox : getParamSet().values())
1006     {
1007       ParameterI parm = parambox.getParameter();
1008       if (parm != null)
1009       {
1010         argSet.add(parm);
1011       }
1012     }
1013
1014     return argSet;
1015   }
1016
1017 }