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