1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package uk.ac.rdg.resc.jstyx.gridservice.client;
30
31 import java.util.Hashtable;
32 import java.io.File;
33 import java.io.IOException;
34
35 import javax.swing.JFrame;
36 import javax.swing.JPanel;
37 import javax.swing.JLabel;
38 import javax.swing.JScrollPane;
39 import javax.swing.JTable;
40 import javax.swing.JButton;
41 import javax.swing.JOptionPane;
42 import javax.swing.JRadioButton;
43 import javax.swing.ButtonGroup;
44 import javax.swing.BorderFactory;
45 import javax.swing.JTextField;
46 import javax.swing.JFileChooser;
47 import javax.swing.JComboBox;
48
49 import javax.swing.table.DefaultTableModel;
50 import javax.swing.table.AbstractTableModel;
51
52 import java.awt.event.ActionListener;
53 import java.awt.event.ActionEvent;
54 import java.awt.Dimension;
55 import java.awt.BorderLayout;
56
57 import java.util.Vector;
58 import java.util.Iterator;
59 import java.util.Enumeration;
60
61 import info.clearthought.layout.TableLayout;
62
63 import org.apache.mina.common.ByteBuffer;
64
65 import uk.ac.rdg.resc.jstyx.StyxException;
66 import uk.ac.rdg.resc.jstyx.client.CStyxFile;
67 import uk.ac.rdg.resc.jstyx.client.CStyxFileChangeListener;
68 import uk.ac.rdg.resc.jstyx.types.DirEntry;
69 import uk.ac.rdg.resc.jstyx.messages.TwriteMessage;
70 import uk.ac.rdg.resc.jstyx.messages.TreadMessage;
71 import uk.ac.rdg.resc.jstyx.gridservice.config.SGSParam;
72
73 /***
74 * GUI for interacting with an SGS instance. This class DOES NOT WORK at the
75 * moment! It's based on an older version of the SGS software and has not yet
76 * been updated.
77 *
78 * @author Jon Blower
79 * $Revision: 589 $
80 * $Date: 2006-02-20 17:35:01 +0000 (Mon, 20 Feb 2006) $
81 * $Log$
82 * Revision 1.30 2006/02/20 17:35:01 jonblower
83 * Implemented correct handling of output files/streams (not fully tested yet)
84 *
85 * Revision 1.29 2005/12/09 18:41:56 jonblower
86 * Continuing to simplify client interface to SGS instances
87 *
88 * Revision 1.28 2005/12/07 17:50:01 jonblower
89 * Changed gotCommandLine() to gotArguments()
90 *
91 * Revision 1.27 2005/12/07 08:56:32 jonblower
92 * Refactoring SGS client code
93 *
94 * Revision 1.25 2005/11/10 19:49:28 jonblower
95 * Renamed SGSInstanceChangeListener to SGSInstanceClientChangeListener
96 *
97 * Revision 1.24 2005/10/18 14:08:14 jonblower
98 * Removed inputfiles from namespace
99 *
100 * Revision 1.23 2005/10/14 18:09:40 jonblower
101 * Changed getInputMethods() to getInputStreams() and added synchronous and async versions
102 *
103 * Revision 1.21 2005/09/11 19:30:40 jonblower
104 * Changed call to readAllSteeringParams() to readAllSteeringParamsAsync()
105 *
106 * Revision 1.20 2005/09/09 16:34:03 jonblower
107 * Removed LBViewer as possible stream viewer
108 *
109 * Revision 1.19 2005/09/09 14:19:35 jonblower
110 * Created populatePanel() methods in panel implementations to send messages to get panel details
111 *
112 * Revision 1.18 2005/08/12 08:08:39 jonblower
113 * Developments to support web interface
114 *
115 * Revision 1.17 2005/08/04 16:49:18 jonblower
116 * Added and edited upload() methods in CStyxFile
117 *
118 * Revision 1.15 2005/08/01 16:38:05 jonblower
119 * Implemented simple parameter handling
120 *
121 * Revision 1.14 2005/07/29 16:55:49 jonblower
122 * Implementing reading command line asynchronously
123 *
124 * Revision 1.13 2005/06/14 07:45:16 jonblower
125 * Implemented setting of params and async notification of parameter changes
126 *
127 * Revision 1.12 2005/06/13 16:46:35 jonblower
128 * Implemented setting of parameter values via the GUI
129 *
130 * Revision 1.11 2005/06/10 07:54:40 jonblower
131 * Added code to convert event-based StreamViewer to InputStream-based one
132 *
133 * Revision 1.10 2005/06/07 16:44:45 jonblower
134 * Fixed problem with caching stream reader on client side
135 *
136 * Revision 1.9 2005/05/27 17:05:07 jonblower
137 * Changes to incorporate GeneralCachingStreamReader
138 *
139 * Revision 1.8 2005/05/27 07:44:07 jonblower
140 * Continuing to implement Stream viewers
141 *
142 * Revision 1.7 2005/05/26 21:33:40 jonblower
143 * Added method for viewing streams in a window
144 *
145 * Revision 1.6 2005/05/26 16:52:06 jonblower
146 * Implemented detection and viewing of output streams
147 *
148 * Revision 1.5 2005/05/25 16:59:31 jonblower
149 * Added uploadInputFile()
150 *
151 * Revision 1.4 2005/05/20 16:28:50 jonblower
152 * Continuing to implement GUI app
153 *
154 */
155 public class SGSInstanceGUI extends JFrame implements SGSInstanceClientChangeListener
156 {
157
158 private static final int ROW_HEIGHT = 20;
159 private static final int BORDER = 10;
160
161
162 private static final Hashtable guis = new Hashtable();
163
164 private SGSInstanceClient client;
165
166 private JPanel masterPanel;
167 private TableLayout panelLayout;
168 private InputPanel inputPanel;
169 private InputFilesPanel inputFilesPanel;
170 private ParamsPanel paramsPanel;
171 private SteeringPanel steeringPanel;
172 private ControlPanel ctlPanel;
173 private ServiceDataPanel sdPanel;
174 private OutputStreamsPanel osPanel;
175
176 private JLabel statusBar;
177
178 /*** Creates a new instance of SGSInstanceGUI */
179 private SGSInstanceGUI(SGSInstanceClient client)
180 {
181
182
183 super(client.getInstanceRoot().getURL().substring(7));
184 this.setBounds(200, 100, 550, 400);
185
186 this.client = client;
187 this.client.addChangeListener(this);
188
189
190 this.masterPanel = new JPanel();
191 this.setLayout(new BorderLayout());
192 this.add(new JScrollPane(this.masterPanel), BorderLayout.CENTER);
193 double size[][] =
194 {
195 { BORDER, TableLayout.FILL, BORDER },
196 { BORDER, TableLayout.PREFERRED, BORDER, TableLayout.PREFERRED, BORDER,
197 TableLayout.PREFERRED, BORDER, TableLayout.PREFERRED, BORDER,
198 ROW_HEIGHT, BORDER, TableLayout.FILL, BORDER,
199 TableLayout.PREFERRED, BORDER}
200 };
201 this.panelLayout = new TableLayout(size);
202 this.masterPanel.setLayout(this.panelLayout);
203
204
205 this.inputPanel = new InputPanel();
206 this.inputPanel.populatePanel();
207
208
209
210 this.inputFilesPanel = new InputFilesPanel();
211 this.inputFilesPanel.populatePanel();
212
213
214
215 Vector params = client.getParameters();
216 Vector paramNames = new Vector();
217 for (Iterator it = params.iterator(); it.hasNext(); )
218 {
219 SGSParam param = (SGSParam)it.next();
220 if (param.getType() == SGSParam.INPUT_FILE)
221 {
222
223 }
224 else if (param.getType() == SGSParam.OUTPUT_FILE)
225 {
226
227 }
228 else
229 {
230
231 paramNames.add(param.getName());
232 }
233 }
234 this.paramsPanel = new ParamsPanel((String[])paramNames.toArray(new String[0]));
235 this.masterPanel.add(this.paramsPanel, "1, 5");
236
237
238 this.steeringPanel = new SteeringPanel(client.getSteerableParameterNames());
239 this.masterPanel.add(this.steeringPanel, "1, 7");
240
241
242 this.ctlPanel = new ControlPanel();
243 this.masterPanel.add(this.ctlPanel, "1, 9");
244
245
246 this.sdPanel = new ServiceDataPanel(client.getServiceDataNames());
247 this.masterPanel.add(this.sdPanel, "1, 11");
248
249
250 this.osPanel = new OutputStreamsPanel();
251 this.osPanel.populatePanel();
252
253
254 this.statusBar = new JLabel("Status bar");
255 this.add(this.statusBar, BorderLayout.SOUTH);
256 statusBar.setBorder(BorderFactory.createLoweredBevelBorder());
257
258 this.repaintGUI();
259 }
260
261 public static SGSInstanceGUI getGUI(SGSInstanceClient client)
262 {
263
264
265 synchronized(guis)
266 {
267 if (guis.containsKey(client))
268 {
269 return (SGSInstanceGUI)guis.get(client);
270 }
271 else
272 {
273 SGSInstanceGUI gui = new SGSInstanceGUI(client);
274 guis.put(client, gui);
275 return gui;
276 }
277 }
278 }
279
280 /***
281 * Called when the value of a service data element changes
282 */
283 public void gotServiceDataValue(String sdName, String newData)
284 {
285 this.sdPanel.setSDEValue(sdName, newData);
286 }
287
288 /***
289 * Called when we have a new value for a parameter
290 * @param name Name of the parameter
291 * @param value The new value of the parameter
292 */
293 public void gotParameterValue(String name, String value)
294 {
295 this.paramsPanel.gotParameterValue(name, value);
296 }
297
298 /***
299 * Called when we have a new set of command line arguments
300 * @param newArgs The new command line arguments
301 */
302 public void gotArguments(String newArgs)
303 {
304 this.paramsPanel.setArguments(newArgs);
305 }
306
307 /***
308 * Called when we have a new value for a steerable parameter
309 * @param name Name of the steerable parameter
310 * @param value The new value of the parameter
311 */
312 public void gotSteerableParameterValue(String name, String value)
313 {
314 this.steeringPanel.gotSteeringParameterValue(name, value);
315 }
316
317 /***
318 * Forces the window to be laid out and packed
319 */
320 private void repaintGUI()
321 {
322 this.panelLayout.layoutContainer(this);
323 this.pack();
324 }
325
326 /***
327 * Called when an error occurs. Shows a dialog box with the message
328 */
329 public void error(String message)
330 {
331 JOptionPane.showMessageDialog(this, message, "Error", JOptionPane.ERROR_MESSAGE);
332 }
333
334 /***
335 * Called when the service is started
336 */
337 public void serviceStarted()
338 {
339
340
341 }
342
343 /***
344 * Called when the input files have been successfully uploaded. This is our
345 * cue to start the service going
346 * @todo add arguments to this
347 */
348 public void inputFilesUploaded()
349 {
350 this.client.startServiceAsync();
351 }
352
353 /***
354 * Called when the service is stopped before it has finished
355 */
356 public void serviceAborted() {}
357
358 /***
359 * Panel for providing input data to the SGS
360 */
361 private class InputPanel extends JPanel implements ActionListener
362 {
363 private TableLayout layout;
364 private JTextField inputURL;
365 private JButton btnPickFile;
366
367 public void populatePanel()
368 {
369
370
371
372
373
374 }
375
376 public void setInputStreams(CStyxFile[] inputStreams)
377 {
378
379
380 if (inputStreams.length > 0)
381 {
382 double[][] size =
383 {
384 { TableLayout.FILL, BORDER, TableLayout.PREFERRED },
385 { ROW_HEIGHT }
386 };
387 this.layout = new TableLayout(size);
388 this.setLayout(this.layout);
389
390 this.setBorder(BorderFactory.createTitledBorder("File to stream to stdin"));
391
392 this.inputURL = new JTextField();
393 this.add(this.inputURL, "0, 0");
394
395 this.btnPickFile = new JButton("Pick file");
396 this.btnPickFile.addActionListener(this);
397 this.add(this.btnPickFile, "2, 0");
398 }
399 }
400
401 public void actionPerformed(ActionEvent e)
402 {
403 if (e.getSource() == this.btnPickFile)
404 {
405 JFileChooser chooser = new JFileChooser();
406 int returnVal = chooser.showOpenDialog(this);
407 if (returnVal == JFileChooser.APPROVE_OPTION)
408 {
409 try
410 {
411 this.inputURL.setText(chooser.getSelectedFile().toURL().toString());
412 }
413 catch(java.net.MalformedURLException mue)
414 {
415
416 }
417 }
418 }
419 }
420
421 /***
422 * Return the input URL that has been set, or null if we haven't set
423 * a URL
424 */
425 public String getInputURL()
426 {
427 return this.inputURL == null ? null : this.inputURL.getText();
428 }
429 }
430
431 /***
432 * Panel for allowing uploading of input files
433 */
434 private class InputFilesPanel extends JPanel implements ActionListener
435 {
436 private TableLayout layout;
437 private JButton btnAddInputFile;
438 private Vector destFileNames;
439 private Vector srcFileLocations;
440 private Vector pickFileButtons;
441 private Vector deleteRowButtons;
442 private int numCompulsoryFiles;
443
444 public InputFilesPanel()
445 {
446 double[][] size =
447 {
448 { TableLayout.PREFERRED, BORDER, 300, BORDER, 80, BORDER, 80 },
449 { }
450 };
451 this.layout = new TableLayout(size);
452 this.setLayout(this.layout);
453 this.setBorder(BorderFactory.createTitledBorder("Input files to upload"));
454 }
455
456 public void populatePanel()
457 {
458
459
460 }
461
462 private void updateGUI()
463 {
464 this.layout.layoutContainer(this);
465 repaintGUI();
466 }
467
468 /***
469 * Called when we have found the input files required by this service
470 */
471 public void gotInputFiles(CStyxFile[] inputFiles, boolean allowOtherInputFiles)
472 {
473 this.numCompulsoryFiles = inputFiles.length;
474 this.destFileNames = new Vector();
475 this.srcFileLocations = new Vector();
476 this.pickFileButtons = new Vector();
477 this.deleteRowButtons = new Vector();
478
479 if (allowOtherInputFiles)
480 {
481
482 this.layout.insertRow(0, ROW_HEIGHT);
483 this.layout.insertRow(1, BORDER);
484 this.btnAddInputFile = new JButton("Add another input file");
485 this.btnAddInputFile.addActionListener(this);
486 this.add(btnAddInputFile, "0, 0, 2, 0, l, f");
487 }
488
489 for (int i = 0; i < inputFiles.length; i++)
490 {
491 this.addInputFileRow(inputFiles[i].getName(), false);
492 }
493 this.updateGUI();
494 }
495
496 private synchronized void addInputFileRow(String name, boolean editable)
497 {
498 int rowToAdd = this.layout.getNumRow();
499 this.layout.insertRow(rowToAdd, ROW_HEIGHT);
500 this.layout.insertRow(rowToAdd + 1, BORDER);
501
502 JTextField destFile = new JTextField(name);
503 if (!editable)
504 {
505 destFile.setEditable(false);
506 }
507 this.destFileNames.add(destFile);
508 this.add(destFile, "0, " + rowToAdd);
509
510 JTextField ta = new JTextField();
511 this.srcFileLocations.add(ta);
512 this.add(ta, "2, " + rowToAdd);
513 JButton btn = new JButton("Pick file");
514
515 this.pickFileButtons.add(btn);
516 btn.addActionListener(this);
517 this.add(btn, "4, " + rowToAdd);
518
519
520
521
522
523
524
525
526 }
527
528 /***
529 * Gets an array of File objects representing the source files to
530 * be uploaded
531 */
532 public synchronized File[] getSourceFiles()
533 {
534 File[] srcFiles = new File[this.srcFileLocations.size()];
535 for (int i = 0; i < this.srcFileLocations.size(); i++)
536 {
537 JTextField tf = (JTextField)this.srcFileLocations.get(i);
538 srcFiles[i] = new File(tf.getText());
539 }
540 return srcFiles;
541 }
542
543 /***
544 * Gets an array of Strings representing the names of the target files
545 * on the remote server
546 */
547 public synchronized String[] getTargetFileNames()
548 {
549 String[] destNames = new String[this.destFileNames.size()];
550 for (int i = 0; i < this.destFileNames.size(); i++)
551 {
552 JTextField tf = (JTextField)this.destFileNames.get(i);
553 destNames[i] = tf.getText();
554 }
555 return destNames;
556 }
557
558 /***
559 * Called when a button is pressed on the panel
560 */
561 public void actionPerformed(ActionEvent e)
562 {
563 if (e.getSource() == this.btnAddInputFile)
564 {
565 this.addInputFileRow("", true);
566 this.updateGUI();
567 }
568 else
569 {
570
571 int index = this.pickFileButtons.indexOf(e.getSource());
572 if (index != -1)
573 {
574 JFileChooser chooser = new JFileChooser();
575 int returnVal = chooser.showOpenDialog(this);
576 if (returnVal == JFileChooser.APPROVE_OPTION)
577 {
578 JTextField ta = (JTextField)this.srcFileLocations.get(index);
579 ta.setText(chooser.getSelectedFile().getPath());
580 }
581 }
582 else
583 {
584
585
586 }
587 }
588 }
589 }
590
591 /***
592 * Panel for entering parameters for the SGS
593 */
594 private class ParamsPanel extends JPanel
595 {
596 private JTable table;
597 private TableLayout layout;
598 private ParamsTableModel model;
599 private JLabel argsLabel;
600
601 public ParamsPanel(String[] paramNames)
602 {
603 this.argsLabel = new JLabel("");
604
605
606 if (paramNames.length > 0)
607 {
608 double[][] size =
609 {
610 { TableLayout.PREFERRED },
611 { TableLayout.PREFERRED, BORDER, ROW_HEIGHT}
612 };
613 this.layout = new TableLayout(size);
614 this.setLayout(this.layout);
615 this.setBorder(BorderFactory.createTitledBorder("Parameters"));
616
617 this.model = new ParamsTableModel(paramNames, false);
618 this.table = new JTable(this.model);
619 this.add(new JScrollPane(this.table), "0, 0");
620 this.add(this.argsLabel, "0, 2");
621
622 for (int i = 0; i < paramNames.length; i++)
623 {
624 this.table.getModel().setValueAt(paramNames[i], i, 0);
625 }
626
627 double width = this.table.getPreferredScrollableViewportSize().getWidth();
628 double height = this.table.getRowHeight() * paramNames.length;
629 Dimension d = new Dimension();
630 d.setSize(width, height);
631 this.table.setPreferredScrollableViewportSize(d);
632
633
634 client.readAllParameterValuesAsync();
635 }
636 else
637 {
638 double[][] size =
639 {
640 { TableLayout.PREFERRED },
641 { ROW_HEIGHT}
642 };
643 this.layout = new TableLayout(size);
644 this.setLayout(this.layout);
645 this.setBorder(BorderFactory.createTitledBorder("Parameters"));
646 this.add(this.argsLabel, "0, 0");
647 }
648 this.layout.layoutContainer(this);
649 repaintGUI();
650 client.getArgumentsAsync();
651 }
652
653 public void gotParameterValue(String name, String value)
654 {
655 this.model.setParameterValue(name, value);
656 }
657
658 public void setArguments(String newArgs)
659 {
660 this.argsLabel.setText(client.getName() + " " + newArgs);
661 this.repaint();
662 }
663 }
664
665 /***
666 * Table model for the parameters
667 */
668 private class ParamsTableModel extends DefaultTableModel
669 {
670 private String[] paramNames;
671 private boolean steering;
672
673 public ParamsTableModel(String[] paramNames, boolean steering)
674 {
675 this.paramNames = paramNames;
676 this.steering = steering;
677
678
679 this.setColumnIdentifiers(new String[]{"Parameter", "Value"});
680
681
682 for (int i = 0; i < paramNames.length; i++)
683 {
684 this.addRow(new String[]{"", ""});
685 }
686 }
687
688 public void setParameterValue(String name, String value)
689 {
690 for (int i = 0; i < this.paramNames.length; i++)
691 {
692 if (paramNames[i].equals(name))
693 {
694 super.setValueAt(value, i, 1);
695 return;
696 }
697 }
698 }
699
700 /***
701 * We override this method so that we can see if the server allows
702 * changes to the parameter value to be made
703 */
704 public void setValueAt(Object value, int row, int col)
705 {
706 if (col == 0)
707 {
708
709 super.setValueAt(value, row, col);
710 }
711 else
712 {
713
714
715
716 if (this.steering)
717 {
718 client.setSteerableParameterValueAsync(this.paramNames[row], (String)value);
719 }
720 else
721 {
722
723
724 }
725 }
726 }
727
728 /***
729 * Only the "Value" column is editable
730 */
731 public boolean isCellEditable(int row, int col)
732 {
733
734
735 return (col == 1);
736 }
737 }
738
739 /***
740 * Panel for entering steering parameters for the SGS
741 */
742 private class SteeringPanel extends JPanel
743 {
744 private JTable table;
745 private TableLayout layout;
746 private ParamsTableModel model;
747
748 private SteeringPanel(String[] steerableNames)
749 {
750
751
752 if (steerableNames.length > 0)
753 {
754 double[][] size =
755 {
756 { TableLayout.PREFERRED },
757 { TableLayout.PREFERRED }
758 };
759 this.layout = new TableLayout(size);
760 this.setLayout(this.layout);
761 this.setBorder(BorderFactory.createTitledBorder("Steering"));
762
763 this.model = new ParamsTableModel(steerableNames, true);
764 this.table = new JTable(this.model);
765 this.add(new JScrollPane(this.table), "0, 0");
766
767 for (int i = 0; i < steerableNames.length; i++)
768 {
769 this.table.getModel().setValueAt(steerableNames[i], i, 0);
770 }
771
772 double width = this.table.getPreferredScrollableViewportSize().getWidth();
773 double height = this.table.getRowHeight() * steerableNames.length;
774 Dimension d = new Dimension();
775 d.setSize(width, height);
776 this.table.setPreferredScrollableViewportSize(d);
777 this.repaint();
778 client.readAllSteerableParameterValuesAsync();
779 }
780 }
781
782 public void gotSteeringParameterValue(String name, String value)
783 {
784 this.model.setParameterValue(name, value);
785 }
786 }
787
788 /***
789 * Panel for displaying control buttons (start, stop)
790 */
791 private class ControlPanel extends JPanel implements ActionListener
792 {
793 private JButton btnStart;
794 private JButton btnStop;
795
796 public ControlPanel()
797 {
798 double size[][] =
799 {
800 { TableLayout.FILL, BORDER, TableLayout.FILL },
801 { TableLayout.FILL }
802 };
803 this.setLayout(new TableLayout(size));
804 this.btnStart = new JButton("Start");
805 this.btnStop = new JButton("Stop");
806
807 this.btnStart.addActionListener(this);
808 this.btnStop.addActionListener(this);
809
810
811 this.add(this.btnStart, "0, 0, c, f");
812 this.add(this.btnStop, "2, 0, c, f");
813 }
814
815 /***
816 * Called when a button on the panel is clicked
817 */
818 public void actionPerformed(ActionEvent e)
819 {
820 if (e.getSource() == this.btnStart)
821 {
822 client.startServiceAsync();
823 }
824 else if (e.getSource() == this.btnStop)
825 {
826 client.stopServiceAsync();
827 }
828 }
829 }
830
831 /***
832 * Panel for displaying service data
833 */
834 private class ServiceDataPanel extends JPanel
835 {
836 private JTable table;
837 private SDTableModel model;
838
839 public ServiceDataPanel(String[] sdeNames)
840 {
841 if (sdeNames.length > 0)
842 {
843 this.setBorder(BorderFactory.createTitledBorder("Service data"));
844
845 this.model = new SDTableModel();
846 this.table = new JTable(this.model);
847 this.add(new JScrollPane(this.table));
848 this.model.setSDENames(sdeNames);
849
850
851 double width = this.table.getPreferredScrollableViewportSize().getWidth();
852 double height = this.table.getRowHeight() * sdeNames.length;
853 Dimension d = new Dimension();
854 d.setSize(width, height);
855 this.table.setPreferredScrollableViewportSize(d);
856 client.readAllServiceDataValuesAsync();
857 }
858 }
859
860 /***
861 * Sets the given service data element to the given value
862 */
863 public void setSDEValue(String sdeName, String value)
864 {
865 this.model.setSDEValue(sdeName, value);
866 }
867
868 /***
869 * Table model for the service data
870 */
871 private class SDTableModel extends AbstractTableModel
872 {
873 private String[] sdeNames;
874 private String[] sdeValues;
875
876 public void setSDENames(String[] sdeNames)
877 {
878 this.sdeNames = sdeNames;
879 this.sdeValues = new String[this.sdeNames.length];
880 this.fireTableDataChanged();
881 }
882
883 public int getRowCount()
884 {
885 if (this.sdeNames == null)
886 {
887 return 0;
888 }
889 else
890 {
891 return this.sdeNames.length;
892 }
893 }
894
895 public int getColumnCount()
896 {
897 return 2;
898 }
899
900 public Object getValueAt(int row, int column)
901 {
902 if (column == 0)
903 {
904 return this.sdeNames[row];
905 }
906 else
907 {
908 return this.sdeValues[row];
909 }
910 }
911
912 /***
913 * Set the given service data element to the given value
914 */
915 public void setSDEValue(String sdeName, String value)
916 {
917 for (int i = 0; i < this.sdeNames.length; i++)
918 {
919 if (sdeName.equals(this.sdeNames[i]))
920 {
921 this.sdeValues[i] = value;
922 this.fireTableRowsUpdated(i, i);
923 break;
924 }
925 }
926 }
927
928 public String getColumnName(int column)
929 {
930 if (column == 0)
931 {
932 return "Service data element";
933 }
934 else
935 {
936 return "Value";
937 }
938 }
939 }
940 }
941
942 /***
943 * Panel for displaying data from output streams
944 */
945 private class OutputStreamsPanel extends JPanel implements ActionListener
946 {
947 private TableLayout layout;
948 private Vector streams;
949 private Vector buttons;
950 private Vector combos;
951 private Hashtable viewers;
952
953 public OutputStreamsPanel()
954 {
955 double[][] size =
956 {
957 { TableLayout.PREFERRED, BORDER, TableLayout.PREFERRED, BORDER,
958 TableLayout.FILL },
959 {}
960 };
961 this.layout = new TableLayout(size);
962 this.setLayout(this.layout);
963 this.setBorder(BorderFactory.createTitledBorder("Available output streams"));
964 this.streams = new Vector();
965 this.buttons = new Vector();
966 this.combos = new Vector();
967
968 this.viewers = new Hashtable();
969 this.viewers.put("Text Viewer", TextStreamViewer.class);
970 }
971
972 public void populatePanel()
973 {
974
975
976 }
977
978 private JComboBox makeComboBox()
979 {
980 JComboBox combo = new JComboBox();
981 Enumeration keys = this.viewers.keys();
982 while(keys.hasMoreElements())
983 {
984 combo.addItem(keys.nextElement());
985 }
986 combo.setSelectedIndex(0);
987 return combo;
988 }
989
990 /***
991 * Called when we have got the possible output streams
992 */
993 public void gotOutputStreams(CStyxFile[] outputStreams)
994 {
995 for (int i = 0; i < outputStreams.length; i++)
996 {
997 this.layout.insertRow(2 * i, ROW_HEIGHT);
998 this.layout.insertRow((2 * i) + 1, BORDER);
999 this.streams.add(outputStreams[i]);
1000 this.add(new JLabel(outputStreams[i].getName()), "0, " + 2*i);
1001 JComboBox combo = makeComboBox();
1002 this.combos.add(combo);
1003 this.add(combo, "2, " + 2*i);
1004 JButton btnView = new JButton("View stream");
1005 btnView.addActionListener(this);
1006 this.buttons.add(btnView);
1007 this.add(btnView, "4, " + 2*i + ", c, f");
1008 }
1009 this.layout.layoutContainer(this);
1010 repaintGUI();
1011 }
1012
1013 public void actionPerformed(ActionEvent e)
1014 {
1015 int i = this.buttons.indexOf(e.getSource());
1016 if (i != -1)
1017 {
1018 CStyxFile streamFile = (CStyxFile)this.streams.get(i);
1019
1020 CachedStreamReader reader = client.getStreamReader(streamFile);
1021 try
1022 {
1023 reader.start();
1024
1025 JComboBox combo = (JComboBox)this.combos.get(i);
1026 Object key = combo.getSelectedItem();
1027 Class viewerClass = (Class)this.viewers.get(key);
1028 StreamViewer viewer = (StreamViewer)viewerClass.newInstance();
1029 viewer.setStreamReader(reader);
1030 viewer.start();
1031 }
1032 catch (IOException ioe)
1033 {
1034 ioe.printStackTrace();
1035 }
1036 catch (InstantiationException ie)
1037 {
1038 ie.printStackTrace();
1039 }
1040 catch (IllegalAccessException iae)
1041 {
1042 iae.printStackTrace();
1043 }
1044 }
1045 }
1046 }
1047
1048 /***
1049 * Called when all the output data have been downloaded
1050 */
1051 public void allOutputDataDownloaded() {}
1052 /***
1053 * Called when the exit code from the service is received: this signals that
1054 * the remote executable has completed.
1055 */
1056 public void gotExitCode(int exitCode) {}
1057
1058 }
1059
1060