1   /*
2    *  Copyright (c) 1998-2001, The University of Sheffield.
3    *
4    *  This file is part of GATE (see http://gate.ac.uk/), and is free
5    *  software, licenced under the GNU Library General Public License,
6    *  Version 2, June 1991 (in the distribution as file licence.html,
7    *  and also available at http://gate.ac.uk/gate/licence.html).
8    *
9    *  Valentin Tablan 02/10/2001
10   *
11   *  $Id: SerialControllerEditor.java,v 1.17 2001/11/15 14:21:14 valyt Exp $
12   *
13   */
14  
15  package gate.gui;
16  
17  import gate.creole.*;
18  import gate.*;
19  import gate.swing.*;
20  import gate.util.*;
21  import gate.event.*;
22  
23  
24  import javax.swing.*;
25  import javax.swing.table.*;
26  import javax.swing.event.*;
27  import javax.swing.border.*;
28  import java.awt.event.*;
29  import java.awt.Dimension;
30  import java.awt.Component;
31  import java.text.NumberFormat;
32  import java.util.*;
33  
34  public class SerialControllerEditor extends AbstractVisualResource
35                                 implements CreoleListener{
36  
37    public SerialControllerEditor() {
38    }
39  
40    public void setTarget(Object target){
41      if(!(target instanceof SerialController))
42      throw new IllegalArgumentException(
43        "gate.gui.ApplicationViewer can only be used for serial controllers\n" +
44        target.getClass().toString() +
45        " is not a gate.creole.SerialController!");
46      this.controller = (SerialController)target;
47      analyserMode = controller instanceof SerialAnalyserController;
48      initLocalData();
49      initGuiComponents();
50      initListeners();
51    }//setController
52  
53  
54    public void setHandle(Handle handle) {
55      this.handle = handle;
56      //add the items to the popup
57      JPopupMenu popup = handle.getPopup();
58      popup.addSeparator();
59      popup.add(runAction);
60      popup.addSeparator();
61      popup.add(addMenu);
62      popup.add(removeMenu);
63  
64      //register the listeners
65      if(handle instanceof StatusListener)
66        addStatusListener((StatusListener)handle);
67      if(handle instanceof ProgressListener)
68        addProgressListener((ProgressListener)handle);
69    }//setHandle
70  
71    public Resource init() throws ResourceInstantiationException{
72      super.init();
73      return this;
74    }//init
75  
76    protected void initLocalData() {
77      runAction = new RunAction();
78    }//initLocalData
79  
80    protected void initGuiComponents() {
81      setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
82  
83  
84      JPanel topBox = new JPanel();
85      topBox.setLayout(new BoxLayout(topBox, BoxLayout.X_AXIS));
86      topBox.setAlignmentX(Component.LEFT_ALIGNMENT);
87  
88      loadedPRsTableModel = new LoadedPRsTableModel();
89      loadedPRsTable = new XJTable();
90      loadedPRsTable.setModel(loadedPRsTableModel);
91  
92      loadedPRsTable.setDefaultRenderer(ProcessingResource.class,
93                                        new ResourceRenderer());
94  
95      loadedPRsTable.setIntercellSpacing(new Dimension(5, 5));
96      final int width1 = new JLabel("Loaded Processing resources").
97                  getPreferredSize().width + 10;
98      JScrollPane scroller = new JScrollPane(){
99        public Dimension getPreferredSize(){
100         Dimension dim = super.getPreferredSize();
101         dim.width = Math.max(dim.width, width1);
102         return dim;
103       }
104     };
105     scroller.getViewport().setView(loadedPRsTable);
106     scroller.setBorder(BorderFactory.
107                        createTitledBorder(BorderFactory.createEtchedBorder(),
108                                           "Loaded Processing resources"));
109 
110     topBox.add(scroller);
111     topBox.add(Box.createHorizontalGlue());
112 
113     addButon = new JButton(MainFrame.getIcon("right.gif"));
114     removeButton = new JButton(MainFrame.getIcon("left.gif"));
115 
116     Box buttonsBox =Box.createVerticalBox();
117     buttonsBox.add(Box.createVerticalGlue());
118     buttonsBox.add(addButon);
119     buttonsBox.add(Box.createVerticalStrut(5));
120     buttonsBox.add(removeButton);
121     buttonsBox.add(Box.createVerticalGlue());
122 
123     topBox.add(buttonsBox);
124     topBox.add(Box.createHorizontalGlue());
125 
126     memberPRsTableModel = new MemberPRsTableModel();
127     memberPRsTable = new XJTable(memberPRsTableModel);
128     memberPRsTable.setSortable(false);
129     memberPRsTable.setDefaultRenderer(ProcessingResource.class,
130                                       new ResourceRenderer());
131     memberPRsTable.setIntercellSpacing(new Dimension(5, 5));
132 
133     final int width2 = new JLabel("Selected Processing resources").
134                            getPreferredSize().width + 10;
135     scroller = new JScrollPane(){
136       public Dimension getPreferredSize(){
137         Dimension dim = super.getPreferredSize();
138         dim.width = Math.max(dim.width, width2);
139         return dim;
140       }
141     };
142     scroller.getViewport().setView(memberPRsTable);
143     scroller.setBorder(BorderFactory.
144                        createTitledBorder(BorderFactory.createEtchedBorder(),
145                                           "Selected Processing resources"));
146 
147 
148     topBox.add(scroller);
149 
150     moveUpButton = new JButton(MainFrame.getIcon("moveup.gif"));
151     moveDownButton = new JButton(MainFrame.getIcon("movedown.gif"));
152 
153     buttonsBox =Box.createVerticalBox();
154     buttonsBox.add(Box.createVerticalGlue());
155     buttonsBox.add(moveUpButton);
156     buttonsBox.add(Box.createVerticalStrut(5));
157     buttonsBox.add(moveDownButton);
158     buttonsBox.add(Box.createVerticalGlue());
159 
160     topBox.add(buttonsBox);
161     topBox.add(Box.createHorizontalGlue());
162 
163     add(topBox);
164 
165     if(analyserMode){
166       //we need to add the corpus combo
167       corpusCombo = new JComboBox(corpusComboModel = new CorporaComboModel());
168       corpusCombo.setRenderer(new ResourceRenderer());
169       if(((SerialAnalyserController)controller).getCorpus() != null){
170         corpusCombo.setSelectedItem(((SerialAnalyserController)controller).
171                                      getCorpus());
172       }else{
173         if(corpusCombo.getModel().getSize() > 1) corpusCombo.setSelectedIndex(1);
174         else corpusCombo.setSelectedIndex(0);
175       }
176       JPanel horBox = new JPanel();
177       horBox.setLayout(new BoxLayout(horBox, BoxLayout.X_AXIS));
178       horBox.setAlignmentX(Component.LEFT_ALIGNMENT);
179       horBox.add(new JLabel("Corpus:"));
180       horBox.add(Box.createHorizontalStrut(5));
181       horBox.add(corpusCombo);
182       horBox.add(Box.createHorizontalGlue());
183       add(horBox);
184       JLabel warningLbl = new JLabel(
185         "<HTML>The <b>corpus</b> and <b>document</b> parameters are not " +
186         "available as they are automatically set by the controller!</HTML>");
187       warningLbl.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT);
188       add(warningLbl);
189     }
190 
191     parametersPanel = new JPanel();
192     parametersPanel.setLayout(new BoxLayout(parametersPanel, BoxLayout.Y_AXIS));
193     parametersPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
194     parametersBorder = BorderFactory.createTitledBorder(
195                                       BorderFactory.createEtchedBorder(),
196                                       "No selected processing resource");
197     parametersPanel.setBorder(parametersBorder);
198     parametersEditor = new ResourceParametersEditor();
199     parametersEditor.init(null, null);
200     parametersPanel.add(new JScrollPane(parametersEditor));
201     add(Box.createVerticalStrut(5));
202     add(parametersPanel);
203 
204 
205     add(Box.createVerticalStrut(5));
206     add(Box.createVerticalGlue());
207     JPanel horBox = new JPanel();
208     horBox.setLayout(new BoxLayout(horBox, BoxLayout.X_AXIS));
209     horBox.setAlignmentX(Component.LEFT_ALIGNMENT);
210     horBox.add(Box.createHorizontalGlue());
211     horBox.add(new JButton(runAction));
212     horBox.add(Box.createHorizontalStrut(10));
213     add(horBox);
214     add(Box.createVerticalStrut(10));
215 
216     addMenu = new JMenu("Add");
217     removeMenu = new JMenu("Remove");
218   }// initGuiComponents()
219 
220   protected void initListeners() {
221     Gate.getCreoleRegister().addCreoleListener(this);
222 
223     this.addMouseListener(new MouseAdapter() {
224       public void mouseClicked(MouseEvent e) {
225         if(SwingUtilities.isRightMouseButton(e)){
226           if(handle != null && handle.getPopup()!= null)
227             handle.getPopup().show(SerialControllerEditor.this, e.getX(), e.getY());
228         }
229       }
230     });
231 
232     addButon.addActionListener(new ActionListener() {
233       public void actionPerformed(ActionEvent e) {
234         int rows[] = loadedPRsTable.getSelectedRows();
235         if(rows == null || rows.length == 0){
236           JOptionPane.showMessageDialog(
237               SerialControllerEditor.this,
238               "Please select some components from the list of available components!\n" ,
239               "Gate", JOptionPane.ERROR_MESSAGE);
240         } else {
241           List actions = new ArrayList();
242           for(int i = 0; i < rows.length; i++) {
243             Action act =(Action)new AddPRAction((ProcessingResource)
244                                      loadedPRsTable.getValueAt(rows[i], 0));
245             if(act != null) actions.add(act);
246           }
247           Iterator actIter = actions.iterator();
248           while(actIter.hasNext()){
249             ((Action)actIter.next()).actionPerformed(null);
250           }
251         }
252       }
253     });
254 
255     removeButton.addActionListener(new ActionListener() {
256       public void actionPerformed(ActionEvent e) {
257         int rows[] = memberPRsTable.getSelectedRows();
258         if(rows == null || rows.length == 0){
259           JOptionPane.showMessageDialog(
260               SerialControllerEditor.this,
261               "Please select some components to be removed "+
262               "from the list of used components!\n" ,
263               "Gate", JOptionPane.ERROR_MESSAGE);
264         } else {
265           List actions = new ArrayList();
266           for(int i = 0; i < rows.length; i++){
267             Action act =(Action)new RemovePRAction((ProcessingResource)
268                                      memberPRsTable.getValueAt(rows[i], 0));
269             if(act != null) actions.add(act);
270           }
271           Iterator actIter = actions.iterator();
272           while(actIter.hasNext()){
273             ((Action)actIter.next()).actionPerformed(null);
274           }
275         }// else
276       }//  public void actionPerformed(ActionEvent e)
277     });
278 
279     moveUpButton.addActionListener(new ActionListener() {
280       public void actionPerformed(ActionEvent e) {
281         int rows[] = memberPRsTable.getSelectedRows();
282         if(rows == null || rows.length == 0){
283           JOptionPane.showMessageDialog(
284               SerialControllerEditor.this,
285               "Please select some components to be moved "+
286               "from the list of used components!\n" ,
287               "Gate", JOptionPane.ERROR_MESSAGE);
288         } else {
289           //we need to make sure the rows are sorted
290           Arrays.sort(rows);
291           //get the list of PRs
292           for(int i = 0; i < rows.length; i++){
293             int row = rows[i];
294             if(row > 0){
295               //move it up
296               ProcessingResource value = controller.remove(row);
297               controller.add(row - 1, value);
298             }
299           }
300           memberPRsTableModel.fireTableDataChanged();
301           //restore selection
302           for(int i = 0; i < rows.length; i++){
303             int newRow = -1;
304             if(rows[i] > 0) newRow = rows[i] - 1;
305             else newRow = rows[i];
306             memberPRsTable.addRowSelectionInterval(newRow, newRow);
307           }
308         }
309 
310       }//public void actionPerformed(ActionEvent e)
311     });
312 
313 
314     moveDownButton.addActionListener(new ActionListener() {
315       public void actionPerformed(ActionEvent e) {
316         int rows[] = memberPRsTable.getSelectedRows();
317         if(rows == null || rows.length == 0){
318           JOptionPane.showMessageDialog(
319               SerialControllerEditor.this,
320               "Please select some components to be moved "+
321               "from the list of used components!\n" ,
322               "Gate", JOptionPane.ERROR_MESSAGE);
323         } else {
324           //we need to make sure the rows are sorted
325           Arrays.sort(rows);
326           //get the list of PRs
327           for(int i = rows.length - 1; i >= 0; i--){
328             int row = rows[i];
329             if(row < controller.getPRs().size() -1){
330               //move it down
331               ProcessingResource value = controller.remove(row);
332               controller.add(row + 1, value);
333             }
334           }
335           memberPRsTableModel.fireTableDataChanged();
336           //restore selection
337           for(int i = 0; i < rows.length; i++){
338             int newRow = -1;
339             if(rows[i] < controller.getPRs().size() - 1) newRow = rows[i] + 1;
340             else newRow = rows[i];
341             memberPRsTable.addRowSelectionInterval(newRow, newRow);
342           }
343         }
344 
345       }//public void actionPerformed(ActionEvent e)
346     });
347 
348     loadedPRsTable.addMouseListener(new MouseAdapter() {
349       public void mouseClicked(MouseEvent e) {
350         int row = loadedPRsTable.rowAtPoint(e.getPoint());
351         //load modules on double click
352         ProcessingResource pr = (ProcessingResource)
353                                 loadedPRsTableModel.getValueAt(row, 0);
354         if(SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2){
355           new AddPRAction(pr).actionPerformed(null);
356         }else if(SwingUtilities.isRightMouseButton(e)){
357             JPopupMenu popup = new JPopupMenu();
358             popup.add(new AddPRAction(pr){
359               {
360                 putValue(NAME, "Add \"" + this.pr.getName() +
361                                "\" to the \"" + controller.getName() +
362                                "\" application");
363               }
364             });
365             popup.show(loadedPRsTable, e.getPoint().x, e.getPoint().y);
366           }
367       }
368 
369       public void mousePressed(MouseEvent e) {
370       }
371 
372       public void mouseReleased(MouseEvent e) {
373       }
374 
375       public void mouseEntered(MouseEvent e) {
376       }
377 
378       public void mouseExited(MouseEvent e) {
379       }
380     });
381 
382     memberPRsTable.addMouseListener(new MouseAdapter() {
383       public void mouseClicked(MouseEvent e) {
384         final int row = memberPRsTable.rowAtPoint(e.getPoint());
385         if(row != -1){
386           //edit parameters on double click
387           if(SwingUtilities.isLeftMouseButton(e) /*&& e.getClickCount() == 2*/){
388             ProcessingResource pr = (ProcessingResource)
389                                     memberPRsTableModel.getValueAt(row, 0);
390             showParamsEditor(pr);
391           }else if(SwingUtilities.isRightMouseButton(e)){
392             JPopupMenu popup = new JPopupMenu();
393             popup.add(new AbstractAction("Edit parameters"){
394               public void actionPerformed(ActionEvent e){
395                 ProcessingResource pr = (ProcessingResource)
396                                         memberPRsTableModel.getValueAt(row, 0);
397                 showParamsEditor(pr);
398               }
399             });
400             popup.show(memberPRsTable, e.getPoint().x, e.getPoint().y);
401           }
402         }
403       }
404 
405       public void mousePressed(MouseEvent e) {
406       }
407 
408       public void mouseReleased(MouseEvent e) {
409       }
410 
411       public void mouseEntered(MouseEvent e) {
412       }
413 
414       public void mouseExited(MouseEvent e) {
415       }
416     });
417 
418     addMenu.addMenuListener(new MenuListener() {
419       public void menuCanceled(MenuEvent e) {
420 
421       }
422 
423       public void menuDeselected(MenuEvent e) {
424       }
425 
426       public void menuSelected(MenuEvent e) {
427         addMenu.removeAll();
428         Iterator prIter = Gate.getCreoleRegister().getPrInstances().iterator();
429         while(prIter.hasNext()){
430           ProcessingResource pr = (ProcessingResource)prIter.next();
431           if(Gate.getHiddenAttribute(pr.getFeatures())){
432             //ignore this resource
433           }else{
434             addMenu.add(new AddPRAction(pr));
435           }
436         }// while
437       }
438     });
439 
440     removeMenu.addMenuListener(new MenuListener() {
441       public void menuCanceled(MenuEvent e) {
442       }
443 
444       public void menuDeselected(MenuEvent e) {
445       }
446 
447       public void menuSelected(MenuEvent e) {
448         removeMenu.removeAll();
449         Iterator prIter = Gate.getCreoleRegister().getPrInstances().iterator();
450         while(prIter.hasNext()){
451           ProcessingResource pr = (ProcessingResource)prIter.next();
452           if(Gate.getHiddenAttribute(pr.getFeatures())){
453             //ignore this resource
454           }else{
455             removeMenu.add(new RemovePRAction(pr));
456           }
457         }// while
458       }
459     });
460   }//protected void initListeners()
461 
462   /**
463    * Stops the current edits for parameters; sets the paarmeters for the
464    * resource currently being edited and diplays the editor for the new
465    * resource
466    * @param pr the new resource
467    */
468   protected void showParamsEditor(ProcessingResource pr){
469     try{
470       if(parametersEditor.getResource() != null) parametersEditor.setParameters();
471     }catch(ResourceInstantiationException rie){
472       JOptionPane.showMessageDialog(
473           SerialControllerEditor.this,
474           "Failed to set parameters for \"" + pr.getName() +"\"!\n" ,
475           "Gate", JOptionPane.ERROR_MESSAGE);
476       rie.printStackTrace(Err.getPrintWriter());
477     }
478 
479     if(pr != null){
480       ResourceData rData = (ResourceData)Gate.getCreoleRegister().
481                                          get(pr.getClass().getName());
482 
483       parametersBorder.setTitle("Parameters for the \"" + pr.getName() +
484                                 "\" " + rData.getName());
485 
486       //this is a list of lists
487       List parameters = rData.getParameterList().getRuntimeParameters();
488 
489       if(analyserMode){
490         //remove corpus and document
491         //create a new list so we don't change the one from CreoleReg.
492         List newParameters = new ArrayList();
493         Iterator pDisjIter = parameters.iterator();
494         while(pDisjIter.hasNext()){
495           List aDisjunction = (List)pDisjIter.next();
496           List newDisjunction = new ArrayList(aDisjunction);
497           Iterator internalParIter = newDisjunction.iterator();
498           while(internalParIter.hasNext()){
499             Parameter parameter = (Parameter)internalParIter.next();
500             if(parameter.getName().equals("corpus") ||
501                parameter.getName().equals("document")) internalParIter.remove();
502           }
503           if(!newDisjunction.isEmpty()) newParameters.add(newDisjunction);
504         }
505         parametersEditor.init(pr, newParameters);
506       }else{
507         parametersEditor.init(pr, parameters);
508       }
509     }else{
510       parametersBorder.setTitle("No selected processing resource");
511       parametersEditor.init(null, null);
512     }
513     SerialControllerEditor.this.validate();
514     SerialControllerEditor.this.repaint(100);
515   }
516 
517   //CreoleListener implementation
518   public void resourceLoaded(CreoleEvent e) {
519     if(Gate.getHiddenAttribute(e.getResource().getFeatures())) return;
520     if(e.getResource() instanceof ProcessingResource){
521       loadedPRsTableModel.fireTableDataChanged();
522       memberPRsTableModel.fireTableDataChanged();
523       repaint(100);
524     }else if(e.getResource() instanceof LanguageResource){
525       if(e.getResource() instanceof Corpus && analyserMode){
526         corpusComboModel.fireDataChanged();
527       }
528     }
529   }// public void resourceLoaded
530 
531   public void resourceUnloaded(CreoleEvent e) {
532     if(Gate.getHiddenAttribute(e.getResource().getFeatures())) return;
533     if(e.getResource() instanceof ProcessingResource){
534       ProcessingResource pr = (ProcessingResource)e.getResource();
535       if(controller.getPRs().contains(pr)){
536         new RemovePRAction(pr).actionPerformed(null);
537       }
538       loadedPRsTableModel.fireTableDataChanged();
539       memberPRsTableModel.fireTableDataChanged();
540       repaint(100);
541     }
542   }//public void resourceUnloaded(CreoleEvent e)
543 
544   public void datastoreOpened(CreoleEvent e) {
545   }
546   public void datastoreCreated(CreoleEvent e) {
547   }
548   public void datastoreClosed(CreoleEvent e) {
549   }
550   public synchronized void removeStatusListener(StatusListener l) {
551     if (statusListeners != null && statusListeners.contains(l)) {
552       Vector v = (Vector) statusListeners.clone();
553       v.removeElement(l);
554       statusListeners = v;
555     }
556   }
557   public synchronized void addStatusListener(StatusListener l) {
558     Vector v = statusListeners == null ? new Vector(2) :
559                                   (Vector) statusListeners.clone();
560     if (!v.contains(l)) {
561       v.addElement(l);
562       statusListeners = v;
563     }
564   }
565 
566 
567 
568   /**
569    * Table model for all the loaded processing resources that are not part of
570    * the controller.
571    */
572   class LoadedPRsTableModel extends AbstractTableModel{
573     public int getRowCount(){
574       List loadedPRs = new ArrayList(Gate.getCreoleRegister().getPrInstances());
575       loadedPRs.removeAll(controller.getPRs());
576       Iterator prsIter = loadedPRs.iterator();
577       while(prsIter.hasNext()){
578         ProcessingResource aPR = (ProcessingResource)prsIter.next();
579         if(Gate.getHiddenAttribute(aPR.getFeatures())) prsIter.remove();
580       }
581 
582       return loadedPRs.size();
583     }
584 
585     public Object getValueAt(int row, int column){
586       List loadedPRs = new ArrayList(Gate.getCreoleRegister().getPrInstances());
587       loadedPRs.removeAll(controller.getPRs());
588       Iterator prsIter = loadedPRs.iterator();
589       while(prsIter.hasNext()){
590         ProcessingResource aPR = (ProcessingResource)prsIter.next();
591         if(Gate.getHiddenAttribute(aPR.getFeatures())) prsIter.remove();
592       }
593 
594       Collections.sort(loadedPRs, nameComparator);
595       ProcessingResource pr = (ProcessingResource)loadedPRs.get(row);
596       switch(column){
597         case 0 : return pr;
598         case 1 : {
599           ResourceData rData = (ResourceData)Gate.getCreoleRegister().
600                                     get(pr.getClass().getName());
601           if(rData == null) return pr.getClass();
602           else return rData.getName();
603         }
604         default: return null;
605       }
606     }
607 
608     public int getColumnCount(){
609       return 2;
610     }
611 
612     public String getColumnName(int columnIndex){
613       switch(columnIndex){
614         case 0 : return "Name";
615         case 1 : return "Type";
616         default: return "?";
617       }
618     }
619 
620     public Class getColumnClass(int columnIndex){
621       switch(columnIndex){
622         case 0 : return ProcessingResource.class;
623         case 1 : return String.class;
624         default: return Object.class;
625       }
626     }
627 
628     public boolean isCellEditable(int rowIndex, int columnIndex){
629       return false;
630     }
631 
632     public void setValueAt(Object aValue, int rowIndex, int columnIndex){
633     }
634     NameComparator nameComparator = new NameComparator();
635   }//protected class LoadedPRsTableModel extends AbstractTableModel
636 
637   /**
638    * A model for a combobox containing the loaded corpora in the system
639    */
640   protected class CorporaComboModel extends AbstractListModel
641                                   implements ComboBoxModel{
642     public int getSize(){
643       //get all corpora regardless of their actual type
644       java.util.List loadedCorpora = null;
645       try{
646         loadedCorpora = Gate.getCreoleRegister().
647                                getAllInstances("gate.Corpus");
648       }catch(GateException ge){
649         ge.printStackTrace(Err.getPrintWriter());
650       }
651 
652       return loadedCorpora == null ? 1 : loadedCorpora.size() + 1;
653     }
654 
655     public Object getElementAt(int index){
656       if(index == 0) return "<none>";
657       else{
658         //get all corpora regardless of their actual type
659         java.util.List loadedCorpora = null;
660         try{
661           loadedCorpora = Gate.getCreoleRegister().
662                                  getAllInstances("gate.Corpus");
663         }catch(GateException ge){
664           ge.printStackTrace(Err.getPrintWriter());
665         }
666         return loadedCorpora == null? "" : loadedCorpora.get(index - 1);
667       }
668     }
669 
670     //use the controller for data caching
671     public void setSelectedItem(Object anItem){
672       ((SerialAnalyserController)controller).
673         setCorpus((Corpus)(anItem.equals("<none>") ? null : anItem));
674     }
675 
676     public Object getSelectedItem(){
677       Corpus corpus = ((SerialAnalyserController)controller).getCorpus();
678       return (corpus == null ? (Object)"<none>" : (Object)corpus);
679     }
680 
681     void fireDataChanged(){
682       fireContentsChanged(this, 0, getSize());
683     }
684 
685     Object selectedItem = null;
686   }
687 
688   /**
689    * Table model for all the processing resources in the controller.
690    */
691   class MemberPRsTableModel extends AbstractTableModel{
692     public int getRowCount(){
693       return controller.getPRs().size();
694     }
695 
696     public Object getValueAt(int row, int column){
697       ProcessingResource pr = (ProcessingResource)
698                               ((List)controller.getPRs()).get(row);
699       switch(column){
700         case 0 : return pr;
701 //        case 1 : return new Boolean(checkRuntimeParameters(pr));
702         case 1 : {
703           ResourceData rData = (ResourceData)Gate.getCreoleRegister().
704                                     get(pr.getClass().getName());
705           if(rData == null) return pr.getClass();
706           else return rData.getName();
707         }
708         default: return null;
709       }
710     }
711 
712     public int getColumnCount(){
713       return 2;
714     }
715 
716     public String getColumnName(int columnIndex){
717       switch(columnIndex){
718         case 0 : return "Name";
719 //        case 1 : return "!";
720         case 1 : return "Type";
721         default: return "?";
722       }
723     }
724 
725     public Class getColumnClass(int columnIndex){
726       switch(columnIndex){
727         case 0 : return ProcessingResource.class;
728 //        case 1 : return Boolean.class;
729         case 1 : return String.class;
730         default: return Object.class;
731       }
732     }
733 
734     public boolean isCellEditable(int rowIndex, int columnIndex){
735       return false;
736     }
737 
738     public void setValueAt(Object aValue, int rowIndex, int columnIndex){
739     }
740   }//protected class MemeberPRsTableModel extends AbstractTableModel
741 
742   /** Adds a PR to the controller*/
743   class AddPRAction extends AbstractAction {
744     AddPRAction(ProcessingResource aPR){
745       super(aPR.getName());
746       this.pr = aPR;
747       setEnabled(!controller.getPRs().contains(aPR));
748     }
749 
750     public void actionPerformed(ActionEvent e){
751       controller.add(pr);
752       loadedPRsTableModel.fireTableDataChanged();
753       memberPRsTableModel.fireTableDataChanged();
754       SerialControllerEditor.this.validate();
755       SerialControllerEditor.this.repaint(100);
756     }
757 
758     ProcessingResource pr;
759   }
760 
761   /** Removes a PR from the controller*/
762   class RemovePRAction extends AbstractAction {
763     RemovePRAction(ProcessingResource pr){
764       super(pr.getName());
765       this.pr = pr;
766       setEnabled(controller.getPRs().contains(pr));
767     }
768 
769     public void actionPerformed(ActionEvent e){
770       if(controller.remove(pr)){
771         loadedPRsTableModel.fireTableDataChanged();
772         memberPRsTableModel.fireTableDataChanged();
773         if(parametersEditor.getResource() == pr){
774           parametersEditor.init(null, null);
775           parametersBorder.setTitle("No selected processing resource");
776         }
777         SerialControllerEditor.this.validate();
778         SerialControllerEditor.this.repaint(100);
779       }
780     }
781 
782     ProcessingResource pr;
783   }
784 
785 
786   /** Runs the Application*/
787   class RunAction extends AbstractAction {
788     RunAction(){
789       super("Run");
790     }
791 
792     public void actionPerformed(ActionEvent e){
793       Runnable runnable = new Runnable(){
794         public void run(){
795 
796           //stop editing the parameters
797           try{
798             parametersEditor.setParameters();
799           }catch(ResourceInstantiationException rie){
800             JOptionPane.showMessageDialog(
801               SerialControllerEditor.this,
802               "Could not set parameters for the \"" +
803               parametersEditor.getResource().getName() +
804               "\" processing resource:\nSee \"Messages\" tab for details!",
805               "Gate", JOptionPane.ERROR_MESSAGE);
806               rie.printStackTrace(Err.getPrintWriter());
807               return;
808           }
809 
810           if(analyserMode){
811             //set the corpus
812             Object value = corpusCombo.getSelectedItem();
813             Corpus corpus = value.equals("<none>") ? null : (Corpus)value;
814             if(corpus == null){
815               JOptionPane.showMessageDialog(
816                 SerialControllerEditor.this,
817                 "No corpus provided!\n" +
818                 "Please select a corpus and try again!",
819                 "Gate", JOptionPane.ERROR_MESSAGE);
820               return;
821             }
822             ((SerialAnalyserController)controller).setCorpus(corpus);
823           }
824           //check the runtime parameters
825           List badPRs;
826           try{
827             badPRs = controller.getOffendingPocessingResources();
828           }catch(ResourceInstantiationException rie){
829             JOptionPane.showMessageDialog(
830               SerialControllerEditor.this,
831               "Could not check runtime parameters for " +
832               "the processing resources:\n" + rie.toString(),
833               "Gate", JOptionPane.ERROR_MESSAGE);
834             return;
835           }
836           if(badPRs != null && !badPRs.isEmpty()){
837             //we know what PRs have problems so it would be nice to show
838             //them in red or something
839             JOptionPane.showMessageDialog(
840               SerialControllerEditor.this,
841               "Some required runtime parameters are not set!",
842               "Gate", JOptionPane.ERROR_MESSAGE);
843             return;
844           }
845 
846           //set the listeners
847           StatusListener sListener = new InternalStatusListener();
848           ProgressListener pListener = new InternalProgressListener();
849 
850           controller.addStatusListener(sListener);
851           controller.addProgressListener(pListener);
852 
853           Gate.setExecutable(controller);
854 
855           //execute the thing
856           long startTime = System.currentTimeMillis();
857           fireStatusChanged("Running " +
858                             controller.getName());
859           fireProgressChanged(0);
860 
861           try {
862             controller.execute();
863           }catch(ExecutionInterruptedException eie){
864             JOptionPane.showMessageDialog(
865               SerialControllerEditor.this,
866               "Interrupted!\n" + eie.toString(),
867               "Gate", JOptionPane.ERROR_MESSAGE);
868           }catch(ExecutionException ee) {
869             ee.printStackTrace(Err.getPrintWriter());
870             JOptionPane.showMessageDialog(
871               SerialControllerEditor.this,
872               "Execution error while running \"" + controller.getName() +
873               "\" :\nSee \"Messages\" tab for details!",
874               "Gate", JOptionPane.ERROR_MESSAGE);
875           }catch(Exception e){
876             JOptionPane.showMessageDialog(SerialControllerEditor.this,
877                                           "Unhandled execution error!\n " +
878                                           "See \"Messages\" tab for details!",
879                                           "Gate", JOptionPane.ERROR_MESSAGE);
880             e.printStackTrace(Err.getPrintWriter());
881           }finally{
882             Gate.setExecutable(null);
883           }//catch
884 
885           //remove the listeners
886           controller.removeStatusListener(sListener);
887           controller.removeProgressListener(pListener);
888 
889           long endTime = System.currentTimeMillis();
890           fireProcessFinished();
891           fireStatusChanged(controller.getName() +
892                             " run in " +
893                             NumberFormat.getInstance().format(
894                             (double)(endTime - startTime) / 1000) + " seconds");
895         }
896       };
897       Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
898                                  runnable,
899                                  "ApplicationViewer1");
900       thread.setPriority(Thread.MIN_PRIORITY);
901       thread.start();
902     }//public void actionPerformed(ActionEvent e)
903   }//class RunAction
904 
905   /**
906    * A simple progress listener used to forward the events upstream.
907    */
908   protected class InternalProgressListener implements ProgressListener{
909     public void progressChanged(int i){
910       fireProgressChanged(i);
911     }
912 
913     public void processFinished(){
914       fireProcessFinished();
915     }
916   }//InternalProgressListener
917 
918   /**
919    * A simple status listener used to forward the events upstream.
920    */
921   protected class InternalStatusListener implements StatusListener{
922     public void statusChanged(String message){
923       fireStatusChanged(message);
924     }
925   }//InternalStatusListener
926 
927   /** The controller this editor edits */
928   SerialController controller;
929 
930   /** The {@link Handle} that created this view */
931   Handle handle;
932 
933   /**
934    * Contains all the PRs loaded in the sytem that are not already part of the
935    * serial controller
936    */
937   XJTable loadedPRsTable;
938 
939   /**
940    * model for the {@link loadedPRsTable} JTable.
941    */
942   LoadedPRsTableModel loadedPRsTableModel;
943 
944   /**
945    * Displays the PRs in the controller
946    */
947   XJTable memberPRsTable;
948 
949   /** model for {@link memberPRsTable}*/
950   MemberPRsTableModel memberPRsTableModel;
951 
952   /** Adds one or more PR(s) to the controller*/
953   JButton addButon;
954 
955   /** Removes one or more PR(s) from the controller*/
956   JButton removeButton;
957 
958   /** Moves the module up in the controller list*/
959   JButton moveUpButton;
960 
961   /** Moves the module down in the controller list*/
962   JButton moveDownButton;
963 
964   /** A component for editing the parameters of the currently selected PR*/
965   ResourceParametersEditor parametersEditor;
966 
967   /** A JPanel containing the {@link parametersEditor}*/
968   JPanel parametersPanel;
969 
970   /** A border for the {@link parametersPanel} */
971   TitledBorder parametersBorder;
972 
973   /**
974    * A combobox that allows selection of a corpus from the list of loaded
975    * corpora.
976    */
977   JComboBox corpusCombo;
978 
979   CorporaComboModel corpusComboModel;
980 
981   /**The "Add PR" menu; part of the popup menu*/
982   JMenu addMenu;
983 
984   /**The "Remove PR" menu; part of the popup menu*/
985   JMenu removeMenu;
986 
987   /** Action that runs the application*/
988   RunAction runAction;
989 
990   boolean analyserMode = false;
991 
992   private transient Vector statusListeners;
993   private transient Vector progressListeners;
994 
995 
996 
997   protected void fireStatusChanged(String e) {
998     if (statusListeners != null) {
999       Vector listeners = statusListeners;
1000      int count = listeners.size();
1001      for (int i = 0; i < count; i++) {
1002        ((StatusListener) listeners.elementAt(i)).statusChanged(e);
1003      }
1004    }
1005  }
1006  public synchronized void removeProgressListener(ProgressListener l) {
1007    if (progressListeners != null && progressListeners.contains(l)) {
1008      Vector v = (Vector) progressListeners.clone();
1009      v.removeElement(l);
1010      progressListeners = v;
1011    }
1012  }
1013  public synchronized void addProgressListener(ProgressListener l) {
1014    Vector v = progressListeners == null ? new Vector(2) : (Vector) progressListeners.clone();
1015    if (!v.contains(l)) {
1016      v.addElement(l);
1017      progressListeners = v;
1018    }
1019  }
1020  protected void fireProgressChanged(int e) {
1021    if (progressListeners != null) {
1022      Vector listeners = progressListeners;
1023      int count = listeners.size();
1024      for (int i = 0; i < count; i++) {
1025        ((ProgressListener) listeners.elementAt(i)).progressChanged(e);
1026      }
1027    }
1028  }
1029  protected void fireProcessFinished() {
1030    if (progressListeners != null) {
1031      Vector listeners = progressListeners;
1032      int count = listeners.size();
1033      for (int i = 0; i < count; i++) {
1034        ((ProgressListener) listeners.elementAt(i)).processFinished();
1035      }
1036    }
1037  }
1038  }//SerialControllerEditor
1039