All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gate.gui.SerialControllerEditor Maven / Gradle / Ivy

Go to download

GATE - general achitecture for text engineering - is open source software capable of solving almost any text processing problem. This artifact enables you to embed the core GATE Embedded with its essential dependencies. You will able to use the GATE Embedded API and load and store GATE XML documents. This artifact is the perfect dependency for CREOLE plugins or for applications that need to customize the GATE dependencies due to confict with their own dependencies or for lower footprint.

The newest version!
/*
 *  Copyright (c) 1995-2012, The University of Sheffield. See the file
 *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
 *
 *  This file is part of GATE (see http://gate.ac.uk/), and is free
 *  software, licenced under the GNU Library General Public License,
 *  Version 2, June 1991 (in the distribution as file licence.html,
 *  and also available at http://gate.ac.uk/gate/licence.html).
 *
 *  Valentin Tablan 02/10/2001
 *
 *  $Id: SerialControllerEditor.java 19641 2016-10-06 07:24:25Z markagreenwood $
 *
 */

package gate.gui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.AbstractListModel;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.ComboBoxModel;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.border.TitledBorder;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;

import gate.Controller;
import gate.Corpus;
import gate.CorpusController;
import gate.Gate;
import gate.LanguageResource;
import gate.ProcessingResource;
import gate.Resource;
import gate.VisualResource;
import gate.creole.AbstractVisualResource;
import gate.creole.AnalyserRunningStrategy;
import gate.creole.ConditionalController;
import gate.creole.ConditionalSerialAnalyserController;
import gate.creole.ExecutionException;
import gate.creole.ExecutionInterruptedException;
import gate.creole.Parameter;
import gate.creole.ResourceData;
import gate.creole.ResourceInstantiationException;
import gate.creole.RunningStrategy;
import gate.creole.RunningStrategy.UnconditionalRunningStrategy;
import gate.creole.SerialAnalyserController;
import gate.creole.SerialController;
import gate.creole.metadata.CreoleResource;
import gate.creole.metadata.GuiType;
import gate.event.ControllerEvent;
import gate.event.ControllerListener;
import gate.event.CreoleEvent;
import gate.event.CreoleListener;
import gate.event.ProgressListener;
import gate.event.StatusListener;
import gate.swing.XJPopupMenu;
import gate.swing.XJTable;
import gate.util.Benchmark;
import gate.util.Err;
import gate.util.GateException;
import gate.util.GateRuntimeException;
import gate.util.NameComparator;

@SuppressWarnings("serial")
@CreoleResource(name = "Serial Application Editor", guiType = GuiType.LARGE,
    resourceDisplayed = "gate.creole.SerialController", mainViewer = true)
