added URL display for parameters/options and debugged parameter set switching
[jalview.git] / src / jalview / gui / WsJobParameters.java
1 package jalview.gui;
2
3 import java.awt.BorderLayout;
4 import java.awt.Color;
5 import java.awt.Component;
6 import java.awt.Dimension;
7 import java.awt.FlowLayout;
8 import java.awt.Font;
9 import java.awt.GridLayout;
10 import java.awt.Rectangle;
11 import java.awt.event.ActionEvent;
12 import java.awt.event.ActionListener;
13 import java.awt.event.ComponentEvent;
14 import java.awt.event.ComponentListener;
15 import java.awt.event.ContainerEvent;
16 import java.awt.event.ContainerListener;
17 import java.awt.event.ItemEvent;
18 import java.awt.event.ItemListener;
19 import java.awt.event.KeyEvent;
20 import java.awt.event.KeyListener;
21 import java.awt.event.MouseEvent;
22 import java.awt.event.MouseListener;
23 import java.awt.event.WindowEvent;
24 import java.awt.event.WindowListener;
25 import java.awt.event.WindowStateListener;
26 import java.net.URL;
27 import java.util.ArrayList;
28 import java.util.EventObject;
29 import java.util.HashSet;
30 import java.util.Hashtable;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Vector;
35
36 import javax.swing.JButton;
37 import javax.swing.JCheckBox;
38 import javax.swing.JComboBox;
39 import javax.swing.JComponent;
40 import javax.swing.JDialog;
41 import javax.swing.JFrame;
42 import javax.swing.JLabel;
43 import javax.swing.JList;
44 import javax.swing.JMenuItem;
45 import javax.swing.JOptionPane;
46 import javax.swing.JPanel;
47 import javax.swing.JPopupMenu;
48 import javax.swing.JScrollPane;
49 import javax.swing.JSlider;
50 import javax.swing.JSplitPane;
51 import javax.swing.JTable;
52 import javax.swing.JTextArea;
53 import javax.swing.JTextField;
54 import javax.swing.ListSelectionModel;
55 import javax.swing.SwingConstants;
56 import javax.swing.SwingUtilities;
57 import javax.swing.border.TitledBorder;
58 import javax.swing.event.CellEditorListener;
59 import javax.swing.event.ChangeEvent;
60 import javax.swing.event.ChangeListener;
61 import javax.swing.event.DocumentEvent;
62 import javax.swing.event.DocumentListener;
63 import javax.swing.table.*;
64
65 import compbio.metadata.Argument;
66 import compbio.metadata.Option;
67 import compbio.metadata.Parameter;
68 import compbio.metadata.Preset;
69 import compbio.metadata.PresetManager;
70 import compbio.metadata.RunnerConfig;
71 import compbio.metadata.ValueConstrain;
72 import compbio.metadata.WrongParameterException;
73 import compbio.metadata.ValueConstrain.Type;
74
75 import jalview.util.jarInputStreamProvider;
76 import jalview.ws.jws2.Jws2Discoverer;
77 import jalview.ws.jws2.ParameterUtils;
78 import jalview.ws.jws2.Jws2Discoverer.Jws2Instance;
79
80 /**
81  * job parameter editing/browsing dialog box. User can browse existing settings
82  * (user + presets + Defaults), and any changes to parameters creates a modified
83  * user parameter set. LOGIC: If the parameter set is modified, and its name is
84  * a valid, non-existant user parameter set, then a save button is shown. If the
85  * parameter set is modified and its name is a valid, extant user parameter set,
86  * then an update button is shown. If user parameter set's name is edited, and
87  * old name exists as a writable user parameter set, then rename button is
88  * shown. If current parameter set is associated with a user defined parameter
89  * set, then : if set is modifed, a 'revert' button is shown. if set is not
90  * modified, a 'delete' button is shown.
91  * 
92  * @author JimP
93  * 
94  */
95 public class WsJobParameters extends JPanel implements ItemListener,
96         ActionListener, DocumentListener
97 {
98   private static final String SVC_DEF = "Defaults"; // this is the null
99                                                     // parameter set as shown to
100                                                     // user
101
102   private static final int PARAM_WIDTH = 340, PARAM_HEIGHT = 150,
103           PARAM_CLOSEDHEIGHT = 80;
104
105   private static final int OPTSET_HEIGHT = 30;
106
107   JPanel SetNamePanel = new JPanel();
108
109   JPanel setDetails = new JPanel();
110
111   JSplitPane settingsPanel = new JSplitPane();
112
113   JSplitPane jobPanel = new JSplitPane();
114
115   JPanel jobOptions = new JPanel();
116
117   JScrollPane jobOptionsPane = new JScrollPane();
118
119   JPanel jobParameters = new JPanel();
120
121   JButton savmodified = new JButton();
122
123   JButton renmodified = new JButton();
124
125   JButton deletesetting = new JButton();
126
127   JButton revertsetting = new JButton();
128
129   JButton startjob = new JButton();
130
131   JButton canceljob = new JButton();
132
133   JComboBox setName = new JComboBox();
134
135   JTextArea setDescr = new JTextArea();
136
137   JScrollPane paramPane = new JScrollPane();
138
139   // JList paramList = new JList();
140   JPanel paramList = new JPanel();
141
142   RunnerConfig serviceOptions;
143
144   private BorderLayout jparamLayout;
145
146   WsJobParameters(Jws2Instance service)
147   {
148     this(service, null);
149   }
150
151   public WsJobParameters(Jws2Instance service, Preset p)
152   {
153     this(null, service, p, null);
154   }
155
156   /**
157    * 
158    * @param desktop
159    *          - if null, create new JFrame outside of desktop
160    * @param service
161    * @param p
162    */
163   public WsJobParameters(JFrame parent, Jws2Instance service, Preset p,
164           List<Argument> jobArgset)
165   {
166     super();
167     jbInit();
168     // argSetModified(false);
169     // populate parameter table
170     initForService(service, p, jobArgset);
171     // display in new JFrame attached to parent.
172     validate();
173   }
174
175   int response = -1;
176
177   JDialog frame = null;
178
179   /**
180    * shows a modal dialog containing the parameters.
181    * 
182    * @return
183    */
184   public boolean showRunDialog()
185   {
186
187     frame = new JDialog(Desktop.instance, true);
188
189     frame.setTitle("Edit parameters for " + service.getActionText());
190     Rectangle deskr = Desktop.instance.getBounds();
191     frame.setBounds(new Rectangle((int) (deskr.getCenterX() - 240),
192             (int) (deskr.getCenterY() - 250), 480, 500));
193     frame.setContentPane(this);
194     // should recover defaults from user prefs.
195     frame.validate();
196     settingsPanel.setDividerLocation(0.4);
197     jobPanel.setDividerLocation(0.3);
198     frame.setVisible(true);
199
200     if (response > 0)
201     {
202       return true;
203     }
204     return false;
205   }
206
207   protected JButton makeButton(String label, String tooltip,
208           ActionListener action)
209   {
210     JButton button = new JButton();
211     button.setText(label);
212     button.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
213     button.setForeground(Color.black);
214     button.setHorizontalAlignment(SwingConstants.CENTER);
215     button.setToolTipText(tooltip);
216     button.addActionListener(action);
217     return button;
218   }
219
220   private void jbInit()
221   {
222     savmodified = makeButton("Save", "Not implemented yet :) ",
223             new ActionListener()
224             {
225
226               public void actionPerformed(ActionEvent e)
227               {
228                 savModified_actionPerformed(e);
229               }
230             });
231     renmodified = makeButton("Rename", "Not implemented yet :) ",
232             new ActionListener()
233             {
234
235               public void actionPerformed(ActionEvent e)
236               {
237                 renModified_actionPerformed(e);
238               }
239             });
240     deletesetting = makeButton("Delete", "Not implemented yet :) ",
241             new ActionListener()
242             {
243
244               public void actionPerformed(ActionEvent e)
245               {
246                 deleteSetting_actionPerformed(e);
247               }
248             });
249     revertsetting = makeButton("Revert", "Undo changes to parameters.",
250             new ActionListener()
251             {
252
253               public void actionPerformed(ActionEvent e)
254               {
255                 revertSetting_actionPerformed(e);
256               }
257             });
258
259     startjob.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
260     startjob.setText("Start");
261     startjob.setToolTipText("Start Job");
262     startjob.addActionListener(new ActionListener()
263     {
264       public void actionPerformed(ActionEvent e)
265       {
266         startjob_actionPerformed(e);
267       }
268     });
269     canceljob.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
270     canceljob.setText("Cancel");
271     canceljob.setToolTipText("Cancel Job");
272     canceljob.addActionListener(new ActionListener()
273     {
274       public void actionPerformed(ActionEvent e)
275       {
276         canceljob_actionPerformed(e);
277       }
278     });
279
280     setDetails.setBorder(new TitledBorder("Details"));
281     setDetails.setLayout(new BorderLayout());
282     setDescr.setColumns(40);
283     setDescr.setWrapStyleWord(true);
284     setDescr.setLineWrap(true);
285     setDescr.setBackground(getBackground());
286     setDescr.setEditable(true);
287     setDescr.getDocument().addDocumentListener(this);
288     JScrollPane setDescrView = new JScrollPane();
289     // setDescrView.setPreferredSize(new Dimension(350, 200));
290     setDescrView.getViewport().setView(setDescr);
291     setName.setEditable(true);
292     setName.addItemListener(this);
293     setName.getEditor().addActionListener(this);
294     SetNamePanel.setLayout(new BorderLayout());
295     SetNamePanel.add(setName, BorderLayout.WEST);
296     // initial button visibility
297     deletesetting.setVisible(false);
298     revertsetting.setVisible(false);
299     renmodified.setVisible(false);
300     savmodified.setVisible(false);
301     JPanel setsavebuts = new JPanel();
302     setsavebuts.setLayout(new FlowLayout());
303     setsavebuts.add(revertsetting, BorderLayout.CENTER);
304     setsavebuts.add(renmodified, BorderLayout.CENTER);
305     setsavebuts.add(deletesetting, BorderLayout.CENTER);
306     setsavebuts.add(savmodified, BorderLayout.EAST);
307     SetNamePanel.add(setsavebuts, BorderLayout.EAST);
308     setDetails.add(setDescrView, BorderLayout.CENTER);
309     // setDetails.setPreferredSize(new Dimension(360, 100));
310     jobParameters.setBorder(new TitledBorder("Parameters"));
311     jobParameters.setLayout(jparamLayout = new BorderLayout());
312     paramPane.setPreferredSize(new Dimension(360, 300));
313     paramPane.getVerticalScrollBar().setUnitIncrement(20);
314     // paramPanel.setPreferredSize(new Dimension(360, 300));
315     // TODO: relayout buttons nicely
316     paramPane.getViewport().setView(paramList);
317     jobParameters.add(paramPane, BorderLayout.CENTER);
318     JPanel jobOptionsPanel = new JPanel();
319     jobOptionsPanel.setLayout(new BorderLayout());
320     jobOptionsPanel.setBorder(new TitledBorder("Options"));
321     jobOptionsPane.getViewport().setView(jobOptions);
322     jobOptionsPanel.add(jobOptionsPane, BorderLayout.CENTER);
323     settingsPanel.setLeftComponent(jobOptionsPanel);
324     settingsPanel.setRightComponent(jobParameters);
325     settingsPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
326
327     setLayout(new BorderLayout());
328     // setPreferredSize(new Dimension(400, 600));
329     // setSize(new Dimension(400, 600));
330     jobPanel.setLeftComponent(setDetails);
331     jobPanel.setRightComponent(settingsPanel);
332     jobPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
333     add(SetNamePanel, BorderLayout.NORTH);
334     add(jobPanel, BorderLayout.CENTER);
335     JPanel dialogpanel = new JPanel();
336     dialogpanel.add(startjob);
337     dialogpanel.add(canceljob);
338     add(dialogpanel, BorderLayout.SOUTH);
339   }
340
341   protected void revertSetting_actionPerformed(ActionEvent e)
342   {
343     // TODO Auto-generated method stub
344
345   }
346
347   protected void deleteSetting_actionPerformed(ActionEvent e)
348   {
349     String setname = (String) setName.getSelectedItem();
350     int p = setName.getSelectedIndex();
351     if (_getUserPreset(setname) != null)
352     {
353       _deleteUserPreset(setname);
354
355     }
356     if (p > 0 && p + 1 == setName.getItemCount())
357     {
358       p--;
359     }
360     setName.setSelectedIndex(p);
361
362   }
363
364   protected void renModified_actionPerformed(ActionEvent e)
365   {
366     if (curSetName == null || _getUserPreset(lastSetName) == null)
367     {
368       System.err
369               .println("can't rename - names unchanged or original name not a preset.");
370       return;
371     }
372     _deleteUserPreset(lastSetName);
373     lastSetName = curSetName;
374     savModified_actionPerformed(e);
375     curSetName = null;
376     boolean setd = settingDialog;
377     settingDialog = true;
378     syncSetNamesWithStore();
379     settingDialog = setd;
380   }
381
382   protected void savModified_actionPerformed(ActionEvent e)
383   {
384     _storeUserPreset(lastSetName=(String) setName.getSelectedItem(), setDescr.getText(), getJobParams());
385     curSetName = null;
386     initArgSetModified(); // reset the modification state
387   }
388
389   protected void canceljob_actionPerformed(ActionEvent e)
390   {
391     response = 0;
392     if (frame != null)
393     {
394       frame.setVisible(false);
395     }
396   }
397
398   protected void startjob_actionPerformed(ActionEvent e)
399   {
400     response = 1;
401     if (frame != null)
402     {
403       frame.setVisible(false);
404     }
405   }
406
407   Jws2Instance service;
408
409   /**
410    * list of service presets in the gui
411    */
412   Hashtable servicePresets = null;
413
414   /**
415    * set if dialog is being set - so handlers will avoid spurious events
416    */
417   boolean settingDialog = false;
418
419   void initForService(Jws2Instance service, Preset p,
420           List<Argument> jobArgset)
421   {
422     settingDialog = true;
423     this.service = service;
424     // TODO: Recover window geometry prefs for this service
425     // jobPanel.setDividerLocation(proportionalLocation)
426     // settingsPanel.setDividerLocation(proportionalLocation)
427     Hashtable exnames = new Hashtable();
428     for (int i = 0, iSize = setName.getItemCount(); i < iSize; i++)
429     {
430       exnames.put((String) setName.getItemAt(i), setName.getItemAt(i));
431     }
432     // Add the default entry - if not present already.
433     if (!exnames.contains(SVC_DEF))
434     {
435       setName.addItem(SVC_DEF);
436       exnames.put(SVC_DEF, SVC_DEF);
437     }
438     serviceOptions = service.getRunnerConfig();
439     // add any presets not already added.
440     String curname = (p == null ? "" : p.getName());
441     PresetManager prman = service.getPresets();
442     servicePresets = new Hashtable();
443     if (prman != null)
444     {
445       List prList = service.getPresets().getPresets();
446       if (prList != null)
447       {
448         for (Object pr : prList)
449         {
450           servicePresets.put(((Preset) pr).getName(), "preset");
451           if (!exnames.contains(((Preset) pr).getName()))
452           {
453             setName.addItem(((Preset) pr).getName());
454           }
455         }
456       }
457     }
458     updateTable(p, jobArgset);
459     initArgSetModified();
460     settingDialog = false;
461
462   }
463
464   @SuppressWarnings("unchecked")
465   private void updateTable(Preset p, List<Argument> jobArgset)
466   {
467     List<Parameter> setargs = new ArrayList<Parameter>();
468     // populate table from default parameter set.
469     List<Argument> args = serviceOptions.getArguments();
470
471     // split to params and required arguments
472     {
473       for (Argument arg : args)
474       {
475         Argument myarg = (Argument) arg;
476         // Ideally, Argument would implement isRequired !
477         if (myarg instanceof Parameter)
478         {
479           Parameter parm = (Parameter) myarg;
480           addParameter(parm);
481         }
482         else
483         {
484           if (myarg instanceof Option)
485           {
486             Option opt = (Option) myarg;
487             addOption(opt).resetToDefault();
488           }
489           else
490           {
491             System.err.println("Ignoring unknown service argument type "
492                     + arg.getClass().getName());
493           }
494         }
495       }
496       args = null; // no more args to process.
497     }
498     if (p != null)
499     {
500       // initialise setname
501       setName.setSelectedItem(lastSetName = p.getName());
502       setDescr.setText(lastDescrText = p.getDescription());
503       // TODO - URL link
504       try
505       {
506         args = p.getArguments(serviceOptions);
507       } catch (Exception e)
508       {
509         e.printStackTrace();
510       }
511       // TODO: check if args should be unselected prior to resetting using the
512       // preset
513       setargs.clear();
514     }
515     else
516     {
517       if (lastParmSet == null)
518       {
519         // first call - so create a dummy name
520         setName.setSelectedItem(lastSetName = SVC_DEF);
521       }
522     }
523
524     if (jobArgset != null)
525     {
526       argSetModified(jobArgset, true);
527       args = jobArgset;
528     }
529     // get setargs from current object
530     if (args != null)
531     {
532       for (Argument arg : args)
533       {
534         if (arg instanceof Parameter)
535         {
536           setParameter((Parameter) arg);
537         }
538         else
539         {
540           if (arg instanceof Option)
541           {
542 //            System.out.println("Setting option "
543 //                    + System.identityHashCode(arg) + ":" + arg.getName()
544 //                    + " with " + arg.getDefaultValue());
545             selectOption((Option) arg, arg.getDefaultValue());
546           }
547         }
548
549       }
550     }
551
552     jobOptions.setPreferredSize(new Dimension(PARAM_WIDTH, optSet.size()
553             * OPTSET_HEIGHT));
554     jobOptions.setLayout(new GridLayout(optSet.size(), 1));
555     refreshParamLayout();
556     paramPane.validate();
557     validate();
558   }
559
560   private boolean isModified()
561   {
562     return modifiedElements.size() > 0;
563   }
564
565   private Hashtable modifiedElements = new Hashtable();
566
567   /**
568    * reset gui and modification state settings
569    */
570   private void initArgSetModified()
571   {
572     curSetName = null;
573     modifiedElements.clear();
574     renmodified.setVisible(false);
575     savmodified.setVisible(false);
576
577   }
578
579   private void argSetModified(Object modifiedElement, boolean b)
580   {
581     if (settingDialog)
582     {
583       return;
584     }
585
586     if (!b)
587     {
588       modifiedElements.remove(modifiedElement);
589     }
590     else
591     {
592       modifiedElements.put(modifiedElement, modifiedElement);
593     }
594     // set mod status based on presence of elements in table
595     if (modifiedElements.size() > 0)
596     {
597       makeSetNameValid();
598       savmodified.setVisible(true);
599       revertsetting.setVisible(false);
600     }
601     else
602     {
603       revertsetting.setVisible(false);
604       deletesetting
605               .setVisible(!isServicePreset((String) setName
606                       .getSelectedItem())
607                       && _getUserPreset((String) setName.getSelectedItem()) != null);
608       savmodified.setVisible(false);
609     }
610     // special reveal if setName has been modified
611     if (modifiedElements.get(setName) != null)
612     {
613       if (curSetName != null && lastSetName != null
614               && !lastSetName.equals(curSetName))
615       {
616         renmodified.setVisible(!isServicePreset(lastSetName));
617       }
618     }
619     else
620     {
621       // setname isn't in modlist - so don't rename
622       renmodified.setVisible(false);
623     }
624     validate();
625   }
626
627   private boolean isServicePreset(String selectedItem)
628   {
629     return selectedItem.equals(SVC_DEF)
630             || servicePresets.containsKey(selectedItem);
631   }
632
633   /**
634    * check if the current set name is a valid set name for saving, if not, then
635    * fix it.
636    */
637   private void makeSetNameValid()
638   {
639     boolean stn = settingDialog;
640     boolean renamed = false;
641     settingDialog = true;
642     String nm = (String) setName.getSelectedItem();
643     // check if the name is reserved - if it is, rename it.
644     if (isServicePreset(nm))
645     {
646       nm = "User " + nm;
647       String tnm=nm;
648       renamed = true;
649       int i=0;
650       while (_getUserPreset(tnm)!=null)
651       {
652         tnm = nm+" ("+(++i)+")";
653       }
654       if (i>0)
655       {
656         nm = tnm;
657       }
658     }
659     // if ()
660     // if nm exists in user's preset store then savmodified will update an
661     // existing user defined preset
662     // if nm doesn't exist, then the button will create a new preset.
663
664     boolean makeupdate = false;
665     // sync the gui with the preset database
666     for (int i = 0, iS = setName.getItemCount(); i < iS; i++)
667     {
668       String snm = (String) setName.getItemAt(i);
669       if (snm.equals(nm))
670       {
671         makeupdate = true;
672         setName.setSelectedIndex(i);
673       }
674     }
675
676     if (_getUserPreset(nm) != null)
677     {
678       savmodified.setText("Update");
679     }
680     else
681     {
682       if (renamed)
683       {
684         setName.addItem(nm);
685         setName.setSelectedIndex(setName.getItemCount() - 1);
686       }
687       savmodified.setText("Save");
688     }
689     settingDialog = stn;
690   }
691
692   private void addParameter(Parameter parm)
693   {
694     ParamBox pb = paramSet.get(parm.getName());
695     if (pb == null)
696     {
697       pb = new ParamBox(this, parm);
698       paramSet.put(parm.getName(), pb);
699       paramList.add(pb);
700     }
701     pb.init();
702     // take the defaults from the parameter
703     pb.updateControls(parm);
704   }
705
706   private void setParameter(Parameter arg)
707   {
708     ParamBox pb = paramSet.get(arg.getName());
709     if (pb == null)
710     {
711       addParameter(arg);
712     }
713     else
714     {
715       pb.updateControls(arg);
716     }
717
718   }
719
720   private void selectOption(Option opt, String string)
721   {
722     OptionBox cb = optSet.get(opt.getName());
723     if (cb == null)
724     {
725       cb = addOption(opt);
726     }
727     cb.enabled.setSelected(true); // initial state for an option.
728     if (string != null)
729     {
730       if (opt.getPossibleValues().contains(string))
731       {
732         cb.val.setSelectedItem(string);
733       }
734       else
735       {
736         throw new Error("Invalid value " + string + " for option " + opt);
737       }
738
739     }
740     if (opt.isRequired() && !cb.enabled.isSelected())
741     {
742       // TODO: indicate paramset is not valid.. option needs to be selected!
743     }
744     cb.setInitialValue();
745   }
746
747   Map<String, ParamBox> paramSet = new Hashtable<String, ParamBox>();
748
749   public class ParamBox extends JPanel implements ChangeListener,
750           ActionListener, MouseListener
751   {
752     JButton showDesc = new JButton();
753
754     JTextArea string = new JTextArea();
755
756     JScrollPane descPanel = new JScrollPane();
757
758     JSlider slider = null;
759
760     JTextField valueField = null;
761
762     ValueConstrain validator = null;
763
764     JPanel settingPanel = new JPanel();
765
766     JPanel controlPanel = new JPanel();
767
768     boolean integ = false;
769
770     boolean choice = false;
771
772     boolean descisvisible = false;
773
774     final WsJobParameters pmdialogbox;
775
776     final URL finfo;
777
778     public ParamBox(final WsJobParameters pmlayout, Parameter parm)
779     {
780       pmdialogbox = pmlayout;
781       setPreferredSize(new Dimension(PARAM_WIDTH, PARAM_CLOSEDHEIGHT));
782       setBorder(new TitledBorder(parm.getName()));
783       setLayout(null);
784       showDesc.setFont(new Font("Verdana", Font.PLAIN, 6));
785       showDesc.setText("+");
786       string.setFont(new Font("Verdana", Font.PLAIN, 11));
787       string.setBackground(getBackground());
788       // string.setSize(new Dimension(PARAM_WIDTH, 80));
789       string.setEditable(false);
790       descPanel.getViewport().setView(string);
791       // descPanel.setLocation(2,17);
792       descPanel.setVisible(false);
793       // string.setMinimumSize(new Dimension(140,80));
794       // string.setMaximumSize(new Dimension(280,80));
795       final ParamBox me = this;
796       finfo = parm.getFurtherDetails();
797       if (finfo != null)
798       {
799         showDesc.setToolTipText("<html><p>Click to show brief description, and right click to open link for further information.</p></html>");
800         showDesc.addMouseListener(this);
801       }
802       else
803       {
804         showDesc.setToolTipText("<html><p>Click to show brief description.</p></html>");
805       }
806       showDesc.addActionListener(new ActionListener()
807       {
808
809         public void actionPerformed(ActionEvent e)
810         {
811           descisvisible = !descisvisible;
812           descPanel.setVisible(descisvisible);
813           me.setPreferredSize(new Dimension(PARAM_WIDTH,
814                   (descisvisible) ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT));
815           me.validate();
816           pmlayout.refreshParamLayout();
817         }
818       });
819       string.setWrapStyleWord(true);
820       string.setLineWrap(true);
821       string.setColumns(32);
822       string.setText(parm.getDescription());
823       JPanel firstrow = new JPanel();
824       firstrow.setLayout(null);
825       controlPanel.setLayout(new BorderLayout());
826       controlPanel.setBounds(new Rectangle(39, 10, PARAM_WIDTH - 70,
827               PARAM_CLOSEDHEIGHT - 50));
828       showDesc.setBounds(new Rectangle(10, 10, 16, 16));
829       firstrow.add(showDesc);
830       firstrow.add(controlPanel);
831       firstrow.setBounds(new Rectangle(10, 20, PARAM_WIDTH - 30,
832               PARAM_CLOSEDHEIGHT - 30));
833       add(firstrow);
834       validator = parm.getValidValue();
835       parameter = parm;
836       if (validator != null)
837       {
838         integ = validator.getType() == Type.Integer;
839       }
840       else
841       {
842         if (parameter.getPossibleValues() != null)
843         {
844           choice = true;
845         }
846       }
847       updateControls(parm);
848       descPanel.setBounds(new Rectangle(10, PARAM_CLOSEDHEIGHT,
849               PARAM_WIDTH - 20, PARAM_HEIGHT - PARAM_CLOSEDHEIGHT - 5));
850       add(descPanel);
851       validate();
852     }
853
854     public void init()
855     {
856       // reset the widget's initial value.
857       lastVal = null;
858     }
859
860     boolean adjusting = false;
861
862     Parameter parameter;
863
864     JComboBox choicebox;
865
866     public int getBoxHeight()
867     {
868       return (descisvisible ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT);
869     }
870
871     public void updateControls(Parameter parm)
872     {
873       adjusting = true;
874       boolean init = (choicebox == null && valueField == null);
875       float fVal = 0f;
876       int iVal = 0;
877       if (init)
878       {
879         if (choice)
880         {
881           choicebox = new JComboBox();
882           choicebox.addActionListener(this);
883           controlPanel.add(choicebox, BorderLayout.CENTER);
884         }
885         else
886         {
887           slider = new JSlider();
888           slider.addChangeListener(this);
889           valueField = new JTextField();
890           valueField.addActionListener(this);
891           valueField.setPreferredSize(new Dimension(60, 25));
892           controlPanel.add(slider, BorderLayout.WEST);
893           controlPanel.add(valueField, BorderLayout.EAST);
894
895         }
896       }
897
898       if (parm != null)
899       {
900         if (choice)
901         {
902           if (init)
903           {
904             List vals = parm.getPossibleValues();
905             for (Object val : vals)
906             {
907               choicebox.addItem(val);
908             }
909           }
910
911           if (parm.getDefaultValue() != null)
912           {
913             choicebox.setSelectedItem(parm.getDefaultValue());
914           }
915         }
916         else
917         {
918           valueField.setText(parm.getDefaultValue());
919         }
920       }
921       lastVal = updateSliderFromValueField();
922       adjusting = false;
923     }
924
925     Object lastVal;
926
927     public Parameter getParameter()
928     {
929       Parameter prm = ParameterUtils.copyParameter(parameter);
930       try
931       {
932         if (choice)
933         {
934           prm.setDefaultValue((String) choicebox.getSelectedItem());
935         }
936         else
937         {
938           prm.setDefaultValue(valueField.getText());
939         }
940       } catch (WrongParameterException e)
941       {
942         e.printStackTrace();
943         return null;
944       }
945       return prm;
946     }
947
948     public Object updateSliderFromValueField()
949     {
950       int iVal;
951       float fVal;
952       if (validator != null)
953       {
954         if (integ)
955         {
956           iVal = 0;
957           try
958           {
959             valueField.setText(valueField.getText().trim());
960             iVal = Integer.valueOf(valueField.getText());
961           } catch (Exception e)
962           {
963           }
964           ;
965           if (validator.getMin() != null && validator.getMax() != null)
966           {
967             slider.getModel().setRangeProperties(iVal, 1,
968                     validator.getMin().intValue(),
969                     validator.getMax().intValue(), true);
970           }
971           else
972           {
973             slider.setVisible(false);
974           }
975           return new int[]
976           { iVal };
977         }
978         else
979         {
980           fVal = 0f;
981           try
982           {
983             fVal = Float.valueOf(valueField.getText());
984           } catch (Exception e)
985           {
986           }
987           ;
988           if (validator.getMin() != null && validator.getMax() != null)
989           {
990             slider.getModel().setRangeProperties((int) fVal * 1000, 1,
991                     (int) validator.getMin().floatValue() * 1000,
992                     (int) validator.getMax().floatValue() * 1000, true);
993           }
994           else
995           {
996             slider.setVisible(false);
997           }
998           return new float[]
999           { fVal };
1000         }
1001       }
1002       else
1003       {
1004         if (!choice)
1005         {
1006           slider.setVisible(false);
1007           return new String[]
1008           { valueField.getText().trim() };
1009         }
1010         else
1011         {
1012           return new String[]
1013           { (String) choicebox.getSelectedItem() };
1014         }
1015       }
1016
1017     }
1018
1019     public void stateChanged(ChangeEvent e)
1020     {
1021       if (!adjusting)
1022       {
1023         valueField.setText(""
1024                 + ((integ) ? ("" + (int) slider.getValue())
1025                         : ("" + (float) (slider.getValue() / 1000f))));
1026         checkIfModified();
1027       }
1028
1029     }
1030
1031     public void actionPerformed(ActionEvent e)
1032     {
1033       if (adjusting)
1034       {
1035         return;
1036       }
1037       if (!choice)
1038       {
1039         updateSliderFromValueField();
1040       }
1041       checkIfModified();
1042     }
1043
1044     private void checkIfModified()
1045     {
1046       Object cstate = updateSliderFromValueField();
1047       boolean notmod = false;
1048       if (cstate.getClass() == lastVal.getClass())
1049       {
1050         if (cstate instanceof int[])
1051         {
1052           notmod = (((int[]) cstate)[0] == ((int[]) lastVal)[0]);
1053         }
1054         else if (cstate instanceof float[])
1055         {
1056           notmod = (((float[]) cstate)[0] == ((float[]) lastVal)[0]);
1057         }
1058         else if (cstate instanceof String[])
1059         {
1060           notmod = (((String[]) cstate)[0].equals(((String[]) lastVal)[0]));
1061         }
1062       }
1063       pmdialogbox.argSetModified(this, !notmod);
1064     }
1065
1066     public void mouseClicked(MouseEvent e)
1067     {
1068       if (javax.swing.SwingUtilities.isRightMouseButton(e))
1069       {
1070         Desktop.showUrl(finfo.toString());
1071       }
1072     }
1073
1074     public void mousePressed(MouseEvent e)
1075     {
1076       // TODO Auto-generated method stub
1077
1078     }
1079
1080     public void mouseReleased(MouseEvent e)
1081     {
1082       // TODO Auto-generated method stub
1083
1084     }
1085
1086     public void mouseEntered(MouseEvent e)
1087     {
1088       // TODO Auto-generated method stub
1089
1090     }
1091
1092     public void mouseExited(MouseEvent e)
1093     {
1094       // TODO Auto-generated method stub
1095
1096     }
1097
1098   }
1099
1100   Map<String, OptionBox> optSet = new Hashtable<String, OptionBox>();
1101
1102   public class OptionBox extends JPanel implements MouseListener,
1103           ActionListener
1104   {
1105     JComboBox val = new JComboBox();
1106
1107     JCheckBox enabled = new JCheckBox();
1108
1109     JLabel optlabel = new JLabel();
1110
1111     URL linkImageURL = getClass().getResource("/images/link.gif");
1112
1113     final URL finfo;
1114
1115     boolean hasLink = false;
1116
1117     Option option;
1118
1119     public OptionBox(Option opt)
1120     {
1121       option = opt;
1122       setLayout(new BorderLayout());
1123       enabled.setSelected(opt.isRequired()); // TODO: lock required options
1124       enabled.setFont(new Font("Verdana", Font.PLAIN, 11));
1125       enabled.setText("");
1126       enabled.setText(opt.getName());
1127       enabled.addActionListener(this);
1128       finfo = option.getFurtherDetails();
1129       if (finfo != null)
1130       {
1131         hasLink = true;
1132         // optlabel.setToolTipText("<html><p>"+opt.getDescription()+"</p><img src=\""+linkImageURL+"\"/></html>");
1133         enabled.setToolTipText("<html><p>" + opt.getDescription()
1134                 + "</p><img src=\"" + linkImageURL + "\"/></html>");
1135         // optlabel.addMouseListener(this);
1136         enabled.addMouseListener(this);
1137       }
1138       else
1139       {
1140         // optlabel.setToolTipText(opt.getDescription());
1141         enabled.setToolTipText(opt.getDescription());
1142       }
1143       add(enabled, BorderLayout.NORTH);
1144       if (opt.getPossibleValues().size() > 1)
1145       {
1146         setLayout(new GridLayout(1, 2));
1147         for (Object str : opt.getPossibleValues())
1148         {
1149           val.addItem((String) str);
1150         }
1151         val.setSelectedItem((String) opt.getDefaultValue());
1152         val.addActionListener(this);
1153         add(val, BorderLayout.SOUTH);
1154       }
1155       // TODO: add actionListeners for popup (to open further info),
1156       // and to update list of parameters if an option is enabled
1157       // that takes a value.
1158       setInitialValue();
1159     }
1160
1161     public void resetToDefault()
1162     {
1163       enabled.setSelected(false);
1164       if (option.isRequired())
1165       {
1166         // Apply default value
1167         selectOption(option, option.getDefaultValue());
1168       }
1169     }
1170
1171     boolean initEnabled = false;
1172
1173     String initVal = null;
1174
1175     public void setInitialValue()
1176     {
1177       initEnabled = enabled.isSelected();
1178       if (option.getPossibleValues() != null
1179               && option.getPossibleValues().size() > 1)
1180       {
1181         initVal = (String) val.getSelectedItem();
1182       }
1183       else
1184       {
1185         initVal = null;
1186       }
1187     }
1188
1189     public Option getOptionIfEnabled()
1190     {
1191       if (!enabled.isSelected())
1192       {
1193         return null;
1194       }
1195       try
1196       {
1197         Option opt = jalview.ws.jws2.ParameterUtils.copyOption(option);
1198
1199         if (val.getSelectedItem() != null)
1200         {
1201           opt.setDefaultValue((String) val.getSelectedItem());
1202         }
1203       } catch (WrongParameterException e)
1204       {
1205         e.printStackTrace();
1206         return null;
1207       }
1208       return option;
1209     }
1210
1211     public void actionPerformed(ActionEvent e)
1212     {
1213       if (e.getSource() != enabled)
1214       {
1215         enabled.setSelected(true);
1216       }
1217       checkIfModified();
1218     }
1219
1220     private void checkIfModified()
1221     {
1222       boolean notmod = (initEnabled == enabled.isSelected());
1223       if (enabled.isSelected() && initVal != null)
1224       {
1225         notmod |= initVal.equals(val.getSelectedItem());
1226       }
1227       argSetModified(this, !notmod);
1228     }
1229
1230     public void mouseClicked(MouseEvent e)
1231     {
1232       if (javax.swing.SwingUtilities.isRightMouseButton(e))
1233       {
1234         showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
1235       }
1236     }
1237
1238     public void mousePressed(MouseEvent e)
1239     {
1240       // TODO Auto-generated method stub
1241
1242     }
1243
1244     public void mouseReleased(MouseEvent e)
1245     {
1246       // TODO Auto-generated method stub
1247
1248     }
1249
1250     public void mouseEntered(MouseEvent e)
1251     {
1252       // TODO Auto-generated method stub
1253
1254     }
1255
1256     public void mouseExited(MouseEvent e)
1257     {
1258       // TODO Auto-generated method stub
1259
1260     }
1261
1262   }
1263
1264   private OptionBox addOption(Option opt)
1265   {
1266     OptionBox cb = optSet.get(opt.getName());
1267     if (cb == null)
1268     {
1269       cb = new OptionBox(opt);
1270       optSet.put(opt.getName(), cb);
1271       jobOptions.add(cb);
1272     }
1273     return cb;
1274   }
1275
1276   public static void showUrlPopUp(JComponent invoker, final String finfo,
1277           int x, int y)
1278   {
1279
1280     JPopupMenu mnu = new JPopupMenu();
1281     JMenuItem mitem = new JMenuItem("View " + finfo);
1282     mitem.addActionListener(new ActionListener()
1283     {
1284
1285       @Override
1286       public void actionPerformed(ActionEvent e)
1287       {
1288         Desktop.showUrl(finfo);
1289
1290       }
1291     });
1292     mnu.add(mitem);
1293     mnu.show(invoker, x, y);
1294   }
1295
1296   protected void refreshParamLayout()
1297   {
1298     int s = 100;
1299     for (ParamBox pbox : paramSet.values())
1300     {
1301       s += pbox.getBoxHeight();
1302     }
1303     paramList.setPreferredSize(new Dimension(PARAM_WIDTH, s));
1304     paramList.setLayout(new FlowLayout());
1305     validate();
1306   }
1307
1308   /**
1309    * testing method - grab a service and parameter set and show the window
1310    * 
1311    * @param args
1312    */
1313   public static void main(String[] args)
1314   {
1315     jalview.ws.jws2.Jws2Discoverer disc = jalview.ws.jws2.Jws2Discoverer
1316             .getDiscoverer();
1317     int p = 0;
1318     if (args.length > 3)
1319     {
1320       Vector<String> services = new Vector<String>();
1321       services.addElement(args[p++]);
1322       Jws2Discoverer.setServiceUrls(services);
1323     }
1324     try
1325     {
1326       disc.run();
1327     } catch (Exception e)
1328     {
1329       System.err.println("Aborting. Problem discovering services.");
1330       e.printStackTrace();
1331       return;
1332     }
1333     Jws2Discoverer.Jws2Instance lastserv = null;
1334     for (Jws2Discoverer.Jws2Instance service : disc.getServices())
1335     {
1336       lastserv = service;
1337       if (p >= args.length || service.serviceType.equalsIgnoreCase(args[p]))
1338       {
1339         if (lastserv != null)
1340         {
1341           List<Preset> prl = null;
1342           Preset pr = null;
1343           if (++p < args.length)
1344           {
1345             PresetManager prman = lastserv.getPresets();
1346             if (prman != null)
1347             {
1348               pr = prman.getPresetByName(args[p]);
1349               if (pr == null)
1350               {
1351                 // just grab the last preset.
1352                 prl = prman.getPresets();
1353               }
1354             }
1355           } else {
1356             PresetManager prman = lastserv.getPresets();
1357             if (prman!=null) {
1358               prl = prman.getPresets();
1359             }
1360           }
1361           Iterator<Preset> en = (prl == null) ? null : prl.iterator();
1362           while (en!=null && en.hasNext())
1363           {
1364             if (en != null)
1365             {
1366               if (!en.hasNext())
1367               {
1368                 en = prl.iterator();
1369               }
1370               pr = en.next();
1371             }
1372             {
1373               System.out.println("Testing opts dupes for "+lastserv.getHost()+" : "+lastserv.getActionText()+":"+pr.getName());
1374               List<Option> rg = lastserv.getRunnerConfig().getOptions();
1375               for (Option o : rg)
1376               {
1377                 try
1378                 {
1379                   Option cpy = jalview.ws.jws2.ParameterUtils.copyOption(o);
1380                 } catch (Exception e)
1381                 {
1382                   System.err.println("Failed to copy " + o.getName());
1383                   e.printStackTrace();
1384                 } catch (Error e)
1385                 {
1386                   System.err.println("Failed to copy " + o.getName());
1387                   e.printStackTrace();
1388                 }
1389               }
1390             }
1391             {
1392               System.out.println("Testing param dupes:");
1393               List<Parameter> rg = lastserv.getRunnerConfig()
1394                       .getParameters();
1395               for (Parameter o : rg)
1396               {
1397                 try
1398                 {
1399                   Parameter cpy = jalview.ws.jws2.ParameterUtils
1400                           .copyParameter(o);
1401                 } catch (Exception e)
1402                 {
1403                   System.err.println("Failed to copy " + o.getName());
1404                   e.printStackTrace();
1405                 } catch (Error e)
1406                 {
1407                   System.err.println("Failed to copy " + o.getName());
1408                   e.printStackTrace();
1409                 }
1410               }
1411             }
1412             WsJobParameters pgui = new WsJobParameters(lastserv, pr);
1413             JFrame jf = new JFrame("Parameters for "
1414                     + lastserv.getActionText());
1415             JPanel cont = new JPanel();
1416             // jf.setPreferredSize(new Dimension(600, 800));
1417             cont.add(pgui);
1418             jf.add(cont);
1419             final Thread thr = Thread.currentThread();
1420             jf.addWindowListener(new WindowListener()
1421             {
1422
1423               public void windowActivated(WindowEvent e)
1424               {
1425                 // TODO Auto-generated method stub
1426
1427               }
1428
1429               public void windowClosed(WindowEvent e)
1430               {
1431               }
1432
1433               public void windowClosing(WindowEvent e)
1434               {
1435                 thr.interrupt();
1436
1437               }
1438
1439               public void windowDeactivated(WindowEvent e)
1440               {
1441                 // TODO Auto-generated method stub
1442
1443               }
1444
1445               public void windowDeiconified(WindowEvent e)
1446               {
1447                 // TODO Auto-generated method stub
1448
1449               }
1450
1451               public void windowIconified(WindowEvent e)
1452               {
1453                 // TODO Auto-generated method stub
1454
1455               }
1456
1457               public void windowOpened(WindowEvent e)
1458               {
1459                 // TODO Auto-generated method stub
1460
1461               }
1462
1463             });
1464             jf.setVisible(true);
1465             boolean inter = false;
1466             while (!inter)
1467             {
1468               try
1469               {
1470                 Thread.sleep(10000);
1471               } catch (Exception e)
1472               {
1473                 inter = true;
1474               }
1475               ;
1476             }
1477             jf.dispose();
1478           }
1479         }
1480       }
1481     }
1482   }
1483
1484   public List<Argument> getJobParams()
1485   {
1486     List<Argument> argSet = new ArrayList<Argument>();
1487     // recover options and parameters from GUI
1488     for (OptionBox opts : optSet.values())
1489     {
1490       Option opt = opts.getOptionIfEnabled();
1491       if (opt != null)
1492       {
1493         argSet.add(opt);
1494       }
1495     }
1496     for (ParamBox parambox : paramSet.values())
1497     {
1498       Parameter parm = parambox.getParameter();
1499       if (parm != null)
1500       {
1501         argSet.add(parm);
1502       }
1503     }
1504
1505     return argSet;
1506   }
1507
1508   String lastParmSet = null;
1509
1510   Hashtable<String, Object[]> editedParams = new Hashtable<String, Object[]>();
1511
1512   /**
1513    * store the given parameters in the user parameter set database.
1514    * 
1515    * @param storeSetName
1516    *          - lastParmSet
1517    * @param descr
1518    *          - setDescr.getText()
1519    * @param jobParams
1520    *          - getJobParams()
1521    */
1522   private void _storeUserPreset(String storeSetName, String descr,
1523           List<Argument> jobParams)
1524   {
1525     // this is a simple hash store.
1526     Object[] pset;
1527     editedParams.put(storeSetName, pset = new Object[3]);
1528     pset[0] = storeSetName;
1529     pset[1] = descr;
1530     pset[2] = jobParams;
1531     //writeParam("Saving " + storeSetName + ": ", jobParams);
1532   }
1533
1534   private void writeParam(String nm, List<Argument> params)
1535   {
1536     for (Argument p : params)
1537     {
1538       System.out.println(nm + ":" + System.identityHashCode(p) + " Name: "
1539               + p.getName() + " Value: " + p.getDefaultValue());
1540     }
1541   }
1542
1543   private Object[] _getUserPreset(String setName)
1544   {
1545     Object[] pset = editedParams.get(setName);
1546     //if (pset != null)
1547     //  writeParam("Retrieving " + setName + ": ", (List<Argument>) pset[2]);
1548     return pset;
1549   }
1550
1551   /**
1552    * remove the given user preset from the preset stash
1553    * 
1554    * @param setName
1555    */
1556   private void _deleteUserPreset(String setName)
1557   {
1558     editedParams.remove(setName);
1559   }
1560
1561   private void syncSetNamesWithStore()
1562   {
1563     int n = 0;
1564     // remove any set names in the drop down menu that aren't either a reserved
1565     // setting, or a user defined or service preset.
1566     while (n < setName.getItemCount())
1567     {
1568       String item = (String) setName.getItemAt(n);
1569       if (!isServicePreset(item) && _getUserPreset(item) == null)
1570       {
1571         setName.removeItemAt(n);
1572       }
1573       else
1574       {
1575         n++;
1576       }
1577
1578     }
1579   }
1580
1581   private void reInitDialog(String nextPreset)
1582   {
1583     settingDialog = true;
1584     syncSetNamesWithStore();
1585     // updateTable(null,null); // first reset to defaults
1586
1587     Object[] pset = _getUserPreset(nextPreset);
1588     if (pset != null)
1589     {
1590       setDescr.setText((String) pset[1]);
1591       updateTable(null, (List<Argument>) pset[2]);
1592       lastParmSet = nextPreset;
1593       validate();
1594     }
1595     else
1596     {
1597       setDescr.setText("");
1598       // must be a default preset from service
1599       Preset p = null;
1600       try
1601       {
1602         PresetManager prman = service.getPresets();
1603         if (prman != null)
1604         {
1605           p = prman.getPresetByName(nextPreset);
1606         }
1607       } catch (Exception ex)
1608       {
1609         ex.printStackTrace();
1610       }
1611       if (p != null)
1612       {
1613         updateTable(p, null);
1614         lastParmSet = nextPreset;
1615       }
1616       else
1617       {
1618         updateTable(null, null);
1619       }
1620     }
1621     initArgSetModified();
1622     validate();
1623     settingDialog = false;
1624
1625   }
1626
1627   String curSetName = null;
1628
1629   public void itemStateChanged(ItemEvent e)
1630   {
1631     if (settingDialog)
1632     {
1633       // ignore event
1634       return;
1635     }
1636     if (e.getSource() == setName)
1637     {
1638       String setname = (String) setName.getSelectedItem();
1639       if (setname == null)
1640       {
1641         return;
1642       }
1643       if (curSetName == null || !setname.equals(curSetName))
1644       {
1645         settingDialog = true;
1646         if (isModified())
1647         {
1648           System.out.println("Prompting for "+setname);
1649           if (javax.swing.JOptionPane.showConfirmDialog(this,
1650                   "Parameter set is modifed - save ?", "Save changes ?",
1651                   javax.swing.JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION)
1652           {
1653             System.out.println("Saving for "+setname);
1654             savModified_actionPerformed(null);
1655           }
1656         }
1657         reInitDialog(setname);
1658
1659       }
1660     }
1661   }
1662
1663   /**
1664    * last saved name for this user preset
1665    */
1666   String lastSetName = null;
1667
1668   /**
1669    * last saved value of the description text for this user preset
1670    */
1671   String lastDescrText = null;
1672
1673   public void actionPerformed(ActionEvent e)
1674   {
1675     if (e.getSource() instanceof Component)
1676     {
1677       Component src = (Component) e.getSource();
1678       if (src.getParent() == setName)
1679       {
1680         // rename any existing records we know about for this set.
1681         String newname = (String) e.getActionCommand();
1682         String msg = null;
1683         if (isServicePreset(newname))
1684         {
1685           JOptionPane.showConfirmDialog(this,
1686                   "Invalid name - preset already exists.", "Invalid name",
1687                   JOptionPane.OK_OPTION);
1688           return;
1689         }
1690         curSetName = newname;
1691         System.err.println("Command " + curSetName + " : "
1692                 + setName.getSelectedItem());
1693         if (curSetName.trim().equals(setName.getSelectedItem()))
1694         {
1695           curSetName = null;
1696         }
1697         if (curSetName != null)
1698         {
1699           setName.addItem(curSetName);
1700           setName.setSelectedItem(curSetName);
1701           argSetModified(setName,
1702                   lastSetName != null && !curSetName.equals(lastSetName));
1703           return;
1704         }
1705
1706       }
1707     }
1708   }
1709
1710   private void checkDescrModified()
1711   {
1712     if (!settingDialog)
1713     {
1714
1715       argSetModified(
1716               setDescr,
1717               (lastDescrText == null ? setDescr.getText().trim().length() > 0
1718                       : !setDescr.getText().equals(lastDescrText)));
1719
1720     }
1721   }
1722
1723   public void insertUpdate(DocumentEvent e)
1724   {
1725     checkDescrModified();
1726   }
1727
1728   public void removeUpdate(DocumentEvent e)
1729   {
1730     checkDescrModified();
1731   }
1732
1733   public void changedUpdate(DocumentEvent e)
1734   {
1735     checkDescrModified();
1736   }
1737 }