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