SerialControllerEditor.java
0001 /*
0002  *  Copyright (c) 1995-2012, The University of Sheffield. See the file
0003  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
0004  *
0005  *  This file is part of GATE (see http://gate.ac.uk/), and is free
0006  *  software, licenced under the GNU Library General Public License,
0007  *  Version 2, June 1991 (in the distribution as file licence.html,
0008  *  and also available at http://gate.ac.uk/gate/licence.html).
0009  *
0010  *  Valentin Tablan 02/10/2001
0011  *
0012  *  $Id: SerialControllerEditor.java 19248 2016-04-20 09:46:44Z markagreenwood $
0013  *
0014  */
0015 
0016 package gate.gui;
0017 
0018 import gate.Controller;
0019 import gate.Corpus;
0020 import gate.CorpusController;
0021 import gate.Gate;
0022 import gate.LanguageResource;
0023 import gate.ProcessingResource;
0024 import gate.Resource;
0025 import gate.creole.AbstractVisualResource;
0026 import gate.creole.AnalyserRunningStrategy;
0027 import gate.creole.ConditionalController;
0028 import gate.creole.ConditionalSerialAnalyserController;
0029 import gate.creole.ExecutionException;
0030 import gate.creole.ExecutionInterruptedException;
0031 import gate.creole.Parameter;
0032 import gate.creole.ResourceData;
0033 import gate.creole.ResourceInstantiationException;
0034 import gate.creole.RunningStrategy;
0035 import gate.creole.RunningStrategy.UnconditionalRunningStrategy;
0036 import gate.creole.SerialAnalyserController;
0037 import gate.creole.SerialController;
0038 import gate.creole.metadata.CreoleResource;
0039 import gate.creole.metadata.GuiType;
0040 import gate.event.ControllerEvent;
0041 import gate.event.ControllerListener;
0042 import gate.event.CreoleEvent;
0043 import gate.event.CreoleListener;
0044 import gate.event.ProgressListener;
0045 import gate.event.StatusListener;
0046 import gate.swing.XJPopupMenu;
0047 import gate.swing.XJTable;
0048 import gate.util.Benchmark;
0049 import gate.util.Err;
0050 import gate.util.GateException;
0051 import gate.util.GateRuntimeException;
0052 import gate.util.NameComparator;
0053 
0054 import java.awt.BorderLayout;
0055 import java.awt.Component;
0056 import java.awt.Dimension;
0057 import java.awt.GridBagConstraints;
0058 import java.awt.GridBagLayout;
0059 import java.awt.Insets;
0060 import java.awt.datatransfer.DataFlavor;
0061 import java.awt.datatransfer.StringSelection;
0062 import java.awt.datatransfer.Transferable;
0063 import java.awt.datatransfer.UnsupportedFlavorException;
0064 import java.awt.event.ActionEvent;
0065 import java.awt.event.ActionListener;
0066 import java.awt.event.ItemEvent;
0067 import java.awt.event.ItemListener;
0068 import java.awt.event.KeyEvent;
0069 import java.awt.event.MouseAdapter;
0070 import java.awt.event.MouseEvent;
0071 import java.io.IOException;
0072 import java.text.NumberFormat;
0073 import java.util.ArrayList;
0074 import java.util.Arrays;
0075 import java.util.Collections;
0076 import java.util.Iterator;
0077 import java.util.List;
0078 import java.util.Vector;
0079 
0080 import javax.swing.AbstractAction;
0081 import javax.swing.AbstractButton;
0082 import javax.swing.AbstractListModel;
0083 import javax.swing.Action;
0084 import javax.swing.BorderFactory;
0085 import javax.swing.Box;
0086 import javax.swing.BoxLayout;
0087 import javax.swing.ButtonGroup;
0088 import javax.swing.ComboBoxModel;
0089 import javax.swing.Icon;
0090 import javax.swing.JButton;
0091 import javax.swing.JComboBox;
0092 import javax.swing.JComponent;
0093 import javax.swing.JLabel;
0094 import javax.swing.JOptionPane;
0095 import javax.swing.JPanel;
0096 import javax.swing.JPopupMenu;
0097 import javax.swing.JRadioButton;
0098 import javax.swing.JScrollPane;
0099 import javax.swing.JSplitPane;
0100 import javax.swing.JTable;
0101 import javax.swing.JTextField;
0102 import javax.swing.KeyStroke;
0103 import javax.swing.SwingUtilities;
0104 import javax.swing.TransferHandler;
0105 import javax.swing.border.TitledBorder;
0106 import javax.swing.event.AncestorEvent;
0107 import javax.swing.event.AncestorListener;
0108 import javax.swing.event.ListSelectionEvent;
0109 import javax.swing.event.ListSelectionListener;
0110 import javax.swing.event.PopupMenuEvent;
0111 import javax.swing.event.PopupMenuListener;
0112 import javax.swing.table.AbstractTableModel;
0113 import javax.swing.table.DefaultTableCellRenderer;
0114 
0115 @SuppressWarnings("serial")
0116 @CreoleResource(name = "Serial Application Editor", guiType = GuiType.LARGE,
0117     resourceDisplayed = "gate.creole.SerialController", mainViewer = true)
0118 public class SerialControllerEditor extends AbstractVisualResource
0119                                implements CreoleListener, ControllerListener,
0120                                           ActionsPublisher{
0121 
0122   public SerialControllerEditor() {
0123 
0124   }
0125 
0126   @Override
0127   public void setTarget(Object target){
0128     if(!(target instanceof SerialController))
0129     throw new IllegalArgumentException(
0130       "gate.gui.ApplicationViewer can only be used for serial controllers\n" +
0131       target.getClass().toString() +
0132       " is not a gate.creole.SerialController!");
0133     if(controller != nullcontroller.removeControllerListener(this);
0134     this.controller = (SerialController)target;
0135     controller.addControllerListener(this);
0136     corpusControllerMode = controller instanceof CorpusController;
0137     analyserMode = controller instanceof SerialAnalyserController ||
0138                    controller instanceof ConditionalSerialAnalyserController;
0139     conditionalMode = controller instanceof ConditionalController;
0140     
0141     initLocalData();
0142     initGuiComponents();
0143     initListeners();
0144 
0145     loadedPRsTableModel.fireTableDataChanged();
0146     memberPRsTableModel.fireTableDataChanged();
0147 
0148   }//setController
0149 
0150 
0151   @Override
0152   public void setHandle(Handle handle) {
0153     this.handle = handle;
0154 
0155     //register the listeners
0156     addStatusListener(handle);
0157     addProgressListener(handle);
0158   }
0159 
0160   @Override
0161   public Resource init() throws ResourceInstantiationException{
0162     super.init();
0163     return this;
0164   }
0165 
0166   protected void initLocalData() {
0167     actionList = new ArrayList<Action>();
0168     runAction = new RunAction();
0169     //add the items to the popup
0170     actionList.add(null);
0171     actionList.add(runAction);
0172     addPRAction = new AddPRAction();
0173     removePRAction = new RemovePRAction();
0174   }
0175 
0176   @SuppressWarnings({"unchecked""rawtypes"})
0177   protected void initGuiComponents() {
0178     //we use a JSplitPane for most of the content, and add the Run button to 
0179     //the South area
0180     setLayout(new BorderLayout());
0181 
0182     JPanel topSplit = new JPanel();
0183     topSplit.setLayout(new GridBagLayout());
0184     GridBagConstraints constraints = new GridBagConstraints();
0185     constraints.fill = GridBagConstraints.BOTH;
0186     constraints.gridy = 0;
0187     
0188 
0189     loadedPRsTableModel = new LoadedPRsTableModel();
0190     loadedPRsTable = new XJTable();
0191     loadedPRsTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
0192     loadedPRsTable.setSortable(false);
0193     loadedPRsTable.setModel(loadedPRsTableModel);
0194     loadedPRsTable.setDragEnabled(true);
0195     loadedPRsTable.setDefaultRenderer(ProcessingResource.class,
0196                                       new ResourceRenderer());
0197     //create a renderer that doesn't mind being extended horizontally.
0198     loadedPRsTable.setDefaultRenderer(String.class, 
0199             new DefaultTableCellRenderer(){
0200       @Override
0201       public Dimension getMaximumSize() {
0202         //we don't mind being extended horizontally
0203         Dimension dim = super.getMaximumSize();
0204         if(dim != null){
0205           dim.width = Integer.MAX_VALUE;
0206           setMaximumSize(dim);
0207         }
0208         return dim;
0209       }
0210       @Override
0211       public Dimension getMinimumSize() {
0212         //we don't like being squashed!
0213         return getPreferredSize();
0214       }
0215     });
0216 
0217     final int width1 = new JLabel("Loaded Processing resources").
0218                 getPreferredSize().width + 30;
0219     JScrollPane scroller = new JScrollPane(){
0220       @Override
0221       public Dimension getPreferredSize(){
0222         Dimension dim = super.getPreferredSize();
0223         dim.width = Math.max(dim.width, width1);
0224         return dim;
0225       }
0226       @Override
0227       public Dimension getMinimumSize(){
0228         Dimension dim = super.getMinimumSize();
0229         dim.width = Math.max(dim.width, width1);
0230         return dim;
0231       }
0232     };
0233     scroller.getViewport().setView(loadedPRsTable);
0234     scroller.setBorder(BorderFactory.
0235                        createTitledBorder(BorderFactory.createEtchedBorder(),
0236                                           " Loaded Processing resources "));
0237 
0238     //adding a scrollable table
0239     constraints.weightx = 1;
0240     constraints.weighty = 1;
0241     constraints.insets = new Insets(0,0,0,5);
0242     topSplit.add(scroller, constraints);
0243 
0244     
0245     addButton = new JButton(addPRAction);
0246     addButton.setText("");
0247     addButton.setEnabled(false);
0248     removeButton = new JButton(removePRAction);
0249     removeButton.setText("");
0250     removeButton.setEnabled(false);
0251 
0252     Box buttonsBox =Box.createVerticalBox();
0253     buttonsBox.add(Box.createVerticalGlue());
0254     buttonsBox.add(addButton);
0255     buttonsBox.add(Box.createVerticalStrut(5));
0256     buttonsBox.add(removeButton);
0257     buttonsBox.add(Box.createVerticalGlue());
0258 
0259     constraints.weightx = 0;
0260     constraints.weighty = 0;
0261     constraints.insets = new Insets(0,0,0,5);
0262     topSplit.add(buttonsBox, constraints);
0263 
0264     memberPRsTableModel = new MemberPRsTableModel();
0265     memberPRsTable = new XJTable();
0266     memberPRsTable.setSortable(false);
0267     memberPRsTable.setModel(memberPRsTableModel);
0268     memberPRsTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
0269     memberPRsTable.setDefaultRenderer(ProcessingResource.class,
0270                                       new ResourceRenderer());
0271     memberPRsTable.setDefaultRenderer(String.class, 
0272             new DefaultTableCellRenderer(){
0273       @Override
0274       public Dimension getMaximumSize() {
0275         //we don't mind being extended horizontally
0276         Dimension dim = super.getMaximumSize();
0277         if(dim != null){
0278           dim.width = Integer.MAX_VALUE;
0279           setMaximumSize(dim);
0280         }
0281         return dim;
0282       }
0283       @Override
0284       public Dimension getMinimumSize() {
0285         //we don't like being squashed!
0286         return getPreferredSize();
0287       }
0288     });
0289     memberPRsTable.setDefaultRenderer(Icon.class, new IconRenderer());
0290     memberPRsTable.setDragEnabled(true);
0291 
0292     final int width2 = new JLabel("Selected Processing resources").
0293                            getPreferredSize().width + 30;
0294     scroller = new JScrollPane(){
0295       @Override
0296       public Dimension getPreferredSize(){
0297         Dimension dim = super.getPreferredSize();
0298         dim.width = Math.max(dim.width, width2);
0299         return dim;
0300       }
0301       @Override
0302       public Dimension getMinimumSize(){
0303         Dimension dim = super.getMinimumSize();
0304         dim.width = Math.max(dim.width, width2);
0305         return dim;
0306       }      
0307     };
0308     scroller.getViewport().setView(memberPRsTable);
0309     scroller.setBorder(BorderFactory.
0310                        createTitledBorder(BorderFactory.createEtchedBorder(),
0311                                           " Selected Processing resources "));
0312 
0313     //adding a scrollable table
0314     constraints.weightx = 1;
0315     constraints.weighty = 1;
0316     constraints.insets = new Insets(0,0,0,5);
0317     topSplit.add(scroller, constraints);
0318 
0319     
0320     moveUpButton = new JButton(MainFrame.getIcon("up"));
0321     moveUpButton.setMnemonic(KeyEvent.VK_UP);
0322     moveUpButton.setToolTipText("Move the selected resources up.");
0323     moveUpButton.setEnabled(false);
0324     moveDownButton = new JButton(MainFrame.getIcon("down"));
0325     moveDownButton.setMnemonic(KeyEvent.VK_DOWN);
0326     moveDownButton.setToolTipText("Move the selected resources down.");
0327     moveDownButton.setEnabled(false);
0328 
0329     buttonsBox =Box.createVerticalBox();
0330     buttonsBox.add(Box.createVerticalGlue());
0331     buttonsBox.add(moveUpButton);
0332     buttonsBox.add(Box.createVerticalStrut(5));
0333     buttonsBox.add(moveDownButton);
0334     buttonsBox.add(Box.createVerticalGlue());
0335 
0336     //adding a scrollable table
0337     constraints.weightx = 0;
0338     constraints.weighty = 0;
0339     constraints.insets = new Insets(0,0,0,0);
0340     topSplit.add(buttonsBox, constraints);
0341     
0342     // =========== BOTTOM Half ===========
0343     JPanel bottomSplit = new JPanel();
0344     bottomSplit.setLayout(new GridBagLayout());
0345     
0346     //first row
0347     constraints.gridy = 0;
0348     
0349     if(conditionalMode){
0350       strategyPanel = new JPanel();
0351       strategyPanel.setLayout(new BoxLayout(strategyPanel, BoxLayout.X_AXIS));
0352       strategyPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
0353       runBtnGrp = new ButtonGroup();
0354       yes_RunRBtn = new JRadioButton("Yes"true);
0355       yes_RunRBtn.setHorizontalTextPosition(AbstractButton.LEFT);
0356       runBtnGrp.add(yes_RunRBtn);
0357       no_RunRBtn = new JRadioButton("No"false);
0358       no_RunRBtn.setHorizontalTextPosition(AbstractButton.LEFT);
0359       runBtnGrp.add(no_RunRBtn);
0360       conditional_RunRBtn = new JRadioButton("If value of feature"false);
0361       conditional_RunRBtn.setHorizontalTextPosition(AbstractButton.LEFT);
0362       runBtnGrp.add(conditional_RunRBtn);
0363 
0364       featureNameTextField = new JTextField(""25);
0365       featureNameTextField.setMaximumSize(
0366                            new Dimension(Integer.MAX_VALUE,
0367                                          featureNameTextField.getPreferredSize().
0368                                          height));
0369       
0370       featureValueTextField = new JTextField(""25);
0371       featureValueTextField.setMaximumSize(
0372                            new Dimension(Integer.MAX_VALUE,
0373                                          featureValueTextField.getPreferredSize().
0374                                          height));
0375       
0376       strategyPanel.add(new JLabel(MainFrame.getIcon("greenBall")));
0377       strategyPanel.add(yes_RunRBtn);
0378       strategyPanel.add(Box.createHorizontalStrut(5));
0379 
0380       strategyPanel.add(new JLabel(MainFrame.getIcon("redBall")));
0381       strategyPanel.add(no_RunRBtn);
0382       strategyPanel.add(Box.createHorizontalStrut(5));
0383 
0384       strategyPanel.add(new JLabel(MainFrame.getIcon("yellowBall")));
0385       strategyPanel.add(conditional_RunRBtn);
0386       strategyPanel.add(Box.createHorizontalStrut(5));
0387 
0388       strategyPanel.add(featureNameTextField);
0389       strategyPanel.add(Box.createHorizontalStrut(5));
0390       strategyPanel.add(new JLabel("is"));
0391       strategyPanel.add(Box.createHorizontalStrut(5));
0392       strategyPanel.add(featureValueTextField);
0393       strategyPanel.add(Box.createHorizontalStrut(5));
0394       strategyBorder = BorderFactory.createTitledBorder(
0395           BorderFactory.createEtchedBorder(),
0396           " No processing resource selected... ");
0397       strategyPanel.setBorder(strategyBorder);
0398 
0399 
0400       constraints.weightx = 1;
0401       constraints.weighty = 0;
0402       constraints.insets = new Insets(0,0,0,0);
0403       bottomSplit.add(strategyPanel, constraints);
0404       constraints.gridy++;
0405     }//if conditional mode    
0406     
0407     if(corpusControllerMode){
0408       //we need to add the corpus combo
0409       corpusCombo = new JComboBox(corpusComboModel = new CorporaComboModel());
0410       corpusCombo.setRenderer(new ResourceRenderer());
0411       corpusCombo.setMaximumSize(new Dimension(Integer.MAX_VALUE,
0412                                                corpusCombo.getPreferredSize().
0413                                                height));
0414       Corpus corpus = null;
0415       if(controller instanceof CorpusController){
0416         corpus = ((CorpusController)controller).getCorpus();
0417       }else{
0418         throw new GateRuntimeException("Controller editor in corpus " +
0419                                        "controller mode " +
0420                                        "but the target controller is not an " +
0421                                        "CorpusController!");
0422       }
0423 
0424       if(corpus != null){
0425         corpusCombo.setSelectedItem(corpus);
0426       }else{
0427         if(corpusCombo.getModel().getSize() 1corpusCombo.setSelectedIndex(1);
0428         else corpusCombo.setSelectedIndex(0);
0429       }
0430       JPanel horBox = new JPanel();
0431       horBox.setLayout(new BoxLayout(horBox, BoxLayout.X_AXIS));
0432       horBox.setAlignmentX(Component.LEFT_ALIGNMENT);
0433       horBox.add(new JLabel("Corpus:"));
0434       horBox.add(Box.createHorizontalStrut(5));
0435       horBox.add(corpusCombo);
0436       horBox.add(Box.createHorizontalStrut(5));
0437 
0438       constraints.weightx = 1;
0439       constraints.anchor = GridBagConstraints.WEST;
0440       constraints.fill = GridBagConstraints.BOTH;
0441       constraints.weighty = 0;
0442       constraints.insets = new Insets(0,0,0,0);
0443       bottomSplit.add(horBox, constraints);
0444 
0445       //all the following rows have one element only
0446       constraints.gridwidth = 1;
0447       constraints.gridy++;
0448     }//if(corpusControllerMode)    
0449     
0450     parametersPanel = new JPanel();
0451     parametersPanel.setLayout(new BoxLayout(parametersPanel, BoxLayout.Y_AXIS));
0452     parametersPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
0453     parametersBorder = BorderFactory.createTitledBorder(
0454                                       BorderFactory.createEtchedBorder(),
0455                                       " No selected processing resource ");
0456     parametersPanel.setBorder(parametersBorder);
0457     parametersEditor = new ResourceParametersEditor();
0458     parametersEditor.init(null, null);
0459     parametersPanel.add(new JScrollPane(parametersEditor));
0460 //    parametersPanel.add(parametersEditor, constraints);
0461     
0462     constraints.weighty = 1;
0463     constraints.weightx = 1;
0464     constraints.anchor = GridBagConstraints.CENTER;
0465     constraints.fill = GridBagConstraints.BOTH;
0466     constraints.insets = new Insets(0,0,0,0);
0467     bottomSplit.add(parametersPanel, constraints);
0468     constraints.gridy++;
0469 
0470     constraints.weightx = 0;
0471     constraints.weighty = 0;
0472     constraints.fill = GridBagConstraints.NONE;
0473     constraints.anchor = GridBagConstraints.CENTER;
0474     bottomSplit.add(new JButton(runAction), constraints);
0475 
0476     final JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, 
0477             topSplit, bottomSplit);
0478     splitPane.addAncestorListener(new AncestorListener() {
0479       @Override
0480       public void ancestorRemoved(AncestorEvent event) {}
0481       @Override
0482       public void ancestorMoved(AncestorEvent event) {}
0483       /**
0484        * One-shot ancestor listener that places the divider location on first
0485        * show, and then de-registers self. 
0486        */
0487       @Override
0488       public void ancestorAdded(AncestorEvent event) {
0489         // This seems to work more reliably if queued rather than executed
0490         // directly.
0491         SwingUtilities.invokeLater(new Runnable(){
0492           @Override
0493           public void run(){
0494             splitPane.setDividerLocation(0.5);    
0495           }
0496         });
0497         splitPane.removeAncestorListener(this);
0498       }
0499     });
0500     
0501     add(splitPane, BorderLayout.CENTER);
0502   }// initGuiComponents()
0503 
0504   protected void initListeners() {
0505     Gate.getCreoleRegister().addCreoleListener(this);
0506 
0507     this.addMouseListener(new MouseAdapter() {
0508       @Override
0509       public void mousePressed(MouseEvent e) {
0510         processMouseEvent(e);
0511       }
0512       @Override
0513       public void mouseReleased(MouseEvent e) {
0514         processMouseEvent(e);
0515       }
0516       protected void processMouseEvent(MouseEvent e) {
0517         if(e.isPopupTrigger()) {
0518           // context menu
0519           if(handle != null
0520           && handle.getPopup() != null) {
0521             handle.getPopup().show(SerialControllerEditor.this,
0522                                    e.getX(), e.getY());
0523           }
0524         }
0525       }
0526     });
0527 
0528     moveUpButton.addActionListener(new ActionListener() {
0529       @Override
0530       public void actionPerformed(ActionEvent e) {
0531         int rows[] = memberPRsTable.getSelectedRows();
0532         if(rows == null || rows.length == 0){
0533           JOptionPane.showMessageDialog(
0534               SerialControllerEditor.this,
0535               "Please select some components to be moved "+
0536               "from the list of used components!\n" ,
0537               "GATE", JOptionPane.ERROR_MESSAGE);
0538         else {
0539           //we need to make sure the rows are sorted
0540           Arrays.sort(rows);
0541           //get the list of PRs
0542           for(int row : rows) {
0543             if(row > 0) {
0544               //move it up
0545               List<RunningStrategy> strategies = null;
0546               if(conditionalMode) {
0547                 strategies = new ArrayList<RunningStrategy>(((ConditionalController)controller)
0548                         .getRunningStrategies());
0549                 RunningStrategy straegy = strategies.remove(row);
0550                 strategies.add(row-1, straegy)
0551               }
0552               
0553               ProcessingResource value = controller.remove(row);
0554               controller.add(row - 1, value);
0555               
0556               if(conditionalMode) {
0557                 ((ConditionalController)controller).setRunningStrategies(strategies);;
0558               }
0559             }
0560           }
0561 //          memberPRsTableModel.fireTableDataChanged();
0562           //restore selection
0563           for(int row : rows) {
0564             int newRow;
0565             if(row > 0newRow = row - 1;
0566             else newRow = row;
0567             memberPRsTable.addRowSelectionInterval(newRow, newRow);
0568           }
0569           memberPRsTable.requestFocusInWindow();
0570         }
0571 
0572       }
0573     });
0574 
0575     moveDownButton.addActionListener(new ActionListener() {
0576       @Override
0577       public void actionPerformed(ActionEvent e) {
0578         int rows[] = memberPRsTable.getSelectedRows();
0579         if(rows == null || rows.length == 0){
0580           JOptionPane.showMessageDialog(
0581               SerialControllerEditor.this,
0582               "Please select some components to be moved "+
0583               "from the list of used components!\n" ,
0584               "GATE", JOptionPane.ERROR_MESSAGE);
0585         else {
0586           //we need to make sure the rows are sorted
0587           Arrays.sort(rows);
0588           //get the list of PRs
0589           for(int i = rows.length - 1; i >= 0; i--){
0590             int row = rows[i];
0591             if(row < controller.getPRs().size() -1){
0592               
0593               List<RunningStrategy> strategies = null;
0594               if(conditionalMode) {
0595                 strategies = new ArrayList<RunningStrategy>(((ConditionalController)controller)
0596                         .getRunningStrategies());
0597                 RunningStrategy straegy = strategies.remove(row);
0598                 strategies.add(row+1, straegy)
0599               }
0600               
0601               //move it down
0602               ProcessingResource value = controller.remove(row);
0603               controller.add(row + 1, value);
0604               
0605               if(conditionalMode) {
0606                 ((ConditionalController)controller).setRunningStrategies(strategies);;
0607               }
0608             }
0609           }
0610 //          memberPRsTableModel.fireTableDataChanged();
0611           //restore selection
0612           for(int row : rows) {
0613             int newRow;
0614             if(row < controller.getPRs().size() 1newRow = row + 1;
0615             else newRow = row;
0616             memberPRsTable.addRowSelectionInterval(newRow, newRow);
0617           }
0618           memberPRsTable.requestFocusInWindow();
0619         }
0620 
0621       }
0622     });
0623 
0624     // mouse click edit the resource
0625     // mouse double click or context menu add the resource to the application
0626     loadedPRsTable.addMouseListener(new MouseAdapter() {
0627       @Override
0628       public void mousePressed(MouseEvent e) {
0629         if(e.isPopupTrigger()) { processMouseEvent(e)}
0630       }
0631       @Override
0632       public void mouseReleased(MouseEvent e) {
0633         if(e.isPopupTrigger()) { processMouseEvent(e)}
0634       }
0635       @Override
0636       public void mouseClicked(MouseEvent e) {
0637         processMouseEvent(e);
0638       }
0639       protected void processMouseEvent(MouseEvent e) {
0640         int row = loadedPRsTable.rowAtPoint(e.getPoint());
0641         if(row == -1) { return}
0642         //ProcessingResource pr = (ProcessingResource) loadedPRsTable
0643         //  .getValueAt(row, loadedPRsTable.convertColumnIndexToView(0));
0644 
0645         if(e.isPopupTrigger()) {
0646           // context menu
0647           if(!loadedPRsTable.isRowSelected(row)) {
0648             // if right click outside the selection then reset selection
0649             loadedPRsTable.getSelectionModel().setSelectionInterval(row, row);
0650           }
0651           JPopupMenu popup = new XJPopupMenu();
0652           popup.add(addPRAction);
0653           popup.show(loadedPRsTable, e.getPoint().x, e.getPoint().y);
0654 
0655         else if(e.getID() == MouseEvent.MOUSE_CLICKED) {
0656           if (e.getClickCount() == 2) {
0657             //add selected modules on double click
0658             addPRAction.actionPerformed(null);
0659           }
0660         }
0661       }
0662     });
0663 
0664     // drag and drop support
0665     loadedPRsTable.setTransferHandler(new TransferHandler() {
0666       // minimal drag and drop that only call the removePRAction when importing
0667       String source = "";
0668       @Override
0669       public int getSourceActions(JComponent c) {
0670         return MOVE;
0671       }
0672       @Override
0673       protected Transferable createTransferable(JComponent c) {
0674         return new StringSelection("loadedPRsTable");
0675       }
0676       @Override
0677       protected void exportDone(JComponent c, Transferable data, int action) {
0678       }
0679       @Override
0680       public boolean canImport(JComponent c, DataFlavor[] flavors) {
0681         for(DataFlavor flavor : flavors) {
0682           if(DataFlavor.stringFlavor.equals(flavor)) {
0683             return true;
0684           }
0685         }
0686         return false;
0687       }
0688       @Override
0689       public boolean importData(JComponent c, Transferable t) {
0690         if (canImport(c, t.getTransferDataFlavors())) {
0691           try {
0692               source = (String)t.getTransferData(DataFlavor.stringFlavor);
0693               if (source.startsWith("memberPRsTable")) {
0694                 removePRAction.actionPerformed(null);
0695                 return true;
0696               else {
0697                 return false;
0698               }
0699           catch (UnsupportedFlavorException ufe) { // just return false later
0700           catch (IOException ioe) { // just return false later
0701           }
0702         }
0703         return false;
0704       }
0705     });
0706     
0707     // mouse click edit the resource
0708     // mouse double click or context menu remove the resource from the
0709     // application
0710     memberPRsTable.addMouseListener(new MouseAdapter() {
0711       @Override
0712       public void mousePressed(MouseEvent e) {
0713         if(e.isPopupTrigger()) { processMouseEvent(e)}
0714       }
0715       @Override
0716       public void mouseReleased(MouseEvent e) {
0717         if(e.isPopupTrigger()) { processMouseEvent(e)}
0718       }
0719       @Override
0720       public void mouseClicked(MouseEvent e) {
0721         processMouseEvent(e);
0722       }
0723       protected void processMouseEvent(MouseEvent e) {
0724         int row = memberPRsTable.rowAtPoint(e.getPoint());
0725         if(row == -1) { return}
0726 
0727         if(e.isPopupTrigger()) {
0728           // context menu
0729           if(!memberPRsTable.isRowSelected(row)) {
0730             // if right click outside the selection then reset selection
0731             memberPRsTable.getSelectionModel().setSelectionInterval(row, row);
0732           }
0733           JPopupMenu popup = new XJPopupMenu();
0734           popup.add(removePRAction);
0735           popup.show(memberPRsTable, e.getPoint().x, e.getPoint().y);
0736 
0737         else if(e.getID() == MouseEvent.MOUSE_CLICKED) {
0738           if (e.getClickCount() == 2) {
0739             // open the double-clicked PR in the main view.
0740             Component root = SwingUtilities.getRoot(SerialControllerEditor.this);
0741             if (!(root instanceof MainFrame)) { return}
0742             final MainFrame mainFrame = (MainFrameroot;
0743             if(controller != null) {
0744               ProcessingResource res = 
0745                   controller.getPRs().get(row);
0746               if(res != nullmainFrame.select(res);
0747             }
0748           }
0749         }
0750       }
0751     });
0752 
0753     // Drag and drop support
0754     memberPRsTable.setTransferHandler(new TransferHandler() {
0755       // minimal drag and drop that only call the addPRAction when importing
0756       String source = "";
0757       @Override
0758       public int getSourceActions(JComponent c) {
0759         return MOVE;
0760       }
0761       @Override
0762       protected Transferable createTransferable(JComponent c) {
0763         int selectedRows[] = memberPRsTable.getSelectedRows();
0764         Arrays.sort(selectedRows);
0765         return new StringSelection("memberPRsTable"
0766           + Arrays.toString(selectedRows));
0767       }
0768       @Override
0769       protected void exportDone(JComponent c, Transferable data, int action) {
0770       }
0771       @Override
0772       public boolean canImport(JComponent c, DataFlavor[] flavors) {
0773         for(DataFlavor flavor : flavors) {
0774           if(DataFlavor.stringFlavor.equals(flavor)) {
0775             return true;
0776           }
0777         }
0778         return false;
0779       }
0780       @Override
0781       public boolean importData(JComponent c, Transferable t) {
0782         if (!canImport(c, t.getTransferDataFlavors())) {
0783           return false;
0784         }
0785         try {
0786           source = (String)t.getTransferData(DataFlavor.stringFlavor);
0787           if (source.startsWith("memberPRsTable")) {
0788             int insertion = memberPRsTable.getSelectedRow();
0789             int initialInsertion = insertion;
0790             List<ProcessingResource> prs = new ArrayList<ProcessingResource>();
0791             source = source.replaceFirst("^memberPRsTable\\[""");
0792             source = source.replaceFirst("\\]$""");
0793             String selectedRows[] = source.split(", ");
0794             if (Integer.valueOf(selectedRows[0]) < insertion) { insertion++; }
0795             // get the list of PRs selected when dragging started
0796             for(String row : selectedRows) {
0797               if (Integer.valueOf(row== initialInsertion) {
0798                 // the user draged the selected rows on themselves, do nothing
0799                 return false;
0800               }
0801               prs.add((ProcessingResourcememberPRsTable.getValueAt(
0802                 Integer.valueOf(row),
0803                 memberPRsTable.convertColumnIndexToView(1)));
0804               if (Integer.valueOf(row< initialInsertion) { insertion--; }
0805             }
0806             // remove the PRs selected when dragging started
0807             for (ProcessingResource pr : prs) {
0808               controller.remove(pr);
0809             }
0810             // add the PRs at the insertion point
0811             for (ProcessingResource pr : prs) {
0812               controller.add(insertion, pr);
0813               insertion++;
0814             }
0815             // select the moved PRs
0816             memberPRsTable.addRowSelectionInterval(
0817               insertion - selectedRows.length, insertion - 1);
0818             return true;
0819           else if (source.equals("loadedPRsTable")) {
0820             addPRAction.actionPerformed(null);
0821             return true;
0822           else {
0823             return false;
0824           }
0825         catch (UnsupportedFlavorException ufe) {
0826           return false;
0827         catch (IOException ioe) {
0828           return false;
0829         }
0830       }
0831     });
0832     
0833     loadedPRsTable.getSelectionModel().addListSelectionListener(
0834       new ListSelectionListener() {
0835         @Override
0836         public void valueChanged(ListSelectionEvent e) {
0837           // disable Add button if no selection
0838           addButton.setEnabled(loadedPRsTable.getSelectedRowCount() 0);
0839         }
0840       });
0841 
0842     memberPRsTable.getSelectionModel().addListSelectionListener(
0843       new ListSelectionListener() {
0844         @Override
0845         public void valueChanged(ListSelectionEvent e) {
0846           // disable Remove and Move buttons if no selection
0847           removeButton.setEnabled(memberPRsTable.getSelectedRowCount() 0);
0848           moveUpButton.setEnabled(memberPRsTable.getSelectedRowCount() 0
0849             && !memberPRsTable.isRowSelected(0));
0850           moveDownButton.setEnabled(memberPRsTable.getSelectedRowCount() 0
0851             && !memberPRsTable.isRowSelected(memberPRsTable.getRowCount() 1));
0852           //update the parameters & strategy editors
0853           if(memberPRsTable.getSelectedRowCount() == 1){
0854             //only one selection
0855             selectPR(memberPRsTable.getSelectedRow());
0856           }else{
0857             //clean up UI
0858             selectPR(-1);
0859           }
0860         }
0861       });
0862 
0863     if(conditionalMode){
0864       /**
0865        * A listener called when the selection state changes for any of the
0866        * execution mode radio buttons. We use selection changes rather than 
0867        * action listeners, as the change of state may not be as results of an 
0868        * action (e.g. editing one of the text fields, changes the selection). 
0869        */
0870       ItemListener strategyModeListener = new ItemListener() {
0871         @Override
0872         public void itemStateChanged(ItemEvent e) {
0873           if(selectedPRRunStrategy != null) {
0874             if(selectedPRRunStrategy instanceof AnalyserRunningStrategy){
0875               AnalyserRunningStrategy strategy =
0876                 (AnalyserRunningStrategy)selectedPRRunStrategy;
0877               if(yes_RunRBtn.isSelected()){
0878                 strategy.setRunMode(RunningStrategy.RUN_ALWAYS);
0879               }else if(no_RunRBtn.isSelected()){
0880                 strategy.setRunMode(RunningStrategy.RUN_NEVER);
0881               }else if(conditional_RunRBtn.isSelected()){
0882                 strategy.setRunMode(RunningStrategy.RUN_CONDITIONAL);
0883               }
0884             else if(selectedPRRunStrategy instanceof UnconditionalRunningStrategy) {
0885               UnconditionalRunningStrategy strategy =
0886                 (UnconditionalRunningStrategy)selectedPRRunStrategy;
0887               if(yes_RunRBtn.isSelected()){
0888                 strategy.shouldRun(true);
0889               }else if(no_RunRBtn.isSelected()){
0890                 strategy.shouldRun(false);
0891               }
0892             }
0893           }
0894           //some icons may have changed!
0895           memberPRsTable.repaint();
0896         }
0897       };
0898       
0899       yes_RunRBtn.addItemListener(strategyModeListener);
0900       no_RunRBtn.addItemListener(strategyModeListener);
0901       conditional_RunRBtn.addItemListener(strategyModeListener);
0902       
0903       
0904       featureNameTextField.getDocument().addDocumentListener(
0905       new javax.swing.event.DocumentListener() {
0906         @Override
0907         public void insertUpdate(javax.swing.event.DocumentEvent e) {
0908           changeOccured(e);
0909         }
0910 
0911         @Override
0912         public void removeUpdate(javax.swing.event.DocumentEvent e) {
0913           changeOccured(e);
0914         }
0915 
0916         @Override
0917         public void changedUpdate(javax.swing.event.DocumentEvent e) {
0918           changeOccured(e);
0919         }
0920 
0921         protected void changeOccured(javax.swing.event.DocumentEvent e){
0922           if(selectedPRRunStrategy != null &&
0923              selectedPRRunStrategy instanceof AnalyserRunningStrategy){
0924             AnalyserRunningStrategy strategy =
0925               (AnalyserRunningStrategy)selectedPRRunStrategy;
0926             strategy.setFeatureName(featureNameTextField.getText());
0927           }
0928           //editing the textfield changes the running strategy to conditional
0929           conditional_RunRBtn.setSelected(true);
0930         }
0931       });
0932 
0933       featureValueTextField.getDocument().addDocumentListener(
0934       new javax.swing.event.DocumentListener() {
0935         @Override
0936         public void insertUpdate(javax.swing.event.DocumentEvent e) {
0937           changeOccured(e);
0938         }
0939 
0940         @Override
0941         public void removeUpdate(javax.swing.event.DocumentEvent e) {
0942           changeOccured(e);
0943         }
0944 
0945         @Override
0946         public void changedUpdate(javax.swing.event.DocumentEvent e) {
0947           changeOccured(e);
0948         }
0949 
0950         protected void changeOccured(javax.swing.event.DocumentEvent e){
0951           if(selectedPRRunStrategy != null &&
0952              selectedPRRunStrategy instanceof AnalyserRunningStrategy){
0953             AnalyserRunningStrategy strategy =
0954               (AnalyserRunningStrategy)selectedPRRunStrategy;
0955             strategy.setFeatureValue(featureValueTextField.getText());
0956           }
0957           //editing the textfield changes the running strategy to conditional
0958           conditional_RunRBtn.setSelected(true);
0959         }
0960       });
0961     }//if conditional
0962     
0963     if(corpusControllerMode){
0964       corpusCombo.addPopupMenuListener(new PopupMenuListener() {
0965         @Override
0966         public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
0967           corpusComboModel.fireDataChanged();
0968         }
0969 
0970         @Override
0971         public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
0972         }
0973 
0974         @Override
0975         public void popupMenuCanceled(PopupMenuEvent e) {
0976         }
0977       });
0978     }
0979 
0980     addAncestorListener(new AncestorListener() {
0981       @Override
0982       public void ancestorAdded(AncestorEvent event) {
0983         // every time the user switches back to this view, we check
0984         // whether another controller has just included this one
0985         loadedPRsTableModel.fireTableDataChanged();
0986         memberPRsTableModel.fireTableDataChanged();
0987       }
0988       @Override
0989       public void ancestorRemoved(AncestorEvent event) { /* do nothing */ }
0990       @Override
0991       public void ancestorMoved(AncestorEvent event) { /* do nothing */
0992       }
0993     }
0994     );
0995 
0996     // binds F3 key to the run action
0997     getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
0998       .put(KeyStroke.getKeyStroke("F3")"Run");
0999     getActionMap().put("Run", runAction);
1000   
1001   }//protected void initListeners()
1002   
1003   @Override
1004   public List<Action> getActions(){
1005     return actionList;
1006   }
1007 
1008   /**
1009    * Cleans the internal data and prepares this object to be collected
1010    */
1011   @Override
1012   public void cleanup(){
1013     Gate.getCreoleRegister().removeCreoleListener(this);
1014     controller.removeControllerListener(this);
1015     controller = null;
1016     progressListeners.clear();
1017     statusListeners.clear();
1018     parametersEditor.cleanup();
1019     handle = null;
1020   }
1021 
1022   /**
1023    * Called when a PR has been selected in the member PRs table;
1024    @param index row index in {@link #memberPRsTable} (or -1 if no PR is
1025    * currently selected)
1026    */
1027   protected void selectPR(int index){
1028     //stop current editing of parameters
1029     if(parametersEditor.getResource() != null){
1030       try{
1031         parametersEditor.setParameters();
1032       }catch(ResourceInstantiationException rie){
1033         JOptionPane.showMessageDialog(
1034             SerialControllerEditor.this,
1035             "Failed to set parameters for \"" 
1036             parametersEditor.getResource().getName() +"\"!\n" ,
1037             "GATE", JOptionPane.ERROR_MESSAGE);
1038         rie.printStackTrace(Err.getPrintWriter());
1039       }
1040       
1041       if(conditionalMode){
1042         if(selectedPRRunStrategy != null &&
1043                 selectedPRRunStrategy instanceof AnalyserRunningStrategy){
1044                AnalyserRunningStrategy strategy =
1045                  (AnalyserRunningStrategy)selectedPRRunStrategy;
1046                strategy.setFeatureName(featureNameTextField.getText());
1047                strategy.setFeatureValue(featureValueTextField.getText());
1048         }
1049         selectedPRRunStrategy = null;
1050       }
1051     }
1052     //find the new PR 
1053     ProcessingResource pr = null;
1054     if(index >= && index < controller.getPRs().size()){
1055       pr = controller.getPRs().get(index);
1056     }
1057     if(pr != null){
1058       //update the GUI for the new PR
1059       ResourceData rData = Gate.getCreoleRegister().
1060                                          get(pr.getClass().getName());
1061       //update the border name
1062       parametersBorder.setTitle(" Runtime Parameters for the \"" + pr.getName() +
1063                                 "\" " + rData.getName() ": ");
1064       //update the params editor
1065       //this is a list of lists
1066       List<List<Parameter>> parameters = 
1067           rData.getParameterList().getRuntimeParameters();
1068       if(corpusControllerMode){
1069         //remove corpus and document
1070         //create a new list so we don't change the one from CreoleReg.
1071         List<List<Parameter>> oldParameters = parameters;
1072         parameters = new ArrayList<List<Parameter>>();
1073         for(List<Parameter> aDisjunction : oldParameters) {
1074           List<Parameter> newDisjunction = new ArrayList<Parameter>();
1075           for(Parameter parameter : aDisjunction) {
1076             if(!parameter.getName().equals("corpus")
1077             && !parameter.getName().equals("document")) {
1078               newDisjunction.add(parameter);
1079             }
1080           }
1081           if(!newDisjunction.isEmpty()) parameters.add(newDisjunction);
1082         }
1083       }
1084       parametersEditor.init(pr, parameters);
1085       
1086       if(conditionalMode){
1087         strategyBorder.setTitle(" Run \"" + pr.getName() "\"? ");
1088         //update the state of the run strategy buttons
1089         yes_RunRBtn.setEnabled(true);
1090         no_RunRBtn.setEnabled(true);
1091         conditional_RunRBtn.setEnabled(true);
1092         
1093         //editing the strategy panel causes the edits to be sent to the current
1094         //strategy object, which can lead to a race condition. 
1095         //So we used a cached value instead.
1096         selectedPRRunStrategy = null;
1097         RunningStrategy newStrategy = ((ConditionalController)controller).
1098                                             getRunningStrategies().get(index);
1099         if(newStrategy instanceof AnalyserRunningStrategy){
1100           featureNameTextField.setEnabled(true);
1101           featureValueTextField.setEnabled(true);
1102           conditional_RunRBtn.setEnabled(true);
1103           featureNameTextField.setText(
1104                 ((AnalyserRunningStrategy)newStrategy).
1105                 getFeatureName());
1106           featureValueTextField.setText(
1107                 ((AnalyserRunningStrategy)newStrategy).
1108                 getFeatureValue());
1109         }
1110         else {
1111           featureNameTextField.setEnabled(false);
1112           featureValueTextField.setEnabled(false);
1113           conditional_RunRBtn.setEnabled(false);
1114         }
1115         switch(newStrategy.getRunMode()){
1116           case RunningStrategy.RUN_ALWAYS:{
1117             yes_RunRBtn.setSelected(true);
1118             break;
1119           }
1120           case RunningStrategy.RUN_NEVER:{
1121             no_RunRBtn.setSelected(true);
1122             break;
1123           }
1124           case RunningStrategy.RUN_CONDITIONAL:{
1125             conditional_RunRBtn.setSelected(true);
1126             break;
1127           }
1128         }//switch
1129         //now that the UI is updated, we can safely link to the new strategy
1130         selectedPRRunStrategy = newStrategy;
1131       }
1132     }else{
1133       //selected PR == null -> clean all mentions of the old PR from the GUI
1134       parametersBorder.setTitle(" No processing resource selected... ");
1135       parametersEditor.init(null, null);
1136       if(conditionalMode){
1137         strategyBorder.setTitle(" No processing resource selected... ");
1138         yes_RunRBtn.setEnabled(false);
1139         no_RunRBtn.setEnabled(false);
1140         conditional_RunRBtn.setEnabled(false);
1141         featureNameTextField.setText("");
1142         featureNameTextField.setEnabled(false);
1143         featureValueTextField.setText("");
1144         featureValueTextField.setEnabled(false);
1145       }
1146     }
1147     //this seems to be needed to show the changes
1148     SerialControllerEditor.this.repaint(100);
1149   }
1150 
1151   /*
1152    * Utility method to refresh the PR lists on the EDT but making sure
1153    * that if we are on the EDT we don't wait we do it right now
1154    */
1155   private void refreshPRLists() {
1156     if(SwingUtilities.isEventDispatchThread()) {
1157       loadedPRsTableModel.fireTableDataChanged();
1158       memberPRsTableModel.fireTableDataChanged();
1159     else {
1160       SwingUtilities.invokeLater(new Runnable() {
1161 
1162         @Override
1163         public void run() {
1164           loadedPRsTableModel.fireTableDataChanged();
1165           memberPRsTableModel.fireTableDataChanged();
1166         }
1167       });
1168     }
1169   }
1170 
1171   //CreoleListener implementation
1172   @Override
1173   public void resourceLoaded(CreoleEvent e) {
1174     if(Gate.getHiddenAttribute(e.getResource().getFeatures())) return;
1175     if(e.getResource() instanceof ProcessingResource){
1176       refreshPRLists();
1177 //      repaint(100);
1178     }else if(e.getResource() instanceof LanguageResource){
1179       if(e.getResource() instanceof Corpus && corpusControllerMode){
1180         corpusComboModel.fireDataChanged();
1181       }
1182     }
1183   }
1184 
1185   @Override
1186   public void resourceUnloaded(CreoleEvent e) {
1187     if(Gate.getHiddenAttribute(e.getResource().getFeatures())) return;
1188     if(e.getResource() instanceof ProcessingResource){
1189       ProcessingResource pr = (ProcessingResource)e.getResource();
1190       if(controller != null && controller.getPRs().contains(pr)){
1191         controller.remove(pr);
1192       }
1193       refreshPRLists();
1194     }
1195     else if(e.getResource() instanceof LanguageResource) {
1196       if(e.getResource() instanceof Corpus && corpusControllerMode) {
1197         Corpus c = (Corpus)e.getResource();
1198         if(controller instanceof CorpusController) {
1199           if(c == ((CorpusController)controller).getCorpus()) {
1200             // setCorpus(null) is also called in the controller's
1201             // resourceUnloaded(), but we can't be sure which handler is
1202             // called first...
1203             ((CorpusController)controller).setCorpus(null);
1204           }
1205         }
1206         else {
1207           throw new GateRuntimeException("Controller editor in analyser mode " +
1208                                          "but the target controller is not an " +
1209                                          "analyser!");
1210         }
1211         corpusComboModel.fireDataChanged();
1212       }
1213     }
1214   }
1215 
1216   @Override
1217   public void resourceRenamed(Resource resource, String oldName,
1218                               String newName){
1219     if(Gate.getHiddenAttribute(resource.getFeatures())) return;
1220     if(resource instanceof ProcessingResource){
1221       repaint(100);
1222     }
1223   }
1224 
1225   @Override
1226   public void datastoreOpened(CreoleEvent e) {
1227   }
1228   @Override
1229   public void datastoreCreated(CreoleEvent e) {
1230   }
1231   @Override
1232   public void datastoreClosed(CreoleEvent e) {
1233   }
1234   public synchronized void removeStatusListener(StatusListener l) {
1235     if (statusListeners != null && statusListeners.contains(l)) {
1236       @SuppressWarnings("unchecked")
1237       Vector<StatusListener> v = (Vector<StatusListener>statusListeners.clone();
1238       v.removeElement(l);
1239       statusListeners = v;
1240     }
1241   }
1242   
1243   /* (non-Javadoc)
1244    * @see gate.event.ControllerListener#resourceAdded(gate.event.ControllerEvent)
1245    */
1246   @Override
1247   public void resourceAdded(ControllerEvent evt){
1248     refreshPRLists();    
1249   }
1250   
1251   /* (non-Javadoc)
1252    * @see gate.event.ControllerListener#resourceRemoved(gate.event.ControllerEvent)
1253    */
1254   @Override
1255   public void resourceRemoved(ControllerEvent evt){
1256     refreshPRLists();
1257   }
1258 
1259   public synchronized void addStatusListener(StatusListener l) {
1260     @SuppressWarnings("unchecked")
1261     Vector<StatusListener> v = statusListeners == null ?
1262       new Vector<StatusListener>(2(Vector<StatusListener>statusListeners.clone();
1263     if (!v.contains(l)) {
1264       v.addElement(l);
1265       statusListeners = v;
1266     }
1267   }
1268 
1269   private boolean firstIncludesOrEqualsSecond(Controller first,
1270                                               Controller second) {
1271     if (first.equals(second)) {
1272       return true;
1273     else {
1274       for (Object object : first.getPRs()) {
1275         if (object instanceof Controller) {
1276           if (firstIncludesOrEqualsSecond((Controller)object, second)) {
1277             return true;
1278           }
1279         }
1280       }
1281     }
1282     return false;
1283   }
1284 
1285   /**
1286    * Table model for all the loaded processing resources that are not part of
1287    * the controller.
1288    */
1289   class LoadedPRsTableModel extends AbstractTableModel{
1290     @Override
1291     public int getRowCount(){
1292       List<ProcessingResource> loadedPRs = new ArrayList<ProcessingResource>(
1293         Gate.getCreoleRegister().getPrInstances());
1294       if(controller != null) {
1295         loadedPRs.removeAll(controller.getPRs());
1296       }
1297       Iterator<ProcessingResource> prsIter = loadedPRs.iterator();
1298       while(prsIter.hasNext()){
1299         ProcessingResource aPR = prsIter.next();
1300         if(Gate.getHiddenAttribute(aPR.getFeatures())
1301        || aPR instanceof Controller
1302          && firstIncludesOrEqualsSecond((Controller)aPR, controller)) ) {
1303           prsIter.remove();
1304         }
1305       }
1306 
1307       return loadedPRs.size();
1308     }
1309 
1310     @Override
1311     public Object getValueAt(int row, int column){
1312       List<ProcessingResource> loadedPRs = new ArrayList<ProcessingResource>(
1313         Gate.getCreoleRegister().getPrInstances());
1314       if(controller != null) {
1315         loadedPRs.removeAll(controller.getPRs());
1316       }
1317       Iterator<ProcessingResource> prsIter = loadedPRs.iterator();
1318       while(prsIter.hasNext()){
1319         ProcessingResource aPR = prsIter.next();
1320         if(Gate.getHiddenAttribute(aPR.getFeatures())
1321        || aPR instanceof Controller
1322          && firstIncludesOrEqualsSecond((Controller)aPR, controller)) ) {
1323           prsIter.remove();
1324         }
1325       }
1326 
1327       Collections.sort(loadedPRs, nameComparator);
1328       ProcessingResource pr = loadedPRs.get(row);
1329       switch(column){
1330         case return pr;
1331         case {
1332           ResourceData rData = Gate.getCreoleRegister()
1333             .get(pr.getClass().getName());
1334           if(rData == nullreturn pr.getClass();
1335           else return rData.getName();
1336         }
1337         defaultreturn null;
1338       }
1339     }
1340 
1341     @Override
1342     public int getColumnCount(){
1343       return 2;
1344     }
1345 
1346     @Override
1347     public String getColumnName(int columnIndex){
1348       switch(columnIndex){
1349         case return "Name";
1350         case return "Type";
1351         defaultreturn "?";
1352       }
1353     }
1354 
1355     @Override
1356     public Class<?> getColumnClass(int columnIndex){
1357       switch(columnIndex){
1358         case return ProcessingResource.class;
1359         case return String.class;
1360         defaultreturn Object.class;
1361       }
1362     }
1363 
1364     @Override
1365     public boolean isCellEditable(int rowIndex, int columnIndex){
1366       return false;
1367     }
1368 
1369     @Override
1370     public void setValueAt(Object aValue, int rowIndex, int columnIndex){
1371     }
1372     NameComparator nameComparator = new NameComparator();
1373   }//protected class LoadedPRsTableModel extends AbstractTableModel
1374 
1375   /**
1376    * A model for a combobox containing the loaded corpora in the system
1377    */
1378   @SuppressWarnings("rawtypes")
1379   protected class CorporaComboModel extends AbstractListModel
1380                                   implements ComboBoxModel{
1381     @Override
1382     public int getSize(){
1383       //get all corpora regardless of their actual type
1384       List<Resource> loadedCorpora = null;
1385       try{
1386         loadedCorpora = Gate.getCreoleRegister().
1387                                getAllInstances("gate.Corpus");
1388       }catch(GateException ge){
1389         ge.printStackTrace(Err.getPrintWriter());
1390       }
1391 
1392       return loadedCorpora == null : loadedCorpora.size() 1;
1393     }
1394 
1395     @Override
1396     public Object getElementAt(int index){
1397       if(index == 0return "<none>";
1398       else{
1399         //get all corpora regardless of their actual type
1400         List<Resource> loadedCorpora = null;
1401         try{
1402           loadedCorpora = Gate.getCreoleRegister().
1403                                  getAllInstances("gate.Corpus");
1404         }catch(GateException ge){
1405           ge.printStackTrace(Err.getPrintWriter());
1406         }
1407         return loadedCorpora == null"" : loadedCorpora.get(index - 1);
1408       }
1409     }
1410 
1411     //use the controller for data caching
1412     @Override
1413     public void setSelectedItem(Object anItem){
1414       if(controller instanceof CorpusController)
1415       ((CorpusController)controller).
1416         setCorpus((Corpus)(anItem.equals("<none>"null : anItem));
1417     }
1418 
1419     @Override
1420     public Object getSelectedItem(){
1421       Corpus corpus = null;
1422       if(controller instanceof CorpusController) {
1423         corpus = ((CorpusController)controller).getCorpus();
1424       }else{
1425         throw new GateRuntimeException("Controller editor in corpus " +
1426                                        "controller mode " +
1427                                        "but the target controller is not a " +
1428                                        "CorpusController!");
1429       }
1430       return (corpus == null (Object)"<none>" (Object)corpus);
1431     }
1432 
1433     void fireDataChanged(){
1434       SwingUtilities.invokeLater(new Runnable() {
1435         
1436         @Override
1437         public void run() {
1438           fireContentsChanged(this, 0, getSize());    
1439         }
1440       });
1441       
1442     }
1443   }
1444 
1445   /**
1446    *  Renders JLabel by simply displaying them
1447    */
1448   class IconRenderer extends DefaultTableCellRenderer{
1449     
1450     @Override
1451     public Component getTableCellRendererComponent(JTable table,
1452                                                    Object value,
1453                                                    boolean isSelected,
1454                                                    boolean hasFocus,
1455                                                    int row,
1456                                                    int column){
1457       super.getTableCellRendererComponent(table, "", isSelected, hasFocus, 
1458               row, column);
1459       setIcon((Icon)value);
1460       return this;
1461     }
1462 
1463     @Override
1464     public Dimension getMaximumSize() {
1465       return getPreferredSize();
1466     }
1467 
1468     @Override
1469     public Dimension getMinimumSize() {
1470       return getPreferredSize();
1471     }
1472     
1473   }
1474 
1475   /**
1476    * Table model for all the processing resources in the controller.
1477    */
1478   class MemberPRsTableModel extends AbstractTableModel{
1479     public MemberPRsTableModel(){
1480       green = MainFrame.getIcon("greenBall");
1481       red = MainFrame.getIcon("redBall");
1482       yellow = MainFrame.getIcon("yellowBall");
1483     }
1484     
1485     @Override
1486     public int getRowCount(){
1487       return controller == null : controller.getPRs().size();
1488     }
1489 
1490     @Override
1491     public Object getValueAt(int row, int column){
1492       ProcessingResource pr = controller.getPRs().get(row);
1493       switch(column){
1494         case {
1495           if(conditionalMode){
1496             RunningStrategy strategy = 
1497                                  ((ConditionalController)controller).
1498                                           getRunningStrategies().get(row);
1499             switch(strategy.getRunMode()){
1500               case RunningStrategy.RUN_ALWAYS : return green;
1501               case RunningStrategy.RUN_NEVER : return red;
1502               case RunningStrategy.RUN_CONDITIONAL : return yellow;
1503             }
1504           }
1505           return green;
1506         }
1507         case return pr;
1508         case {
1509           ResourceData rData = Gate.getCreoleRegister().
1510                                     get(pr.getClass().getName());
1511           if(rData == nullreturn pr.getClass();
1512           else return rData.getName();
1513         }
1514         defaultreturn null;
1515       }
1516     }
1517 
1518     @Override
1519     public int getColumnCount(){
1520       return 3;
1521     }
1522 
1523     @Override
1524     public String getColumnName(int columnIndex){
1525       switch(columnIndex){
1526         case return "!";
1527         case return "Name";
1528 //        case 1 : return "!";
1529         case return "Type";
1530         defaultreturn "?";
1531       }
1532     }
1533 
1534     @Override
1535     public Class<?> getColumnClass(int columnIndex){
1536       switch(columnIndex){
1537         case return Icon.class;
1538         case return ProcessingResource.class;
1539 //        case 1 : return Boolean.class;
1540         case return String.class;
1541         defaultreturn Object.class;
1542       }
1543     }
1544 
1545     @Override
1546     public boolean isCellEditable(int rowIndex, int columnIndex){
1547       return false;
1548     }
1549 
1550     @Override
1551     public void setValueAt(Object aValue, int rowIndex, int columnIndex){
1552     }
1553 
1554     protected Icon green, red, yellow;
1555   }//protected class MemberPRsTableModel extends AbstractTableModel
1556 
1557   /** Adds a PR to the controller*/
1558   class AddPRAction extends AbstractAction {
1559     AddPRAction(){
1560       putValue(NAME, "Add selected resources to the application");
1561       putValue(SHORT_DESCRIPTION, "Add selected resources to the application");
1562       putValue(SMALL_ICON, MainFrame.getIcon("right-arrow"));
1563       putValue(MNEMONIC_KEY, KeyEvent.VK_RIGHT);
1564     }
1565 
1566     @Override
1567     public void actionPerformed(ActionEvent e){
1568       try {
1569         List<ProcessingResource> prs = new ArrayList<ProcessingResource>();
1570         int selectedRows[] = loadedPRsTable.getSelectedRows();
1571         Arrays.sort(selectedRows);
1572         for (int row : selectedRows) {
1573           prs.add((ProcessingResourceloadedPRsTable
1574             .getValueAt(row, loadedPRsTable.convertColumnIndexToView(0)));
1575         }
1576         //insert the new PRs after the last currently selected row.
1577         selectedRows = memberPRsTable.getSelectedRows();
1578         Arrays.sort(selectedRows);
1579         int insertion = selectedRows.length == ?
1580                 memberPRsTable.getRowCount() :
1581                 selectedRows[selectedRows.length -1+1;
1582         for (ProcessingResource pr : prs) {
1583           controller.add(insertion, pr);
1584           insertion++;
1585         }      
1586         //select the newly added PRs
1587         for (ProcessingResource pr : prs) {
1588           for (int row = 0; row < memberPRsTable.getRowCount(); row++) {
1589             if (memberPRsTable.getValueAt(row,
1590                   memberPRsTable.convertColumnIndexToView(1)) == pr) {
1591               memberPRsTable.addRowSelectionInterval(row, row);
1592             }
1593           }
1594         }
1595         memberPRsTable.requestFocusInWindow();
1596       }
1597       catch(GateRuntimeException ex) {
1598         JOptionPane.showMessageDialog(SerialControllerEditor.this,
1599               "Could not add PR to pipeline:\n"
1600               +ex.getMessage(),
1601               "GATE", JOptionPane.ERROR_MESSAGE);
1602             return;
1603       }
1604     }
1605   }
1606 
1607   /** Removes a PR from the controller*/
1608   class RemovePRAction extends AbstractAction {
1609     RemovePRAction(){
1610       putValue(NAME, "Remove selected resouces from the application");
1611       putValue(SHORT_DESCRIPTION,
1612         "Remove selected resouces from the application");
1613       putValue(SMALL_ICON, MainFrame.getIcon("left-arrow"));
1614       putValue(MNEMONIC_KEY, KeyEvent.VK_LEFT);
1615     }
1616 
1617     @Override
1618     public void actionPerformed(ActionEvent e){
1619       List<ProcessingResource> prs = new ArrayList<ProcessingResource>();
1620       for (int row : memberPRsTable.getSelectedRows()) {
1621         prs.add((ProcessingResourcememberPRsTable
1622           .getValueAt(row, memberPRsTable.convertColumnIndexToView(1)));
1623       }
1624       for (ProcessingResource pr : prs) {
1625         controller.remove(pr);
1626       }
1627       // transfer the selection
1628       for (ProcessingResource pr : prs) {
1629         for (int row = 0; row < loadedPRsTable.getRowCount(); row++) {
1630           if (loadedPRsTable.getValueAt(row,
1631                 loadedPRsTable.convertColumnIndexToView(0)) == pr) {
1632             loadedPRsTable.addRowSelectionInterval(row, row);
1633           }
1634         }
1635       }
1636       loadedPRsTable.requestFocusInWindow();
1637       if (memberPRsTable.getSelectedRowCount() == 0) {
1638         parametersEditor.init(null, null);
1639         parametersBorder.setTitle("No selected processing resource");
1640       }
1641     }
1642   }
1643 
1644 
1645   /** Runs the Application*/
1646   class RunAction extends AbstractAction {
1647     RunAction(){
1648       super("Run this Application");
1649       super.putValue(SHORT_DESCRIPTION, "<html>Run this application"
1650       +"&nbsp;&nbsp;<font color=#667799><small>F3"
1651       +"&nbsp;&nbsp;</small></font></html>");
1652     }
1653 
1654     @Override
1655     public void actionPerformed(ActionEvent e){
1656 
1657       if (memberPRsTable.getRowCount() == 0) {
1658         JOptionPane.showMessageDialog(SerialControllerEditor.this,
1659           "Add at least one processing resource in the right table\n"
1660           +"that contains the resources of the application to be run.",
1661           "GATE", JOptionPane.ERROR_MESSAGE);
1662         return;
1663       }
1664 
1665       //stop editing the parameters
1666       try{
1667         parametersEditor.setParameters();
1668       }catch(ResourceInstantiationException rie){
1669         JOptionPane.showMessageDialog(
1670           SerialControllerEditor.this,
1671           "Could not set parameters for the \"" +
1672           parametersEditor.getResource().getName() +
1673           "\" processing resource:\nSee \"Messages\" tab for details!",
1674           "GATE", JOptionPane.ERROR_MESSAGE);
1675           rie.printStackTrace(Err.getPrintWriter());
1676           return;
1677       }
1678       
1679       Runnable runnable = new Runnable(){
1680         @Override
1681         public void run(){
1682 
1683           if(corpusControllerMode){
1684             //set the corpus
1685             Object value = corpusCombo.getSelectedItem();
1686             Corpus corpus = value.equals("<none>"null (Corpus)value;
1687             if(analyserMode && corpus == null){
1688               
1689               SwingUtilities.invokeLater(new Runnable(){
1690                 @Override
1691                 public void run() {
1692                   JOptionPane.showMessageDialog(
1693                           SerialControllerEditor.this,
1694                           "No corpus provided!\n" +
1695                           "Please select a corpus and try again!",
1696                           "GATE", JOptionPane.ERROR_MESSAGE);
1697                         corpusCombo.requestFocusInWindow();
1698                 }                
1699               });
1700               return;
1701             }
1702             if(controller instanceof CorpusController)
1703               ((CorpusController)controller).setCorpus(corpus);
1704           }
1705           //check the runtime parameters
1706           List<ProcessingResource> badPRs;
1707           try{
1708             badPRs = controller.getOffendingPocessingResources();
1709           }catch(ResourceInstantiationException rie){
1710             JOptionPane.showMessageDialog(
1711               SerialControllerEditor.this,
1712               "Could not check runtime parameters for " +
1713               "the processing resources:\n" + rie.toString(),
1714               "GATE", JOptionPane.ERROR_MESSAGE);
1715             return;
1716           }
1717           if(badPRs != null && !badPRs.isEmpty()){
1718             String badPRsString = "";
1719             for (Object badPR : badPRs) {
1720               badPRsString += "- "
1721                 ((ProcessingResourcebadPR).getName() "\n";
1722             }
1723             //we know what PRs have problems so it would be nice to show
1724             //them in red or something
1725             JOptionPane.showMessageDialog(
1726               SerialControllerEditor.this,
1727               "Some required runtime parameters are not set\n"+
1728               "in the following resources:\n"+
1729               badPRsString,
1730               "GATE", JOptionPane.ERROR_MESSAGE);
1731             return;
1732           }
1733 
1734           //set the listeners
1735           StatusListener sListener = new InternalStatusListener();
1736           ProgressListener pListener = new InternalProgressListener();
1737 
1738           controller.addStatusListener(sListener);
1739           controller.addProgressListener(pListener);
1740 
1741           Gate.setExecutable(controller);
1742 
1743           int corpusSize = 1;
1744           if (controller instanceof CorpusController) {
1745             Corpus corpus = ((CorpusControllercontroller).getCorpus();
1746             if(corpus != null) {
1747               corpusSize = corpus.size();
1748             }
1749           }
1750           MainFrame.lockGUI("Running " + controller.getName() " on "
1751             + corpusSize + (corpusSize == " document" " documents"));
1752           //execute the thing
1753           long startTime = System.currentTimeMillis();
1754           fireStatusChanged("Start running " + controller.getName() " on "
1755             + corpusSize + (corpusSize == " document" " documents"));
1756           fireProgressChanged(0);
1757 
1758           try {
1759             Benchmark.executeWithBenchmarking(controller,
1760                     Benchmark.createBenchmarkId(controller.getName()null),
1761                     RunAction.this, null);
1762           }catch(final ExecutionInterruptedException eie){
1763             MainFrame.unlockGUI();
1764             SwingUtilities.invokeLater(new Runnable() {
1765               @Override
1766               public void run() {
1767                 JOptionPane.showMessageDialog(
1768                     SerialControllerEditor.this,
1769                     "Interrupted!\n" + eie.toString(),
1770                     "GATE", JOptionPane.ERROR_MESSAGE);
1771               }
1772             });
1773           }catch(final ExecutionException ee) {
1774             ee.printStackTrace(Err.getPrintWriter());
1775             MainFrame.unlockGUI();
1776             SwingUtilities.invokeLater(new Runnable() {
1777             @Override
1778             public void run() {  
1779               JOptionPane.showMessageDialog(
1780                   SerialControllerEditor.this,
1781                   "Execution error while running \"" + controller.getName() +
1782                   "\" :\nSee \"Messages\" tab for details!",
1783                   "GATE", JOptionPane.ERROR_MESSAGE);
1784               }
1785             });
1786           }catch(final Exception e){
1787             e.printStackTrace(Err.getPrintWriter());
1788             MainFrame.unlockGUI();
1789             SwingUtilities.invokeLater(new Runnable() {
1790               @Override
1791               public void run() {
1792                 JOptionPane.showMessageDialog(SerialControllerEditor.this,
1793                     "Unhandled execution error!\n " +
1794                         "See \"Messages\" tab for details!",
1795                         "GATE", JOptionPane.ERROR_MESSAGE);
1796               }
1797             });                                        
1798           }finally{
1799             MainFrame.unlockGUI();
1800             Gate.setExecutable(null);
1801           }//catch
1802 
1803           //remove the listeners
1804           controller.removeStatusListener(sListener);
1805           controller.removeProgressListener(pListener);
1806 
1807           long endTime = System.currentTimeMillis();
1808           fireProcessFinished();
1809           fireStatusChanged(controller.getName() +
1810                             " run in " +
1811                             NumberFormat.getInstance().format(
1812                             (double)(endTime - startTime1000" seconds");
1813         }
1814       };
1815       Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
1816                                  runnable,
1817                                  "ApplicationViewer1");
1818       thread.setPriority(Thread.MIN_PRIORITY);
1819       thread.start();
1820     }//public void actionPerformed(ActionEvent e)
1821   }//class RunAction
1822 
1823   /**
1824    * A simple progress listener used to forward the events upstream.
1825    */
1826   protected class InternalProgressListener implements ProgressListener{
1827     @Override
1828     public void progressChanged(int i){
1829       fireProgressChanged(i);
1830     }
1831 
1832     @Override
1833     public void processFinished(){
1834       fireProcessFinished();
1835     }
1836   }//InternalProgressListener
1837 
1838   /**
1839    * A simple status listener used to forward the events upstream.
1840    */
1841   protected class InternalStatusListener implements StatusListener{
1842     @Override
1843     public void statusChanged(String message){
1844       fireStatusChanged(message);
1845     }
1846   }//InternalStatusListener
1847 
1848   /** The controller this editor edits */
1849   protected SerialController controller;
1850 
1851   /**
1852    * The list of actions provided by this editor
1853    */
1854   protected List<Action> actionList;
1855   /**
1856    * Contains all the PRs loaded in the sytem that are not already part of the
1857    * serial controller
1858    */
1859   protected XJTable loadedPRsTable;
1860 
1861   /**
1862    * model for the {@link #loadedPRsTable} JTable.
1863    */
1864   protected LoadedPRsTableModel loadedPRsTableModel;
1865 
1866   /**
1867    * Displays the PRs in the controller
1868    */
1869   protected XJTable memberPRsTable;
1870 
1871   /** model for {@link #memberPRsTable}*/
1872   protected MemberPRsTableModel memberPRsTableModel;
1873 
1874   /** Adds one or more PR(s) to the controller*/
1875   protected JButton addButton;
1876 
1877   /** Removes one or more PR(s) from the controller*/
1878   protected JButton removeButton;
1879 
1880   /** Moves the module up in the controller list*/
1881   protected JButton moveUpButton;
1882 
1883   /** Moves the module down in the controller list*/
1884   protected JButton moveDownButton;
1885 
1886   /** A component for editing the parameters of the currently selected PR*/
1887   protected ResourceParametersEditor parametersEditor;
1888 
1889   /** A JPanel containing the {@link #parametersEditor}*/
1890   protected JPanel parametersPanel;
1891 
1892   /** A border for the {@link #parametersPanel} */
1893   protected TitledBorder parametersBorder;
1894 
1895 
1896   /** A JPanel containing the running strategy options*/
1897   protected JPanel strategyPanel;
1898 
1899   /** A border for the running strategy options box */
1900   protected TitledBorder strategyBorder;
1901 
1902   /**
1903    * Button for run always.
1904    */
1905   protected JRadioButton yes_RunRBtn;
1906 
1907   /**
1908    * Button for never run.
1909    */
1910   protected JRadioButton no_RunRBtn;
1911 
1912   /**
1913    * Button for conditional run.
1914    */
1915   protected JRadioButton conditional_RunRBtn;
1916 
1917   /**
1918    * The group for run strategy buttons;
1919    */
1920   protected ButtonGroup runBtnGrp;
1921 
1922   /**
1923    * Text field for the feature name for conditional run.
1924    */
1925   protected JTextField featureNameTextField;
1926 
1927   /**
1928    * Text field for the feature value for conditional run.
1929    */
1930   protected JTextField featureValueTextField;
1931 
1932   /**
1933    * A combobox that allows selection of a corpus from the list of loaded
1934    * corpora.
1935    */
1936   @SuppressWarnings("rawtypes")
1937   protected JComboBox corpusCombo;
1938 
1939   protected CorporaComboModel corpusComboModel;
1940 
1941   /** Action that runs the application*/
1942   protected RunAction runAction;
1943 
1944   /**
1945    * Is the controller displayed a CorpusController?
1946    */
1947   protected boolean corpusControllerMode = false;
1948 
1949   /**
1950    * Is the controller displayed an analyser controller?
1951    */
1952   protected boolean analyserMode = false;
1953 
1954   /**
1955    * Is the controller displayed conditional?
1956    */
1957   protected boolean conditionalMode = false;
1958 
1959   /**
1960    * The PR currently selected (having its parameters set)
1961    */
1962   protected ProcessingResource selectedPR = null;
1963 
1964   /**
1965    * The running strategy for the selected PR.
1966    */
1967   protected RunningStrategy selectedPRRunStrategy = null;
1968 
1969   private transient Vector<StatusListener> statusListeners;
1970   private transient Vector<ProgressListener> progressListeners;
1971 
1972   private AddPRAction addPRAction;
1973   private RemovePRAction removePRAction;
1974 
1975 
1976   protected void fireStatusChanged(String e) {
1977     if (statusListeners != null) {
1978       Vector<StatusListener> listeners = statusListeners;
1979       int count = listeners.size();
1980       for (int i = 0; i < count; i++) {
1981         listeners.elementAt(i).statusChanged(e);
1982       }
1983     }
1984   }
1985   public synchronized void removeProgressListener(ProgressListener l) {
1986     if (progressListeners != null && progressListeners.contains(l)) {
1987       @SuppressWarnings("unchecked")
1988       Vector<ProgressListener> v = (Vector<ProgressListener>progressListeners.clone();
1989       v.removeElement(l);
1990       progressListeners = v;
1991     }
1992   }
1993   public synchronized void addProgressListener(ProgressListener l) {
1994     @SuppressWarnings("unchecked")
1995     Vector<ProgressListener> v = progressListeners == null ?
1996       new Vector<ProgressListener>(2(Vector<ProgressListener>progressListeners.clone();
1997     if (!v.contains(l)) {
1998       v.addElement(l);
1999       progressListeners = v;
2000     }
2001   }
2002   protected void fireProgressChanged(int e) {
2003     if (progressListeners != null) {
2004       Vector<ProgressListener> listeners = progressListeners;
2005       int count = listeners.size();
2006       for (int i = 0; i < count; i++) {
2007         listeners.elementAt(i).progressChanged(e);
2008       }
2009     }
2010   }
2011   protected void fireProcessFinished() {
2012     if (progressListeners != null) {
2013       Vector<ProgressListener> listeners = progressListeners;
2014       int count = listeners.size();
2015       for (int i = 0; i < count; i++) {
2016         listeners.elementAt(i).processFinished();
2017       }
2018     }
2019   }
2020 
2021 }