public class SerialControllerEditor extends AbstractVisualResource
                               implements CreoleListener, ControllerListener,
                                          ActionsPublisher{

  public SerialControllerEditor() {

  }

  /**
   * Forces all open controller editors to refresh the list of selected PRs.
   * This should be called before any other code attempts to update a runtime
   * parameter to ensure that the PR being edited isn't selected so that changes
   * in it's parameters are correctly stored and not overwritten by subsequent
   * GUI actions
   */
  public static void clearAllSelections() {
    List controllerEditors = Gate.getCreoleRegister()
        .getVrInstances("gate.gui.SerialControllerEditor");
    if(controllerEditors != null) {
      for(Resource editor : controllerEditors) {
        ((SerialControllerEditor)editor).refreshPRLists();
      }
    }
  }

  @Override
  public void setTarget(Object target){
    if(!(target instanceof SerialController))
    throw new IllegalArgumentException(
      "gate.gui.ApplicationViewer can only be used for serial controllers\n" +
      target.getClass().toString() +
      " is not a gate.creole.SerialController!");
    if(controller != null) controller.removeControllerListener(this);
    this.controller = (SerialController)target;
    controller.addControllerListener(this);
    corpusControllerMode = controller instanceof CorpusController;
    analyserMode = controller instanceof SerialAnalyserController ||
                   controller instanceof ConditionalSerialAnalyserController;
    conditionalMode = controller instanceof ConditionalController;
    
    initLocalData();
    initGuiComponents();
    initListeners();

    loadedPRsTableModel.fireTableDataChanged();
    memberPRsTableModel.fireTableDataChanged();

  }//setController


  @Override
  public void setHandle(Handle handle) {
    this.handle = handle;

    //register the listeners
    addStatusListener(handle);
    addProgressListener(handle);
  }

  @Override
  public Resource init() throws ResourceInstantiationException{
    super.init();
    return this;
  }

  protected void initLocalData() {
    actionList = new ArrayList();
    runAction = new RunAction();
    //add the items to the popup
    actionList.add(null);
    actionList.add(runAction);
    addPRAction = new AddPRAction();
    removePRAction = new RemovePRAction();
  }

  @SuppressWarnings({"unchecked", "rawtypes"})
  protected void initGuiComponents() {
    //we use a JSplitPane for most of the content, and add the Run button to 
    //the South area
    setLayout(new BorderLayout());

    JPanel topSplit = new JPanel();
    topSplit.setLayout(new GridBagLayout());
    GridBagConstraints constraints = new GridBagConstraints();
    constraints.fill = GridBagConstraints.BOTH;
    constraints.gridy = 0;
    

    loadedPRsTableModel = new LoadedPRsTableModel();
    loadedPRsTable = new XJTable();
    loadedPRsTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
    loadedPRsTable.setSortable(false);
    loadedPRsTable.setModel(loadedPRsTableModel);
    loadedPRsTable.setDragEnabled(true);
    loadedPRsTable.setDefaultRenderer(ProcessingResource.class,
                                      new ResourceRenderer());
    //create a renderer that doesn't mind being extended horizontally.
    loadedPRsTable.setDefaultRenderer(String.class, 
            new DefaultTableCellRenderer(){
      @Override
      public Dimension getMaximumSize() {
        //we don't mind being extended horizontally
        Dimension dim = super.getMaximumSize();
        if(dim != null){
          dim.width = Integer.MAX_VALUE;
          setMaximumSize(dim);
        }
        return dim;
      }
      @Override
      public Dimension getMinimumSize() {
        //we don't like being squashed!
        return getPreferredSize();
      }
    });

    final int width1 = new JLabel("Loaded Processing resources").
                getPreferredSize().width + 30;
    JScrollPane scroller = new JScrollPane(){
      @Override
      public Dimension getPreferredSize(){
        Dimension dim = super.getPreferredSize();
        dim.width = Math.max(dim.width, width1);
        return dim;
      }
      @Override
      public Dimension getMinimumSize(){
        Dimension dim = super.getMinimumSize();
        dim.width = Math.max(dim.width, width1);
        return dim;
      }
    };
    scroller.getViewport().setView(loadedPRsTable);
    scroller.setBorder(BorderFactory.
                       createTitledBorder(BorderFactory.createEtchedBorder(),
                                          " Loaded Processing resources "));

    //adding a scrollable table
    constraints.weightx = 1;
    constraints.weighty = 1;
    constraints.insets = new Insets(0,0,0,5);
    topSplit.add(scroller, constraints);

    
    addButton = new JButton(addPRAction);
    addButton.setText("");
    addButton.setEnabled(false);
    removeButton = new JButton(removePRAction);
    removeButton.setText("");
    removeButton.setEnabled(false);

    Box buttonsBox =Box.createVerticalBox();
    buttonsBox.add(Box.createVerticalGlue());
    buttonsBox.add(addButton);
    buttonsBox.add(Box.createVerticalStrut(5));
    buttonsBox.add(removeButton);
    buttonsBox.add(Box.createVerticalGlue());

    constraints.weightx = 0;
    constraints.weighty = 0;
    constraints.insets = new Insets(0,0,0,5);
    topSplit.add(buttonsBox, constraints);

    memberPRsTableModel = new MemberPRsTableModel();
    memberPRsTable = new XJTable();
    memberPRsTable.setSortable(false);
    memberPRsTable.setModel(memberPRsTableModel);
    memberPRsTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
    memberPRsTable.setDefaultRenderer(ProcessingResource.class,
                                      new ResourceRenderer());
    memberPRsTable.setDefaultRenderer(String.class, 
            new DefaultTableCellRenderer(){
      @Override
      public Dimension getMaximumSize() {
        //we don't mind being extended horizontally
        Dimension dim = super.getMaximumSize();
        if(dim != null){
          dim.width = Integer.MAX_VALUE;
          setMaximumSize(dim);
        }
        return dim;
      }
      @Override
      public Dimension getMinimumSize() {
        //we don't like being squashed!
        return getPreferredSize();
      }
    });
    memberPRsTable.setDefaultRenderer(Icon.class, new IconRenderer());
    memberPRsTable.setDragEnabled(true);

    final int width2 = new JLabel("Selected Processing resources").
                           getPreferredSize().width + 30;
    scroller = new JScrollPane(){
      @Override
      public Dimension getPreferredSize(){
        Dimension dim = super.getPreferredSize();
        dim.width = Math.max(dim.width, width2);
        return dim;
      }
      @Override
      public Dimension getMinimumSize(){
        Dimension dim = super.getMinimumSize();
        dim.width = Math.max(dim.width, width2);
        return dim;
      }      
    };
    scroller.getViewport().setView(memberPRsTable);
    scroller.setBorder(BorderFactory.
                       createTitledBorder(BorderFactory.createEtchedBorder(),
                                          " Selected Processing resources "));

    //adding a scrollable table
    constraints.weightx = 1;
    constraints.weighty = 1;
    constraints.insets = new Insets(0,0,0,5);
    topSplit.add(scroller, constraints);

    
    moveUpButton = new JButton(MainFrame.getIcon("up"));
    moveUpButton.setMnemonic(KeyEvent.VK_UP);
    moveUpButton.setToolTipText("Move the selected resources up.");
    moveUpButton.setEnabled(false);
    moveDownButton = new JButton(MainFrame.getIcon("down"));
    moveDownButton.setMnemonic(KeyEvent.VK_DOWN);
    moveDownButton.setToolTipText("Move the selected resources down.");
    moveDownButton.setEnabled(false);

    buttonsBox =Box.createVerticalBox();
    buttonsBox.add(Box.createVerticalGlue());
    buttonsBox.add(moveUpButton);
    buttonsBox.add(Box.createVerticalStrut(5));
    buttonsBox.add(moveDownButton);
    buttonsBox.add(Box.createVerticalGlue());

    //adding a scrollable table
    constraints.weightx = 0;
    constraints.weighty = 0;
    constraints.insets = new Insets(0,0,0,0);
    topSplit.add(buttonsBox, constraints);
    
    // =========== BOTTOM Half ===========
    JPanel bottomSplit = new JPanel();
    bottomSplit.setLayout(new GridBagLayout());
    
    //first row
    constraints.gridy = 0;
    
    if(conditionalMode){
      strategyPanel = new JPanel();
      strategyPanel.setLayout(new BoxLayout(strategyPanel, BoxLayout.X_AXIS));
      strategyPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
      runBtnGrp = new ButtonGroup();
      yes_RunRBtn = new JRadioButton("Yes", true);
      yes_RunRBtn.setHorizontalTextPosition(AbstractButton.LEFT);
      runBtnGrp.add(yes_RunRBtn);
      no_RunRBtn = new JRadioButton("No", false);
      no_RunRBtn.setHorizontalTextPosition(AbstractButton.LEFT);
      runBtnGrp.add(no_RunRBtn);
      conditional_RunRBtn = new JRadioButton("If value of feature", false);
      conditional_RunRBtn.setHorizontalTextPosition(AbstractButton.LEFT);
      runBtnGrp.add(conditional_RunRBtn);

      featureNameTextField = new JTextField("", 25);
      featureNameTextField.setMaximumSize(
                           new Dimension(Integer.MAX_VALUE,
                                         featureNameTextField.getPreferredSize().
                                         height));
      
      featureValueTextField = new JTextField("", 25);
      featureValueTextField.setMaximumSize(
                           new Dimension(Integer.MAX_VALUE,
                                         featureValueTextField.getPreferredSize().
                                         height));
      
      strategyPanel.add(new JLabel(MainFrame.getIcon("greenBall")));
      strategyPanel.add(yes_RunRBtn);
      strategyPanel.add(Box.createHorizontalStrut(5));

      strategyPanel.add(new JLabel(MainFrame.getIcon("redBall")));
      strategyPanel.add(no_RunRBtn);
      strategyPanel.add(Box.createHorizontalStrut(5));

      strategyPanel.add(new JLabel(MainFrame.getIcon("yellowBall")));
      strategyPanel.add(conditional_RunRBtn);
      strategyPanel.add(Box.createHorizontalStrut(5));

      strategyPanel.add(featureNameTextField);
      strategyPanel.add(Box.createHorizontalStrut(5));
      strategyPanel.add(new JLabel("is"));
      strategyPanel.add(Box.createHorizontalStrut(5));
      strategyPanel.add(featureValueTextField);
      strategyPanel.add(Box.createHorizontalStrut(5));
      strategyBorder = BorderFactory.createTitledBorder(
          BorderFactory.createEtchedBorder(),
          " No processing resource selected... ");
      strategyPanel.setBorder(strategyBorder);


      constraints.weightx = 1;
      constraints.weighty = 0;
      constraints.insets = new Insets(0,0,0,0);
      bottomSplit.add(strategyPanel, constraints);
      constraints.gridy++;
    }//if conditional mode    
    
    if(corpusControllerMode){
      //we need to add the corpus combo
      corpusCombo = new JComboBox(corpusComboModel = new CorporaComboModel());
      corpusCombo.setRenderer(new ResourceRenderer());
      corpusCombo.setMaximumSize(new Dimension(Integer.MAX_VALUE,
                                               corpusCombo.getPreferredSize().
                                               height));
      Corpus corpus = null;
      if(controller instanceof CorpusController){
        corpus = ((CorpusController)controller).getCorpus();
      }else{
        throw new GateRuntimeException("Controller editor in corpus " +
                                       "controller mode " +
                                       "but the target controller is not an " +
                                       "CorpusController!");
      }

      if(corpus != null){
        corpusCombo.setSelectedItem(corpus);
      }else{
        if(corpusCombo.getModel().getSize() > 1) corpusCombo.setSelectedIndex(1);
        else corpusCombo.setSelectedIndex(0);
      }
      JPanel horBox = new JPanel();
      horBox.setLayout(new BoxLayout(horBox, BoxLayout.X_AXIS));
      horBox.setAlignmentX(Component.LEFT_ALIGNMENT);
      horBox.add(new JLabel("Corpus:"));
      horBox.add(Box.createHorizontalStrut(5));
      horBox.add(corpusCombo);
      horBox.add(Box.createHorizontalStrut(5));

      constraints.weightx = 1;
      constraints.anchor = GridBagConstraints.WEST;
      constraints.fill = GridBagConstraints.BOTH;
      constraints.weighty = 0;
      constraints.insets = new Insets(0,0,0,0);
      bottomSplit.add(horBox, constraints);

      //all the following rows have one element only
      constraints.gridwidth = 1;
      constraints.gridy++;
    }//if(corpusControllerMode)    
    
    parametersPanel = new JPanel();
    parametersPanel.setLayout(new BoxLayout(parametersPanel, BoxLayout.Y_AXIS));
    parametersPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
    parametersBorder = BorderFactory.createTitledBorder(
                                      BorderFactory.createEtchedBorder(),
                                      " No selected processing resource ");
    parametersPanel.setBorder(parametersBorder);
    parametersEditor = new ResourceParametersEditor();
    parametersEditor.init(null, null);
    parametersPanel.add(new JScrollPane(parametersEditor));
//    parametersPanel.add(parametersEditor, constraints);
    
    constraints.weighty = 1;
    constraints.weightx = 1;
    constraints.anchor = GridBagConstraints.CENTER;
    constraints.fill = GridBagConstraints.BOTH;
    constraints.insets = new Insets(0,0,0,0);
    bottomSplit.add(parametersPanel, constraints);
    constraints.gridy++;

    constraints.weightx = 0;
    constraints.weighty = 0;
    constraints.fill = GridBagConstraints.NONE;
    constraints.anchor = GridBagConstraints.CENTER;
    bottomSplit.add(new JButton(runAction), constraints);

    final JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, 
            topSplit, bottomSplit);
    splitPane.addAncestorListener(new AncestorListener() {
      @Override
      public void ancestorRemoved(AncestorEvent event) {}
      @Override
      public void ancestorMoved(AncestorEvent event) {}
      /**
       * One-shot ancestor listener that places the divider location on first
       * show, and then de-registers self. 
       */
      @Override
      public void ancestorAdded(AncestorEvent event) {
        // This seems to work more reliably if queued rather than executed
        // directly.
        SwingUtilities.invokeLater(new Runnable(){
          @Override
          public void run(){
            splitPane.setDividerLocation(0.5);    
          }
        });
        splitPane.removeAncestorListener(this);
      }
    });
    
    add(splitPane, BorderLayout.CENTER);
  }// initGuiComponents()

  protected void initListeners() {
    Gate.getCreoleRegister().addCreoleListener(this);

    this.addMouseListener(new MouseAdapter() {
      @Override
      public void mousePressed(MouseEvent e) {
        processMouseEvent(e);
      }
      @Override
      public void mouseReleased(MouseEvent e) {
        processMouseEvent(e);
      }
      protected void processMouseEvent(MouseEvent e) {
        if(e.isPopupTrigger()) {
          // context menu
          if(handle != null
          && handle.getPopup() != null) {
            handle.getPopup().show(SerialControllerEditor.this,
                                   e.getX(), e.getY());
          }
        }
      }
    });

    moveUpButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        int rows[] = memberPRsTable.getSelectedRows();
        if(rows == null || rows.length == 0){
          JOptionPane.showMessageDialog(
              SerialControllerEditor.this,
              "Please select some components to be moved "+
              "from the list of used components!\n" ,
              "GATE", JOptionPane.ERROR_MESSAGE);
        } else {
          //we need to make sure the rows are sorted
          Arrays.sort(rows);
          //get the list of PRs
          for(int row : rows) {
            if(row > 0) {
              //move it up
              List strategies = null;
              if(conditionalMode) {
                strategies = new ArrayList(((ConditionalController)controller)
                        .getRunningStrategies());
                RunningStrategy straegy = strategies.remove(row);
                strategies.add(row-1, straegy); 
              }
              
              ProcessingResource value = controller.remove(row);
              controller.add(row - 1, value);
              
              if(conditionalMode) {
                ((ConditionalController)controller).setRunningStrategies(strategies);;
              }
            }
          }
//          memberPRsTableModel.fireTableDataChanged();
          //restore selection
          for(int row : rows) {
            int newRow;
            if(row > 0) newRow = row - 1;
            else newRow = row;
            memberPRsTable.addRowSelectionInterval(newRow, newRow);
          }
          memberPRsTable.requestFocusInWindow();
        }

      }
    });

    moveDownButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        int rows[] = memberPRsTable.getSelectedRows();
        if(rows == null || rows.length == 0){
          JOptionPane.showMessageDialog(
              SerialControllerEditor.this,
              "Please select some components to be moved "+
              "from the list of used components!\n" ,
              "GATE", JOptionPane.ERROR_MESSAGE);
        } else {
          //we need to make sure the rows are sorted
          Arrays.sort(rows);
          //get the list of PRs
          for(int i = rows.length - 1; i >= 0; i--){
            int row = rows[i];
            if(row < controller.getPRs().size() -1){
              
              List strategies = null;
              if(conditionalMode) {
                strategies = new ArrayList(((ConditionalController)controller)
                        .getRunningStrategies());
                RunningStrategy straegy = strategies.remove(row);
                strategies.add(row+1, straegy); 
              }
              
              //move it down
              ProcessingResource value = controller.remove(row);
              controller.add(row + 1, value);
              
              if(conditionalMode) {
                ((ConditionalController)controller).setRunningStrategies(strategies);;
              }
            }
          }
//          memberPRsTableModel.fireTableDataChanged();
          //restore selection
          for(int row : rows) {
            int newRow;
            if(row < controller.getPRs().size() - 1) newRow = row + 1;
            else newRow = row;
            memberPRsTable.addRowSelectionInterval(newRow, newRow);
          }
          memberPRsTable.requestFocusInWindow();
        }

      }
    });

    // mouse click edit the resource
    // mouse double click or context menu add the resource to the application
    loadedPRsTable.addMouseListener(new MouseAdapter() {
      @Override
      public void mousePressed(MouseEvent e) {
        if(e.isPopupTrigger()) { processMouseEvent(e); }
      }
      @Override
      public void mouseReleased(MouseEvent e) {
        if(e.isPopupTrigger()) { processMouseEvent(e); }
      }
      @Override
      public void mouseClicked(MouseEvent e) {
        processMouseEvent(e);
      }
      protected void processMouseEvent(MouseEvent e) {
        int row = loadedPRsTable.rowAtPoint(e.getPoint());
        if(row == -1) { return; }
        //ProcessingResource pr = (ProcessingResource) loadedPRsTable
        //  .getValueAt(row, loadedPRsTable.convertColumnIndexToView(0));

        if(e.isPopupTrigger()) {
          // context menu
          if(!loadedPRsTable.isRowSelected(row)) {
            // if right click outside the selection then reset selection
            loadedPRsTable.getSelectionModel().setSelectionInterval(row, row);
          }
          JPopupMenu popup = new XJPopupMenu();
          popup.add(addPRAction);
          popup.show(loadedPRsTable, e.getPoint().x, e.getPoint().y);

        } else if(e.getID() == MouseEvent.MOUSE_CLICKED) {
          if (e.getClickCount() == 2) {
            //add selected modules on double click
            addPRAction.actionPerformed(null);
          }
        }
      }
    });

    // drag and drop support
    loadedPRsTable.setTransferHandler(new TransferHandler() {
      // minimal drag and drop that only call the removePRAction when importing
      String source = "";
      @Override
      public int getSourceActions(JComponent c) {
        return MOVE;
      }
      @Override
      protected Transferable createTransferable(JComponent c) {
        return new StringSelection("loadedPRsTable");
      }
      @Override
      protected void exportDone(JComponent c, Transferable data, int action) {
      }
      @Override
      public boolean canImport(JComponent c, DataFlavor[] flavors) {
        for(DataFlavor flavor : flavors) {
          if(DataFlavor.stringFlavor.equals(flavor)) {
            return true;
          }
        }
        return false;
      }
      @Override
      public boolean importData(JComponent c, Transferable t) {
        if (canImport(c, t.getTransferDataFlavors())) {
          try {
              source = (String)t.getTransferData(DataFlavor.stringFlavor);
              if (source.startsWith("memberPRsTable")) {
                removePRAction.actionPerformed(null);
                return true;
              } else {
                return false;
              }
          } catch (UnsupportedFlavorException ufe) { // just return false later
          } catch (IOException ioe) { // just return false later
          }
        }
        return false;
      }
    });
    
    // mouse click edit the resource
    // mouse double click or context menu remove the resource from the
    // application
    memberPRsTable.addMouseListener(new MouseAdapter() {
      @Override
      public void mousePressed(MouseEvent e) {
        if(e.isPopupTrigger()) { processMouseEvent(e); }
      }
      @Override
      public void mouseReleased(MouseEvent e) {
        if(e.isPopupTrigger()) { processMouseEvent(e); }
      }
      @Override
      public void mouseClicked(MouseEvent e) {
        processMouseEvent(e);
      }
      protected void processMouseEvent(MouseEvent e) {
        int row = memberPRsTable.rowAtPoint(e.getPoint());
        if(row == -1) { return; }

        if(e.isPopupTrigger()) {
          // context menu
          if(!memberPRsTable.isRowSelected(row)) {
            // if right click outside the selection then reset selection
            memberPRsTable.getSelectionModel().setSelectionInterval(row, row);
          }
          JPopupMenu popup = new XJPopupMenu();
          popup.add(removePRAction);
          popup.show(memberPRsTable, e.getPoint().x, e.getPoint().y);

        } else if(e.getID() == MouseEvent.MOUSE_CLICKED) {
          if (e.getClickCount() == 2) {
            // open the double-clicked PR in the main view.
            Component root = SwingUtilities.getRoot(SerialControllerEditor.this);
            if (!(root instanceof MainFrame)) { return; }
            final MainFrame mainFrame = (MainFrame) root;
            if(controller != null) {
              ProcessingResource res = 
                  controller.getPRs().get(row);
              if(res != null) mainFrame.select(res);
            }
          }
        }
      }
    });

    // Drag and drop support
    memberPRsTable.setTransferHandler(new TransferHandler() {
      // minimal drag and drop that only call the addPRAction when importing
      String source = "";
      @Override
      public int getSourceActions(JComponent c) {
        return MOVE;
      }
      @Override
      protected Transferable createTransferable(JComponent c) {
        int selectedRows[] = memberPRsTable.getSelectedRows();
        Arrays.sort(selectedRows);
        return new StringSelection("memberPRsTable"
          + Arrays.toString(selectedRows));
      }
      @Override
      protected void exportDone(JComponent c, Transferable data, int action) {
      }
      @Override
      public boolean canImport(JComponent c, DataFlavor[] flavors) {
        for(DataFlavor flavor : flavors) {
          if(DataFlavor.stringFlavor.equals(flavor)) {
            return true;
          }
        }
        return false;
      }
      @Override
      public boolean importData(JComponent c, Transferable t) {
        if (!canImport(c, t.getTransferDataFlavors())) {
          return false;
        }
        try {
          source = (String)t.getTransferData(DataFlavor.stringFlavor);
          if (source.startsWith("memberPRsTable")) {
            int insertion = memberPRsTable.getSelectedRow();
            int initialInsertion = insertion;
            List prs = new ArrayList();
            source = source.replaceFirst("^memberPRsTable\\[", "");
            source = source.replaceFirst("\\]$", "");
            String selectedRows[] = source.split(", ");
            if (Integer.parseInt(selectedRows[0]) < insertion) { insertion++; }
            // get the list of PRs selected when dragging started
            for(String row : selectedRows) {
              if (Integer.parseInt(row) == initialInsertion) {
                // the user draged the selected rows on themselves, do nothing
                return false;
              }
              prs.add((ProcessingResource) memberPRsTable.getValueAt(
                Integer.parseInt(row),
                memberPRsTable.convertColumnIndexToView(1)));
              if (Integer.parseInt(row) < initialInsertion) { insertion--; }
            }
            // remove the PRs selected when dragging started
            for (ProcessingResource pr : prs) {
              controller.remove(pr);
            }
            // add the PRs at the insertion point
            for (ProcessingResource pr : prs) {
              controller.add(insertion, pr);
              insertion++;
            }
            // select the moved PRs
            memberPRsTable.addRowSelectionInterval(
              insertion - selectedRows.length, insertion - 1);
            return true;
          } else if (source.equals("loadedPRsTable")) {
            addPRAction.actionPerformed(null);
            return true;
          } else {
            return false;
          }
        } catch (UnsupportedFlavorException ufe) {
          return false;
        } catch (IOException ioe) {
          return false;
        }
      }
    });
    
    loadedPRsTable.getSelectionModel().addListSelectionListener(
      new ListSelectionListener() {
        @Override
        public void valueChanged(ListSelectionEvent e) {
          // disable Add button if no selection
          addButton.setEnabled(loadedPRsTable.getSelectedRowCount() > 0);
        }
      });

    memberPRsTable.getSelectionModel().addListSelectionListener(
      new ListSelectionListener() {
        @Override
        public void valueChanged(ListSelectionEvent e) {
          // disable Remove and Move buttons if no selection
          removeButton.setEnabled(memberPRsTable.getSelectedRowCount() > 0);
          moveUpButton.setEnabled(memberPRsTable.getSelectedRowCount() > 0
            && !memberPRsTable.isRowSelected(0));
          moveDownButton.setEnabled(memberPRsTable.getSelectedRowCount() > 0
            && !memberPRsTable.isRowSelected(memberPRsTable.getRowCount() - 1));
          //update the parameters & strategy editors
          if(memberPRsTable.getSelectedRowCount() == 1){
            //only one selection
            selectPR(memberPRsTable.getSelectedRow());
          }else{
            //clean up UI
            selectPR(-1);
          }
        }
      });

    if(conditionalMode){
      /**
       * A listener called when the selection state changes for any of the
       * execution mode radio buttons. We use selection changes rather than 
       * action listeners, as the change of state may not be as results of an 
       * action (e.g. editing one of the text fields, changes the selection). 
       */
      ItemListener strategyModeListener = new ItemListener() {
        @Override
        public void itemStateChanged(ItemEvent e) {
          if(selectedPRRunStrategy != null) {
            if(selectedPRRunStrategy instanceof AnalyserRunningStrategy){
              AnalyserRunningStrategy strategy =
                (AnalyserRunningStrategy)selectedPRRunStrategy;
              if(yes_RunRBtn.isSelected()){
                strategy.setRunMode(RunningStrategy.RUN_ALWAYS);
              }else if(no_RunRBtn.isSelected()){
                strategy.setRunMode(RunningStrategy.RUN_NEVER);
              }else if(conditional_RunRBtn.isSelected()){
                strategy.setRunMode(RunningStrategy.RUN_CONDITIONAL);
              }
            } else if(selectedPRRunStrategy instanceof UnconditionalRunningStrategy) {
              UnconditionalRunningStrategy strategy =
                (UnconditionalRunningStrategy)selectedPRRunStrategy;
              if(yes_RunRBtn.isSelected()){
                strategy.shouldRun(true);
              }else if(no_RunRBtn.isSelected()){
                strategy.shouldRun(false);
              }
            }
          }
          //some icons may have changed!
          memberPRsTable.repaint();
        }
      };
      
      yes_RunRBtn.addItemListener(strategyModeListener);
      no_RunRBtn.addItemListener(strategyModeListener);
      conditional_RunRBtn.addItemListener(strategyModeListener);
      
      
      featureNameTextField.getDocument().addDocumentListener(
      new javax.swing.event.DocumentListener() {
        @Override
        public void insertUpdate(javax.swing.event.DocumentEvent e) {
          changeOccured(e);
        }

        @Override
        public void removeUpdate(javax.swing.event.DocumentEvent e) {
          changeOccured(e);
        }

        @Override
        public void changedUpdate(javax.swing.event.DocumentEvent e) {
          changeOccured(e);
        }

        protected void changeOccured(javax.swing.event.DocumentEvent e){
          if(selectedPRRunStrategy != null &&
             selectedPRRunStrategy instanceof AnalyserRunningStrategy){
            AnalyserRunningStrategy strategy =
              (AnalyserRunningStrategy)selectedPRRunStrategy;
            strategy.setFeatureName(featureNameTextField.getText());
          }
          //editing the textfield changes the running strategy to conditional
          conditional_RunRBtn.setSelected(true);
        }
      });

      featureValueTextField.getDocument().addDocumentListener(
      new javax.swing.event.DocumentListener() {
        @Override
        public void insertUpdate(javax.swing.event.DocumentEvent e) {
          changeOccured(e);
        }

        @Override
        public void removeUpdate(javax.swing.event.DocumentEvent e) {
          changeOccured(e);
        }

        @Override
        public void changedUpdate(javax.swing.event.DocumentEvent e) {
          changeOccured(e);
        }

        protected void changeOccured(javax.swing.event.DocumentEvent e){
          if(selectedPRRunStrategy != null &&
             selectedPRRunStrategy instanceof AnalyserRunningStrategy){
            AnalyserRunningStrategy strategy =
              (AnalyserRunningStrategy)selectedPRRunStrategy;
            strategy.setFeatureValue(featureValueTextField.getText());
          }
          //editing the textfield changes the running strategy to conditional
          conditional_RunRBtn.setSelected(true);
        }
      });
    }//if conditional
    
    if(corpusControllerMode){
      corpusCombo.addPopupMenuListener(new PopupMenuListener() {
        @Override
        public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
          corpusComboModel.fireDataChanged();
        }

        @Override
        public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
        }

        @Override
        public void popupMenuCanceled(PopupMenuEvent e) {
        }
      });
    }

    addAncestorListener(new AncestorListener() {
      @Override
      public void ancestorAdded(AncestorEvent event) {
        // every time the user switches back to this view, we check
        // whether another controller has just included this one
        loadedPRsTableModel.fireTableDataChanged();
        memberPRsTableModel.fireTableDataChanged();
      }
      @Override
      public void ancestorRemoved(AncestorEvent event) { /* do nothing */ }
      @Override
      public void ancestorMoved(AncestorEvent event) { /* do nothing */
      }
    }
    );

    // binds F3 key to the run action
    getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
      .put(KeyStroke.getKeyStroke("F3"), "Run");
    getActionMap().put("Run", runAction);
  
  }//protected void initListeners()
  
  @Override
  public List getActions(){
    return actionList;
  }

  /**
   * Cleans the internal data and prepares this object to be collected
   */
  @Override
  public void cleanup(){
    Gate.getCreoleRegister().removeCreoleListener(this);
    controller.removeControllerListener(this);
    controller = null;
    progressListeners.clear();
    statusListeners.clear();
    parametersEditor.cleanup();
    handle = null;
  }

  /**
   * Called when a PR has been selected in the member PRs table;
   * @param index row index in {@link #memberPRsTable} (or -1 if no PR is
   * currently selected)
   */
  protected void selectPR(int index){
    //stop current editing of parameters
    if(parametersEditor.getResource() != null){
      try{
        parametersEditor.setParameters();
      }catch(ResourceInstantiationException rie){
        JOptionPane.showMessageDialog(
            SerialControllerEditor.this,
            "Failed to set parameters for \"" + 
            parametersEditor.getResource().getName() +"\"!\n" ,
            "GATE", JOptionPane.ERROR_MESSAGE);
        rie.printStackTrace(Err.getPrintWriter());
      }
      
      if(conditionalMode){
        if(selectedPRRunStrategy != null &&
                selectedPRRunStrategy instanceof AnalyserRunningStrategy){
               AnalyserRunningStrategy strategy =
                 (AnalyserRunningStrategy)selectedPRRunStrategy;
               strategy.setFeatureName(featureNameTextField.getText());
               strategy.setFeatureValue(featureValueTextField.getText());
        }
        selectedPRRunStrategy = null;
      }
    }
    //find the new PR 
    ProcessingResource pr = null;
    if(index >= 0 && index < controller.getPRs().size()){
      pr = controller.getPRs().get(index);
    }
    if(pr != null){
      //update the GUI for the new PR
      ResourceData rData = Gate.getCreoleRegister().
                                         get(pr.getClass().getName());
      //update the border name
      parametersBorder.setTitle(" Runtime Parameters for the \"" + pr.getName() +
                                "\" " + rData.getName() + ": ");
      //update the params editor
      //this is a list of lists
      List> parameters = 
          rData.getParameterList().getRuntimeParameters();
      if(corpusControllerMode){
        //remove corpus and document
        //create a new list so we don't change the one from CreoleReg.
        List> oldParameters = parameters;
        parameters = new ArrayList>();
        for(List aDisjunction : oldParameters) {
          List newDisjunction = new ArrayList();
          for(Parameter parameter : aDisjunction) {
            if(!parameter.getName().equals("corpus")
            && !parameter.getName().equals("document")) {
              newDisjunction.add(parameter);
            }
          }
          if(!newDisjunction.isEmpty()) parameters.add(newDisjunction);
        }
      }
      parametersEditor.init(pr, parameters);
      
      if(conditionalMode){
        strategyBorder.setTitle(" Run \"" + pr.getName() + "\"? ");
        //update the state of the run strategy buttons
        yes_RunRBtn.setEnabled(true);
        no_RunRBtn.setEnabled(true);
        conditional_RunRBtn.setEnabled(true);
        
        //editing the strategy panel causes the edits to be sent to the current
        //strategy object, which can lead to a race condition. 
        //So we used a cached value instead.
        selectedPRRunStrategy = null;
        RunningStrategy newStrategy = ((ConditionalController)controller).
                                            getRunningStrategies().get(index);
        if(newStrategy instanceof AnalyserRunningStrategy){
          featureNameTextField.setEnabled(true);
          featureValueTextField.setEnabled(true);
          conditional_RunRBtn.setEnabled(true);
          featureNameTextField.setText(
                ((AnalyserRunningStrategy)newStrategy).
                getFeatureName());
          featureValueTextField.setText(
                ((AnalyserRunningStrategy)newStrategy).
                getFeatureValue());
        }
        else {
          featureNameTextField.setEnabled(false);
          featureValueTextField.setEnabled(false);
          conditional_RunRBtn.setEnabled(false);
        }
        switch(newStrategy.getRunMode()){
          case RunningStrategy.RUN_ALWAYS:{
            yes_RunRBtn.setSelected(true);
            break;
          }
          case RunningStrategy.RUN_NEVER:{
            no_RunRBtn.setSelected(true);
            break;
          }
          case RunningStrategy.RUN_CONDITIONAL:{
            conditional_RunRBtn.setSelected(true);
            break;
          }
        }//switch
        //now that the UI is updated, we can safely link to the new strategy
        selectedPRRunStrategy = newStrategy;
      }
    }else{
      //selected PR == null -> clean all mentions of the old PR from the GUI
      parametersBorder.setTitle(" No processing resource selected... ");
      parametersEditor.init(null, null);
      if(conditionalMode){
        strategyBorder.setTitle(" No processing resource selected... ");
        yes_RunRBtn.setEnabled(false);
        no_RunRBtn.setEnabled(false);
        conditional_RunRBtn.setEnabled(false);
        featureNameTextField.setText("");
        featureNameTextField.setEnabled(false);
        featureValueTextField.setText("");
        featureValueTextField.setEnabled(false);
      }
    }
    //this seems to be needed to show the changes
    SerialControllerEditor.this.repaint(100);
  }

  /*
   * Utility method to refresh the PR lists on the EDT but making sure
   * that if we are on the EDT we don't wait we do it right now
   */
  private void refreshPRLists() {
    if(SwingUtilities.isEventDispatchThread()) {
      loadedPRsTableModel.fireTableDataChanged();
      memberPRsTableModel.fireTableDataChanged();
    } else {
      SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
          loadedPRsTableModel.fireTableDataChanged();
          memberPRsTableModel.fireTableDataChanged();
        }
      });
    }
  }

  //CreoleListener implementation
  @Override
  public void resourceLoaded(CreoleEvent e) {
    if(Gate.getHiddenAttribute(e.getResource().getFeatures())) return;
    if(e.getResource() instanceof ProcessingResource){
      refreshPRLists();
//      repaint(100);
    }else if(e.getResource() instanceof LanguageResource){
      if(e.getResource() instanceof Corpus && corpusControllerMode){
        corpusComboModel.fireDataChanged();
      }
    }
  }

  @Override
  public void resourceUnloaded(CreoleEvent e) {
    if(Gate.getHiddenAttribute(e.getResource().getFeatures())) return;
    if(e.getResource() instanceof ProcessingResource){
      ProcessingResource pr = (ProcessingResource)e.getResource();
      if(controller != null && controller.getPRs().contains(pr)){
        controller.remove(pr);
      }
      refreshPRLists();
    }
    else if(e.getResource() instanceof LanguageResource) {
      if(e.getResource() instanceof Corpus && corpusControllerMode) {
        Corpus c = (Corpus)e.getResource();
        if(controller instanceof CorpusController) {
          if(c == ((CorpusController)controller).getCorpus()) {
            // setCorpus(null) is also called in the controller's
            // resourceUnloaded(), but we can't be sure which handler is
            // called first...
            ((CorpusController)controller).setCorpus(null);
          }
        }
        else {
          throw new GateRuntimeException("Controller editor in analyser mode " +
                                         "but the target controller is not an " +
                                         "analyser!");
        }
        corpusComboModel.fireDataChanged();
      }
    }
  }

  @Override
  public void resourceRenamed(Resource resource, String oldName,
                              String newName){
    if(Gate.getHiddenAttribute(resource.getFeatures())) return;
    if(resource instanceof ProcessingResource){
      repaint(100);
    }
  }

  @Override
  public void datastoreOpened(CreoleEvent e) {
  }
  @Override
  public void datastoreCreated(CreoleEvent e) {
  }
  @Override
  public void datastoreClosed(CreoleEvent e) {
  }
  public synchronized void removeStatusListener(StatusListener l) {
    if (statusListeners != null && statusListeners.contains(l)) {
      @SuppressWarnings("unchecked")
      Vector v = (Vector) statusListeners.clone();
      v.removeElement(l);
      statusListeners = v;
    }
  }
  
  /* (non-Javadoc)
   * @see gate.event.ControllerListener#resourceAdded(gate.event.ControllerEvent)
   */
  @Override
  public void resourceAdded(ControllerEvent evt){
    refreshPRLists();    
  }
  
  /* (non-Javadoc)
   * @see gate.event.ControllerListener#resourceRemoved(gate.event.ControllerEvent)
   */
  @Override
  public void resourceRemoved(ControllerEvent evt){
    refreshPRLists();
  }

  public synchronized void addStatusListener(StatusListener l) {
    @SuppressWarnings("unchecked")
    Vector v = statusListeners == null ?
      new Vector(2) : (Vector) statusListeners.clone();
    if (!v.contains(l)) {
      v.addElement(l);
      statusListeners = v;
    }
  }

  private boolean firstIncludesOrEqualsSecond(Controller first,
                                              Controller second) {
    if (first.equals(second)) {
      return true;
    } else {
      for (Object object : first.getPRs()) {
        if (object instanceof Controller) {
          if (firstIncludesOrEqualsSecond((Controller)object, second)) {
            return true;
          }
        }
      }
    }
    return false;
  }

  /**
   * Table model for all the loaded processing resources that are not part of
   * the controller.
   */
  class LoadedPRsTableModel extends AbstractTableModel{
    @Override
    public int getRowCount(){
      List loadedPRs = new ArrayList(
        Gate.getCreoleRegister().getPrInstances());
      if(controller != null) {
        loadedPRs.removeAll(controller.getPRs());
      }
      Iterator prsIter = loadedPRs.iterator();
      while(prsIter.hasNext()){
        ProcessingResource aPR = prsIter.next();
        if(Gate.getHiddenAttribute(aPR.getFeatures())
       || ( aPR instanceof Controller
         && firstIncludesOrEqualsSecond((Controller)aPR, controller)) ) {
          prsIter.remove();
        }
      }

      return loadedPRs.size();
    }

    @Override
    public Object getValueAt(int row, int column){
      List loadedPRs = new ArrayList(
        Gate.getCreoleRegister().getPrInstances());
      if(controller != null) {
        loadedPRs.removeAll(controller.getPRs());
      }
      Iterator prsIter = loadedPRs.iterator();
      while(prsIter.hasNext()){
        ProcessingResource aPR = prsIter.next();
        if(Gate.getHiddenAttribute(aPR.getFeatures())
       || ( aPR instanceof Controller
         && firstIncludesOrEqualsSecond((Controller)aPR, controller)) ) {
          prsIter.remove();
        }
      }

      Collections.sort(loadedPRs, nameComparator);
      ProcessingResource pr = loadedPRs.get(row);
      switch(column){
        case 0 : return pr;
        case 1 : {
          ResourceData rData = Gate.getCreoleRegister()
            .get(pr.getClass().getName());
          if(rData == null) return pr.getClass();
          else return rData.getName();
        }
        default: return null;
      }
    }

    @Override
    public int getColumnCount(){
      return 2;
    }

    @Override
    public String getColumnName(int columnIndex){
      switch(columnIndex){
        case 0 : return "Name";
        case 1 : return "Type";
        default: return "?";
      }
    }

    @Override
    public Class getColumnClass(int columnIndex){
      switch(columnIndex){
        case 0 : return ProcessingResource.class;
        case 1 : return String.class;
        default: return Object.class;
      }
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex){
      return false;
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex){
    }
    NameComparator nameComparator = new NameComparator();
  }//protected class LoadedPRsTableModel extends AbstractTableModel

  /**
   * A model for a combobox containing the loaded corpora in the system
   */
  @SuppressWarnings("rawtypes")
  protected class CorporaComboModel extends AbstractListModel
                                  implements ComboBoxModel{
    @Override
    public int getSize(){
      //get all corpora regardless of their actual type
      List loadedCorpora = null;
      try{
        loadedCorpora = Gate.getCreoleRegister().
                               getAllInstances("gate.Corpus");
      }catch(GateException ge){
        ge.printStackTrace(Err.getPrintWriter());
      }

      return loadedCorpora == null ? 1 : loadedCorpora.size() + 1;
    }

    @Override
    public Object getElementAt(int index){
      if(index == 0) return "";
      else{
        //get all corpora regardless of their actual type
        List loadedCorpora = null;
        try{
          loadedCorpora = Gate.getCreoleRegister().
                                 getAllInstances("gate.Corpus");
        }catch(GateException ge){
          ge.printStackTrace(Err.getPrintWriter());
        }
        return loadedCorpora == null ||
          index > loadedCorpora.size() ? "" : loadedCorpora.get(index - 1);
      }
    }

    //use the controller for data caching
    @Override
    public void setSelectedItem(Object anItem){
      if(controller instanceof CorpusController)
      ((CorpusController)controller).
        setCorpus((Corpus)(anItem.equals("") ? null : anItem));
    }

    @Override
    public Object getSelectedItem(){
      Corpus corpus = null;
      if(controller instanceof CorpusController) {
        corpus = ((CorpusController)controller).getCorpus();
      }else{
        throw new GateRuntimeException("Controller editor in corpus " +
                                       "controller mode " +
                                       "but the target controller is not a " +
                                       "CorpusController!");
      }
      return (corpus == null ? (Object)"" : (Object)corpus);
    }

    void fireDataChanged(){
      SwingUtilities.invokeLater(new Runnable() {
        
        @Override
        public void run() {
          fireContentsChanged(this, 0, getSize());    
        }
      });
      
    }
  }

  /**
   *  Renders JLabel by simply displaying them
   */
  class IconRenderer extends DefaultTableCellRenderer{
    
    @Override
    public Component getTableCellRendererComponent(JTable table,
                                                   Object value,
                                                   boolean isSelected,
                                                   boolean hasFocus,
                                                   int row,
                                                   int column){
      super.getTableCellRendererComponent(table, "", isSelected, hasFocus, 
              row, column);
      setIcon((Icon)value);
      return this;
    }

    @Override
    public Dimension getMaximumSize() {
      return getPreferredSize();
    }

    @Override
    public Dimension getMinimumSize() {
      return getPreferredSize();
    }
    
  }

  /**
   * Table model for all the processing resources in the controller.
   */
  class MemberPRsTableModel extends AbstractTableModel{
    public MemberPRsTableModel(){
      green = MainFrame.getIcon("greenBall");
      red = MainFrame.getIcon("redBall");
      yellow = MainFrame.getIcon("yellowBall");
    }
    
    @Override
    public int getRowCount(){
      return controller == null ? 0 : controller.getPRs().size();
    }

    @Override
    public Object getValueAt(int row, int column){
      ProcessingResource pr = controller.getPRs().get(row);
      switch(column){
        case 0 : {
          if(conditionalMode){
            RunningStrategy strategy = 
                                 ((ConditionalController)controller).
                                          getRunningStrategies().get(row);
            switch(strategy.getRunMode()){
              case RunningStrategy.RUN_ALWAYS : return green;
              case RunningStrategy.RUN_NEVER : return red;
              case RunningStrategy.RUN_CONDITIONAL : return yellow;
            }
          }
          return green;
        }
        case 1 : return pr;
        case 2 : {
          ResourceData rData = Gate.getCreoleRegister().
                                    get(pr.getClass().getName());
          if(rData == null) return pr.getClass();
          else return rData.getName();
        }
        default: return null;
      }
    }

    @Override
    public int getColumnCount(){
      return 3;
    }

    @Override
    public String getColumnName(int columnIndex){
      switch(columnIndex){
        case 0 : return "!";
        case 1 : return "Name";
//        case 1 : return "!";
        case 2 : return "Type";
        default: return "?";
      }
    }

    @Override
    public Class getColumnClass(int columnIndex){
      switch(columnIndex){
        case 0 : return Icon.class;
        case 1 : return ProcessingResource.class;
//        case 1 : return Boolean.class;
        case 2 : return String.class;
        default: return Object.class;
      }
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex){
      return false;
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex){
    }

    protected Icon green, red, yellow;
  }//protected class MemberPRsTableModel extends AbstractTableModel

  /** Adds a PR to the controller*/
  class AddPRAction extends AbstractAction {
    AddPRAction(){
      putValue(NAME, "Add selected resources to the application");
      putValue(SHORT_DESCRIPTION, "Add selected resources to the application");
      putValue(SMALL_ICON, MainFrame.getIcon("right-arrow"));
      putValue(MNEMONIC_KEY, KeyEvent.VK_RIGHT);
    }

    @Override
    public void actionPerformed(ActionEvent e){
      try {
        List prs = new ArrayList();
        int selectedRows[] = loadedPRsTable.getSelectedRows();
        Arrays.sort(selectedRows);
        for (int row : selectedRows) {
          prs.add((ProcessingResource) loadedPRsTable
            .getValueAt(row, loadedPRsTable.convertColumnIndexToView(0)));
        }
        //insert the new PRs after the last currently selected row.
        selectedRows = memberPRsTable.getSelectedRows();
        Arrays.sort(selectedRows);
        int insertion = selectedRows.length == 0 ?
                memberPRsTable.getRowCount() :
                selectedRows[selectedRows.length -1] +1;
        for (ProcessingResource pr : prs) {
          controller.add(insertion, pr);
          insertion++;
        }      
        //select the newly added PRs
        for (ProcessingResource pr : prs) {
          for (int row = 0; row < memberPRsTable.getRowCount(); row++) {
            if (memberPRsTable.getValueAt(row,
                  memberPRsTable.convertColumnIndexToView(1)) == pr) {
              memberPRsTable.addRowSelectionInterval(row, row);
            }
          }
        }
        memberPRsTable.requestFocusInWindow();
      }
      catch(GateRuntimeException ex) {
        JOptionPane.showMessageDialog(SerialControllerEditor.this,
              "Could not add PR to pipeline:\n"
              +ex.getMessage(),
              "GATE", JOptionPane.ERROR_MESSAGE);
            return;
      }
    }
  }

  /** Removes a PR from the controller*/
  class RemovePRAction extends AbstractAction {
    RemovePRAction(){
      putValue(NAME, "Remove selected resouces from the application");
      putValue(SHORT_DESCRIPTION,
        "Remove selected resouces from the application");
      putValue(SMALL_ICON, MainFrame.getIcon("left-arrow"));
      putValue(MNEMONIC_KEY, KeyEvent.VK_LEFT);
    }

    @Override
    public void actionPerformed(ActionEvent e){
      List prs = new ArrayList();
      for (int row : memberPRsTable.getSelectedRows()) {
        prs.add((ProcessingResource) memberPRsTable
          .getValueAt(row, memberPRsTable.convertColumnIndexToView(1)));
      }
      for (ProcessingResource pr : prs) {
        controller.remove(pr);
      }
      // transfer the selection
      for (ProcessingResource pr : prs) {
        for (int row = 0; row < loadedPRsTable.getRowCount(); row++) {
          if (loadedPRsTable.getValueAt(row,
                loadedPRsTable.convertColumnIndexToView(0)) == pr) {
            loadedPRsTable.addRowSelectionInterval(row, row);
          }
        }
      }
      loadedPRsTable.requestFocusInWindow();
      if (memberPRsTable.getSelectedRowCount() == 0) {
        parametersEditor.init(null, null);
        parametersBorder.setTitle("No selected processing resource");
      }
    }
  }


  /** Runs the Application*/
  class RunAction extends AbstractAction {
    RunAction(){
      super("Run this Application");
      super.putValue(SHORT_DESCRIPTION, "Run this application"
      +"  F3"
      +"  ");
    }

    @Override
    public void actionPerformed(ActionEvent e){

      if (memberPRsTable.getRowCount() == 0) {
        JOptionPane.showMessageDialog(SerialControllerEditor.this,
          "Add at least one processing resource in the right table\n"
          +"that contains the resources of the application to be run.",
          "GATE", JOptionPane.ERROR_MESSAGE);
        return;
      }

      //stop editing the parameters
      try{
        parametersEditor.setParameters();
      }catch(ResourceInstantiationException rie){
        JOptionPane.showMessageDialog(
          SerialControllerEditor.this,
          "Could not set parameters for the \"" +
          parametersEditor.getResource().getName() +
          "\" processing resource:\nSee \"Messages\" tab for details!",
          "GATE", JOptionPane.ERROR_MESSAGE);
          rie.printStackTrace(Err.getPrintWriter());
          return;
      }
      
      Runnable runnable = new Runnable(){
        @Override
        public void run(){

          if(corpusControllerMode){
            //set the corpus
            Object value = corpusCombo.getSelectedItem();
            Corpus corpus = value.equals("") ? null : (Corpus)value;
            if(analyserMode && corpus == null){
              
              SwingUtilities.invokeLater(new Runnable(){
                @Override
                public void run() {
                  JOptionPane.showMessageDialog(
                          SerialControllerEditor.this,
                          "No corpus provided!\n" +
                          "Please select a corpus and try again!",
                          "GATE", JOptionPane.ERROR_MESSAGE);
                        corpusCombo.requestFocusInWindow();
                }                
              });
              return;
            }
            if(controller instanceof CorpusController)
              ((CorpusController)controller).setCorpus(corpus);
          }
          //check the runtime parameters
          List badPRs;
          try{
            badPRs = controller.getOffendingPocessingResources();
          }catch(ResourceInstantiationException rie){
            JOptionPane.showMessageDialog(
              SerialControllerEditor.this,
              "Could not check runtime parameters for " +
              "the processing resources:\n" + rie.toString(),
              "GATE", JOptionPane.ERROR_MESSAGE);
            return;
          }
          if(badPRs != null && !badPRs.isEmpty()){
            String badPRsString = "";
            for (Object badPR : badPRs) {
              badPRsString += "- "
                + ((ProcessingResource) badPR).getName() + "\n";
            }
            //we know what PRs have problems so it would be nice to show
            //them in red or something
            JOptionPane.showMessageDialog(
              SerialControllerEditor.this,
              "Some required runtime parameters are not set\n"+
              "in the following resources:\n"+
              badPRsString,
              "GATE", JOptionPane.ERROR_MESSAGE);
            return;
          }

          //set the listeners
          StatusListener sListener = new InternalStatusListener();
          ProgressListener pListener = new InternalProgressListener();

          controller.addStatusListener(sListener);
          controller.addProgressListener(pListener);

          Gate.setExecutable(controller);

          int corpusSize = 1;
          if (controller instanceof CorpusController) {
            Corpus corpus = ((CorpusController) controller).getCorpus();
            if(corpus != null) {
              corpusSize = corpus.size();
            }
          }
          MainFrame.lockGUI("Running " + controller.getName() + " on "
            + corpusSize + (corpusSize == 1 ? " document" : " documents"));
          //execute the thing
          long startTime = System.currentTimeMillis();
          fireStatusChanged("Start running " + controller.getName() + " on "
            + corpusSize + (corpusSize == 1 ? " document" : " documents"));
          fireProgressChanged(0);

          try {
            Benchmark.executeWithBenchmarking(controller,
                    Benchmark.createBenchmarkId(controller.getName(), null),
                    RunAction.this, null);
          }catch(final ExecutionInterruptedException eie){
            MainFrame.unlockGUI();
            SwingUtilities.invokeLater(new Runnable() {
              @Override
              public void run() {
                JOptionPane.showMessageDialog(
                    SerialControllerEditor.this,
                    "Interrupted!\n" + eie.toString(),
                    "GATE", JOptionPane.ERROR_MESSAGE);
              }
            });
          }catch(final ExecutionException ee) {
            ee.printStackTrace(Err.getPrintWriter());
            MainFrame.unlockGUI();
            SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {  
              JOptionPane.showMessageDialog(
                  SerialControllerEditor.this,
                  "Execution error while running \"" + controller.getName() +
                  "\" :\nSee \"Messages\" tab for details!",
                  "GATE", JOptionPane.ERROR_MESSAGE);
              }
            });
          }catch(final Exception e){
            e.printStackTrace(Err.getPrintWriter());
            MainFrame.unlockGUI();
            SwingUtilities.invokeLater(new Runnable() {
              @Override
              public void run() {
                JOptionPane.showMessageDialog(SerialControllerEditor.this,
                    "Unhandled execution error!\n " +
                        "See \"Messages\" tab for details!",
                        "GATE", JOptionPane.ERROR_MESSAGE);
              }
            });                                        
          }finally{
            MainFrame.unlockGUI();
            Gate.setExecutable(null);
          }//catch

          //remove the listeners
          controller.removeStatusListener(sListener);
          controller.removeProgressListener(pListener);

          long endTime = System.currentTimeMillis();
          fireProcessFinished();
          fireStatusChanged(controller.getName() +
                            " run in " +
                            NumberFormat.getInstance().format(
                            (double)(endTime - startTime) / 1000) + " seconds");
        }
      };
      Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
                                 runnable,
                                 "ApplicationViewer1");
      thread.setPriority(Thread.MIN_PRIORITY);
      thread.start();
    }//public void actionPerformed(ActionEvent e)
  }//class RunAction

  /**
   * A simple progress listener used to forward the events upstream.
   */
  protected class InternalProgressListener implements ProgressListener{
    @Override
    public void progressChanged(int i){
      fireProgressChanged(i);
    }

    @Override
    public void processFinished(){
      fireProcessFinished();
    }
  }//InternalProgressListener

  /**
   * A simple status listener used to forward the events upstream.
   */
  protected class InternalStatusListener implements StatusListener{
    @Override
    public void statusChanged(String message){
      fireStatusChanged(message);
    }
  }//InternalStatusListener

  /** The controller this editor edits */
  protected SerialController controller;

  /**
   * The list of actions provided by this editor
   */
  protected List actionList;
  /**
   * Contains all the PRs loaded in the sytem that are not already part of the
   * serial controller
   */
  protected XJTable loadedPRsTable;

  /**
   * model for the {@link #loadedPRsTable} JTable.
   */
  protected LoadedPRsTableModel loadedPRsTableModel;

  /**
   * Displays the PRs in the controller
   */
  protected XJTable memberPRsTable;

  /** model for {@link #memberPRsTable}*/
  protected MemberPRsTableModel memberPRsTableModel;

  /** Adds one or more PR(s) to the controller*/
  protected JButton addButton;

  /** Removes one or more PR(s) from the controller*/
  protected JButton removeButton;

  /** Moves the module up in the controller list*/
  protected JButton moveUpButton;

  /** Moves the module down in the controller list*/
  protected JButton moveDownButton;

  /** A component for editing the parameters of the currently selected PR*/
  protected ResourceParametersEditor parametersEditor;

  /** A JPanel containing the {@link #parametersEditor}*/
  protected JPanel parametersPanel;

  /** A border for the {@link #parametersPanel} */
  protected TitledBorder parametersBorder;


  /** A JPanel containing the running strategy options*/
  protected JPanel strategyPanel;

  /** A border for the running strategy options box */
  protected TitledBorder strategyBorder;

  /**
   * Button for run always.
   */
  protected JRadioButton yes_RunRBtn;

  /**
   * Button for never run.
   */
  protected JRadioButton no_RunRBtn;

  /**
   * Button for conditional run.
   */
  protected JRadioButton conditional_RunRBtn;

  /**
   * The group for run strategy buttons;
   */
  protected ButtonGroup runBtnGrp;

  /**
   * Text field for the feature name for conditional run.
   */
  protected JTextField featureNameTextField;

  /**
   * Text field for the feature value for conditional run.
   */
  protected JTextField featureValueTextField;

  /**
   * A combobox that allows selection of a corpus from the list of loaded
   * corpora.
   */
  @SuppressWarnings("rawtypes")
  protected JComboBox corpusCombo;

  protected CorporaComboModel corpusComboModel;

  /** Action that runs the application*/
  protected RunAction runAction;

  /**
   * Is the controller displayed a CorpusController?
   */
  protected boolean corpusControllerMode = false;

  /**
   * Is the controller displayed an analyser controller?
   */
  protected boolean analyserMode = false;

  /**
   * Is the controller displayed conditional?
   */
  protected boolean conditionalMode = false;

  /**
   * The PR currently selected (having its parameters set)
   */
  protected ProcessingResource selectedPR = null;

  /**
   * The running strategy for the selected PR.
   */
  protected RunningStrategy selectedPRRunStrategy = null;

  private transient Vector statusListeners;
  private transient Vector progressListeners;

  private AddPRAction addPRAction;
  private RemovePRAction removePRAction;


  protected void fireStatusChanged(String e) {
    if (statusListeners != null) {
      Vector listeners = statusListeners;
      int count = listeners.size();
      for (int i = 0; i < count; i++) {
        listeners.elementAt(i).statusChanged(e);
      }
    }
  }
  public synchronized void removeProgressListener(ProgressListener l) {
    if (progressListeners != null && progressListeners.contains(l)) {
      @SuppressWarnings("unchecked")
      Vector v = (Vector) progressListeners.clone();
      v.removeElement(l);
      progressListeners = v;
    }
  }
  public synchronized void addProgressListener(ProgressListener l) {
    @SuppressWarnings("unchecked")
    Vector v = progressListeners == null ?
      new Vector(2) : (Vector) progressListeners.clone();
    if (!v.contains(l)) {
      v.addElement(l);
      progressListeners = v;
    }
  }
  protected void fireProgressChanged(int e) {
    if (progressListeners != null) {
      Vector listeners = progressListeners;
      int count = listeners.size();
      for (int i = 0; i < count; i++) {
        listeners.elementAt(i).progressChanged(e);
      }
    }
  }
  protected void fireProcessFinished() {
    if (progressListeners != null) {
      Vector listeners = progressListeners;
      int count = listeners.size();
      for (int i = 0; i < count; i++) {
        listeners.elementAt(i).processFinished();
      }
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy