7c4391e774fba2f41a869ebf81d28f90a184783a
[jalview.git] / src / jalview / gui / WsJobParameters.java
1 package jalview.gui;
2
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.Dimension;
6 import java.awt.FlowLayout;
7 import java.awt.Font;
8 import java.awt.GridLayout;
9 import java.awt.event.ActionEvent;
10 import java.awt.event.ActionListener;
11 import java.awt.event.ComponentEvent;
12 import java.awt.event.ComponentListener;
13 import java.awt.event.ContainerEvent;
14 import java.awt.event.ContainerListener;
15 import java.awt.event.MouseEvent;
16 import java.awt.event.MouseListener;
17 import java.awt.event.WindowEvent;
18 import java.awt.event.WindowListener;
19 import java.awt.event.WindowStateListener;
20 import java.util.ArrayList;
21 import java.util.EventObject;
22 import java.util.HashSet;
23 import java.util.Hashtable;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Vector;
27
28 import javax.swing.JButton;
29 import javax.swing.JCheckBox;
30 import javax.swing.JComboBox;
31 import javax.swing.JFrame;
32 import javax.swing.JLabel;
33 import javax.swing.JOptionPane;
34 import javax.swing.JPanel;
35 import javax.swing.JScrollPane;
36 import javax.swing.JTable;
37 import javax.swing.JTextArea;
38 import javax.swing.ListSelectionModel;
39 import javax.swing.SwingUtilities;
40 import javax.swing.border.TitledBorder;
41 import javax.swing.event.CellEditorListener;
42 import javax.swing.table.*;
43
44 import compbio.metadata.Argument;
45 import compbio.metadata.Option;
46 import compbio.metadata.Parameter;
47 import compbio.metadata.Preset;
48 import compbio.metadata.PresetManager;
49 import compbio.metadata.RunnerConfig;
50 import compbio.metadata.ValueConstrain;
51 import compbio.metadata.ValueConstrain.Type;
52
53 import jalview.ws.jws2.Jws2Discoverer;
54 import jalview.ws.jws2.Jws2Discoverer.Jws2Instance;
55
56 public class WsJobParameters extends JPanel
57 {
58   JPanel setDetails = new JPanel();
59
60   JPanel settingsPanel = new JPanel();
61
62   JPanel jobOptions = new JPanel();
63
64   JPanel jobParameters = new JPanel();
65
66   JPanel paramButtons = new JPanel();
67
68   JButton exportParams = new JButton();
69
70   JButton importParams = new JButton();
71
72   JButton resetParams = new JButton();
73
74   JButton addParam = new JButton();
75
76   JButton removeParam = new JButton();
77
78   JButton editParam = new JButton();
79
80   JLabel setName = new JLabel();
81
82   JTextArea setDescr = new JTextArea();
83
84   JTable paramTable = new JTable();
85
86   JScrollPane paramPane = new JScrollPane();
87
88   RunnerConfig serviceOptions;
89
90   List<Parameter> availableParameters;
91
92   private BorderLayout jparamLayout;
93
94   WsJobParameters(Jws2Instance service)
95   {
96     this(service, null);
97   }
98
99   public WsJobParameters(Jws2Instance service, Preset p)
100   {
101     this(null, service, p);
102   }
103
104   /**
105    * 
106    * @param desktop
107    *          - if null, create new JFrame outside of desktop
108    * @param service
109    * @param p
110    */
111   public WsJobParameters(JFrame parent, Jws2Instance service, Preset p)
112   {
113     super();
114     jbInit();
115     initTableUI();
116     // populate parameter table
117     initForService(service, p);
118     // display in new JFrame attached to parent.
119     validate();
120   }
121
122   private void jbInit()
123   {
124     exportParams.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
125     exportParams.setText("Export");
126     exportParams.setToolTipText("Export parameters to a file");
127     exportParams.addActionListener(new ActionListener()
128     {
129       public void actionPerformed(ActionEvent e)
130       {
131         exportParams_actionPerformed(e);
132       }
133     });
134     importParams.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
135     importParams.setText("Import");
136     importParams.setToolTipText("Import parameters from a file");
137     importParams.addActionListener(new ActionListener()
138     {
139       public void actionPerformed(ActionEvent e)
140       {
141         importParams_actionPerformed(e);
142       }
143     });
144     resetParams.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
145     resetParams.setText("Defaults");
146     resetParams.setToolTipText("Reset to defaults");
147     resetParams.addActionListener(new ActionListener()
148     {
149       public void actionPerformed(ActionEvent e)
150       {
151         resetParams_actionPerformed(e);
152       }
153     });
154     addParam.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
155     addParam.setText("Add");
156     addParam.setToolTipText("Add new parameter");
157     addParam.addActionListener(new ActionListener()
158     {
159       public void actionPerformed(ActionEvent e)
160       {
161         addParam_actionPerformed(e);
162       }
163     });
164     removeParam.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
165     removeParam.setText("Remove");
166     removeParam.setToolTipText("Remove selected parameter");
167     removeParam.addActionListener(new ActionListener()
168     {
169       public void actionPerformed(ActionEvent e)
170       {
171         removeParam_actionPerformed(e);
172       }
173     });
174     editParam.setFont(new java.awt.Font("Verdana", Font.PLAIN, 10));
175     editParam.setText("Edit");
176     editParam.setToolTipText("Edit selected parameter");
177     editParam.addActionListener(new ActionListener()
178     {
179       public void actionPerformed(ActionEvent e)
180       {
181         editParam_actionPerformed(e);
182       }
183     });
184
185     setDetails.setBorder(new TitledBorder("Details"));
186     setDetails.setLayout(new GridLayout(2, 1));
187     setDescr.setColumns(40);
188     setDescr.setWrapStyleWord(true);
189     setDescr.setPreferredSize(new Dimension(350, 100));
190     setDetails.add(setName);
191     setDetails.add(setDescr);
192     setDetails.setPreferredSize(new Dimension(360, 150));
193     settingsPanel.setLayout(new BorderLayout());
194     jobOptions.setBorder(new TitledBorder("Options"));
195     jobParameters.setBorder(new TitledBorder("Parameters"));
196     jobParameters.setLayout(jparamLayout = new BorderLayout());
197     paramPane.setPreferredSize(new Dimension(360, 300));
198     paramButtons.setLayout(new GridLayout(2, 3));
199     paramButtons.add(addParam);
200     paramButtons.add(editParam);
201     paramButtons.add(removeParam);
202     // TODO: relayout buttons nicely
203     paramButtons.add(exportParams);
204     paramButtons.add(importParams);
205     paramButtons.add(resetParams);
206     jobParameters.add(paramPane, BorderLayout.NORTH);
207     jobParameters.add(paramButtons, BorderLayout.SOUTH);
208     settingsPanel.add(jobOptions, BorderLayout.NORTH);
209     settingsPanel.add(jobParameters, BorderLayout.SOUTH);
210     setLayout(new BorderLayout());
211     setPreferredSize(new Dimension(400, 600));
212     setSize(new Dimension(400, 600));
213     add(setDetails, BorderLayout.NORTH);
214     add(settingsPanel, BorderLayout.CENTER);
215   }
216
217   /**
218    * need to populate table and validate after calling this to set up table and
219    * add it to pane
220    */
221   public void initTableUI()
222   {
223     paramTable = new JTable();
224     paramTable.getTableHeader()
225             .setFont(new Font("Verdana", Font.PLAIN, 12));
226     paramTable.setFont(new Font("Verdana", Font.PLAIN, 12));
227
228     paramPane.getViewport().removeAll();
229     paramPane.getViewport().add(paramTable);
230     paramTable.setDefaultRenderer(Argument.class, new ArgumentRenderer());
231     paramTable.setDefaultRenderer(Parameter.class, new ArgumentRenderer());
232     paramTable.setDefaultRenderer(Option.class, new ArgumentRenderer());
233     paramTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
234     paramTable.addMouseListener(new MouseListener()
235     {
236
237       @Override
238       public void mouseClicked(MouseEvent e)
239       {
240         if (e.getClickCount() > 1)
241         {
242           editParam_actionPerformed(null);
243         }
244       }
245
246       @Override
247       public void mouseEntered(MouseEvent e)
248       {
249         // tooltips
250         // TODO Auto-generated method stub
251
252       }
253
254       @Override
255       public void mouseExited(MouseEvent e)
256       {
257         // tooltips
258         // TODO Auto-generated method stub
259
260       }
261
262       @Override
263       public void mousePressed(MouseEvent e)
264       {
265         // TODO Auto-generated method stub
266
267       }
268
269       @Override
270       public void mouseReleased(MouseEvent e)
271       {
272         // TODO Auto-generated method stub
273
274       }
275
276     });
277     // paramTable.setDefaultEditor(Argument.class, new WsArgumentEditor(this));
278   }
279
280   public class WsArgumentEditor implements TableCellEditor
281   {
282
283     int p;
284
285     Argument arg;
286
287     WsJobParameters wsparm;
288
289     public WsArgumentEditor(WsJobParameters wsJobParameters)
290     {
291       wsparm = wsJobParameters;
292       p = wsparm.paramTable.getSelectedRow();
293       arg = (Argument) wsparm.paramTable.getValueAt(p, wsparm.paramTable
294               .getSelectedColumn());
295       /*
296        * if (arg instanceof Option) { if
297        * (JOptionPane.showInternalConfirmDialog(Desktop.desktop,
298        * "Remove option "+arg.getName(),
299        * "Delete option ?",JOptionPane.YES_NO_OPTION,
300        * JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
301        * 
302        * } }
303        */
304     }
305
306     @Override
307     public Component getTableCellEditorComponent(JTable table,
308             Object value, boolean isSelected, int row, int column)
309     {
310       // TODO Auto-generated method stub
311       return null;
312     }
313
314     @Override
315     public void addCellEditorListener(CellEditorListener l)
316     {
317       // TODO Auto-generated method stub
318
319     }
320
321     @Override
322     public void cancelCellEditing()
323     {
324       // TODO Auto-generated method stub
325
326     }
327
328     @Override
329     public Object getCellEditorValue()
330     {
331       // TODO Auto-generated method stub
332       return null;
333     }
334
335     @Override
336     public boolean isCellEditable(EventObject anEvent)
337     {
338       // TODO Auto-generated method stub
339       return false;
340     }
341
342     @Override
343     public void removeCellEditorListener(CellEditorListener l)
344     {
345       // TODO Auto-generated method stub
346
347     }
348
349     @Override
350     public boolean shouldSelectCell(EventObject anEvent)
351     {
352       // TODO Auto-generated method stub
353       return false;
354     }
355
356     @Override
357     public boolean stopCellEditing()
358     {
359       // TODO Auto-generated method stub
360       return false;
361     }
362
363   }
364
365   protected void editParam_actionPerformed(ActionEvent e)
366   {
367     // TODO Auto-generated method stub
368
369   }
370
371   protected void removeParam_actionPerformed(ActionEvent e)
372   {
373     // TODO Auto-generated method stub
374
375   }
376
377   protected void addParam_actionPerformed(ActionEvent e)
378   {
379     // TODO Auto-generated method stub
380
381   }
382
383   protected void resetParams_actionPerformed(ActionEvent e)
384   {
385     // TODO Auto-generated method stub
386
387   }
388
389   protected void importParams_actionPerformed(ActionEvent e)
390   {
391     // TODO Auto-generated method stub
392
393   }
394
395   protected void exportParams_actionPerformed(ActionEvent e)
396   {
397     // TODO Auto-generated method stub
398
399   }
400
401   void initForService(Jws2Instance service, Preset p)
402   {
403     serviceOptions = service.getRunnerConfig();
404     updateTable(p);
405   }
406
407   @SuppressWarnings("unchecked")
408   private void updateTable(Preset p)
409   {
410     WsParameterTableModel mdl = null;
411     TableModel tmdl = paramTable.getModel();
412     if (tmdl instanceof WsParameterTableModel)
413     {
414       mdl = (WsParameterTableModel) tmdl;
415     }
416     if (mdl == null)
417     {
418       paramTable.setModel(mdl = new WsParameterTableModel());
419     }
420     availableParameters = new ArrayList<Parameter>();
421     List<Parameter> setargs = new ArrayList<Parameter>();
422     // populate table from default parameter set.
423     List<Argument> args = serviceOptions.getArguments();
424     
425     // split to params and required arguments
426     {
427       for (Argument arg : args)
428       {
429         Argument myarg = (Argument) arg;
430         // Ideally, Argument would implement isRequired !
431         if (myarg instanceof Parameter)
432         {
433           Parameter parm = (Parameter) myarg;
434           if (parm.isRequired())
435           {
436             setargs.add(parm);
437           }
438           else
439           {
440             availableParameters.add(parm);
441           }
442         }
443         else
444         {
445           if (myarg instanceof Option)
446           {
447             Option opt = (Option) myarg;
448             addOption(opt);
449             if (opt.isRequired())
450             {
451               selectOption(opt, opt.getDefaultValue());
452             }
453           }
454           else
455           {
456             System.err.println("Ignoring unknown service argument type "
457                     + arg.getClass().getName());
458           }
459         }
460       }
461     }
462
463     if (p != null)
464     {
465       setDescr.setText(p.getDescription());
466       setName.setText(p.getName());
467       // TODO - URL link
468       try
469       {
470         args = p.getArguments(serviceOptions);
471       } catch (Exception e)
472       {
473         e.printStackTrace();
474       }
475       setargs.clear();
476       // get setargs from current object
477       if (args != null)
478       {
479         for (Argument arg : args)
480         {
481           if (arg instanceof Parameter)
482           {
483             setargs.add((Parameter) arg);
484           }
485           else
486           {
487             if (arg instanceof Option)
488             {
489               selectOption((Option) arg, arg.getDefaultValue());
490             }
491           }
492
493         }
494       }
495     }
496
497     mdl.setData(setargs);
498     paramTable.setModel(mdl);
499     // paramTable.validate();
500     jobOptions.setLayout(new GridLayout(optSet.size() / 2 + 1, 2));
501     jobOptions.validate();
502   }
503
504   private void selectOption(Option opt, String string)
505   {
506     OptionBox cb = optSet.get(opt.getName());
507     if (cb == null)
508     {
509       cb = addOption(opt);
510     }
511     if (string == null)
512     {
513       // no value specified.
514       if (opt.isRequired())
515       {
516         // indicate option needs to be selected!
517       }
518       else
519       {
520         cb.enabled.setSelected(false);
521       }
522     }
523     else
524     {
525       cb.enabled.setSelected(true);
526
527       if (opt.getPossibleValues().contains(string))
528       {
529         cb.val.setSelectedItem(string);
530       }
531       else
532       {
533         throw new Error("Invalid value " + string + " for option " + opt);
534       }
535
536     }
537   }
538
539   Map<String, OptionBox> optSet = new Hashtable<String, OptionBox>();
540
541   public class OptionBox extends JPanel
542   {
543     JComboBox val = new JComboBox();
544
545     JCheckBox enabled = new JCheckBox();
546
547     public OptionBox(Option opt)
548     {
549       setLayout(new BorderLayout());
550       enabled.setSelected(opt.isRequired());
551       enabled.setFont(new Font("Verdana", Font.PLAIN, 11));
552       enabled.setText(opt.getName());
553       enabled.setToolTipText(opt.getDescription());
554       add(enabled, BorderLayout.NORTH);
555       if (opt.getPossibleValues().size() > 1)
556       {
557         setLayout(new GridLayout(1,2));
558         for (Object str : opt.getPossibleValues())
559         {
560           val.addItem((String) str);
561         }
562         val.setSelectedItem((String) opt.getDefaultValue());
563         add(val, BorderLayout.SOUTH);
564       }
565       // TODO: add actionListeners for popup (to open further info), 
566       // and to update list of parameters if an option is enabled
567       // that takes a value.
568     }
569   }
570
571   private OptionBox addOption(Option opt)
572   {
573     OptionBox cb = optSet.get(opt.getName());
574     if (cb == null)
575     {
576       cb = new OptionBox(opt);
577       optSet.put(opt.getName(), cb);
578       jobOptions.add(cb);
579     }
580     return cb;
581   }
582
583   class WsParameterTableModel extends AbstractTableModel
584   {
585     // arg list - vector for thread safety
586     public Vector<Parameter> data = new Vector<Parameter>();
587
588     private String[] colNames =
589     { "Parameter", "Value" };
590
591     @Override
592     public int getColumnCount()
593     {
594       return 2;
595     }
596
597     @Override
598     public int findColumn(String columnName)
599     {
600       // TODO Auto-generated method stub
601       return super.findColumn(columnName);
602     }
603
604     public void setData(List<Parameter> setargs)
605     {
606       if (setargs != null)
607       {
608         data = new Vector<Parameter>(setargs);
609
610       }
611       else
612       {
613         data = new Vector<Parameter>();
614       }
615     }
616
617     public List<Parameter> getData()
618     {
619       return new ArrayList<Parameter>(data);
620     }
621
622     @Override
623     public int getRowCount()
624     {
625       return data.size();
626     }
627
628     @Override
629     public Object getValueAt(int rowIndex, int columnIndex)
630     {
631       if (rowIndex >= 0 && rowIndex < data.size())
632       {
633         Parameter prm = data.elementAt(rowIndex);
634         switch (columnIndex)
635         {
636         case 0:
637           return prm.getName();
638         case 1:
639           Object exc = null;
640           // the accessor name for the parameter value is possibly confusing
641           String val = prm.getDefaultValue();
642           try
643           {
644             if (prm.getValidValue().getType().equals(Type.Float))
645             {
646               exc = new Float(0);
647               return Float.parseFloat(val);
648             }
649             if (prm.getValidValue().getType().equals(Type.Integer))
650             {
651               exc = new Integer(0);
652               return Integer.parseInt(val);
653             }
654           } catch (NumberFormatException e)
655           {
656             return exc;
657           }
658           // must be a string
659           return val;
660
661         default:
662         }
663       }
664       return null;
665     }
666
667     /*
668      * (non-Javadoc)
669      * 
670      * @see javax.swing.table.AbstractTableModel#getColumnClass(int)
671      */
672     @Override
673     public Class<?> getColumnClass(int columnIndex)
674     {
675       switch (columnIndex)
676       {
677       case 0:
678         return String.class;
679       case 1:
680         return Parameter.class;
681       }
682       return super.getColumnClass(columnIndex);
683     }
684
685     /*
686      * (non-Javadoc)
687      * 
688      * @see javax.swing.table.AbstractTableModel#getColumnName(int)
689      */
690     @Override
691     public String getColumnName(int column)
692     {
693       return colNames[column];
694     }
695
696     /*
697      * (non-Javadoc)
698      * 
699      * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int)
700      */
701     @Override
702     public boolean isCellEditable(int rowIndex, int columnIndex)
703     {
704       if (columnIndex == 1)
705       {
706         return true;
707       }
708       return false;
709     }
710   }
711
712   class ArgumentRenderer implements TableCellRenderer
713   {
714
715     @Override
716     public Component getTableCellRendererComponent(JTable table,
717             Object value, boolean isSelected, boolean hasFocus, int row,
718             int column)
719     {
720       if (value instanceof Option)
721       {
722         JCheckBox cb = new JCheckBox();
723         cb.setSelected(true);
724         return cb;
725       }
726       if (value instanceof Boolean)
727       {
728         JCheckBox cb = new JCheckBox();
729         cb.setSelected(((Boolean) value).booleanValue());
730         return cb;
731       }
732       if (value instanceof String)
733       {
734         JLabel lbl = new JLabel();
735         lbl.setFont(new Font("Verdana", Font.PLAIN, 11));
736         lbl.setText((String) value);
737         return lbl;
738       }
739       if (value instanceof Parameter)
740       {
741         String val = ((Parameter) value).getDefaultValue();
742         ValueConstrain constr = ((Parameter) value).getValidValue();
743         JLabel lbl = new JLabel();
744         lbl.setFont(new Font("Verdana", Font.PLAIN, 11));
745         lbl.setText(val);
746         return lbl;
747         /*
748          * type dependent return value if
749          * (constr.getType().equals(Type.Integer))
750          * 
751          * { lbl.setText(val); } if (constr.getType().equals(Type.Float)) { }
752          * return lbl;
753          */
754       }
755       return null;
756     }
757   }
758
759   /**
760    * testing method - grab a service and parameter set and show the window
761    * 
762    * @param args
763    */
764   public static void main(String[] args)
765   {
766     jalview.ws.jws2.Jws2Discoverer disc = jalview.ws.jws2.Jws2Discoverer
767             .getDiscoverer();
768     int p = 0;
769     if (args.length > 3)
770     {
771       Vector<String> services = new Vector<String>();
772       services.addElement(args[p++]);
773       Jws2Discoverer.setServiceUrls(services);
774     }
775     try
776     {
777       disc.run();
778     } catch (Exception e)
779     {
780       System.err.println("Aborting. Problem discovering services.");
781       e.printStackTrace();
782       return;
783     }
784     Jws2Discoverer.Jws2Instance lastserv = null;
785     for (Jws2Discoverer.Jws2Instance service : disc.getServices())
786     {
787       lastserv = service;
788       if (p < args.length && service.serviceType.equalsIgnoreCase(args[p]))
789       {
790         break;
791       }
792     }
793     if (lastserv != null)
794     {
795       Preset pr = null;
796       if (++p < args.length)
797       {
798         PresetManager prman = lastserv.getPresets();
799         if (prman != null)
800         {
801           pr = prman.getPresetByName(args[p]);
802           if (pr == null)
803           {
804             // just grab the last preset.
805             List<Preset> prl = prman.getPresets();
806             pr = prl.get(prl.size() - 1);
807           }
808         }
809       }
810       while (true)
811       {
812         WsJobParameters pgui = new WsJobParameters(lastserv, pr);
813         JFrame jf = new JFrame("Parameters for " + lastserv.getActionText());
814         JPanel cont = new JPanel();
815         cont.setSize(new Dimension(600, 800));
816         cont.add(pgui);
817         jf.add(cont);
818         final Thread thr = Thread.currentThread();
819         jf.addWindowListener(new WindowListener()
820         {
821
822           @Override
823           public void windowActivated(WindowEvent e)
824           {
825             // TODO Auto-generated method stub
826
827           }
828
829           @Override
830           public void windowClosed(WindowEvent e)
831           {
832           }
833
834           @Override
835           public void windowClosing(WindowEvent e)
836           {
837             thr.interrupt();
838
839           }
840
841           @Override
842           public void windowDeactivated(WindowEvent e)
843           {
844             // TODO Auto-generated method stub
845
846           }
847
848           @Override
849           public void windowDeiconified(WindowEvent e)
850           {
851             // TODO Auto-generated method stub
852
853           }
854
855           @Override
856           public void windowIconified(WindowEvent e)
857           {
858             // TODO Auto-generated method stub
859
860           }
861
862           @Override
863           public void windowOpened(WindowEvent e)
864           {
865             // TODO Auto-generated method stub
866
867           }
868
869         });
870         jf.setVisible(true);
871         boolean inter = false;
872         while (!inter)
873         {
874           try
875           {
876             Thread.sleep(10000);
877           } catch (Exception e)
878           {
879             inter = true;
880           }
881           ;
882         }
883         jf.dispose();
884       }
885     }
886   }
887 }