MainFrame.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 22/01/2001
0011  *
0012  *  $Id: MainFrame.java 13697 2011-04-19 08:30:16Z valyt $
0013  *
0014  */
0015 
0016 package gate.gui;
0017 
0018 import java.awt.*;
0019 import java.awt.datatransfer.Transferable;
0020 import java.awt.datatransfer.StringSelection;
0021 import java.awt.datatransfer.DataFlavor;
0022 import java.awt.event.*;
0023 import java.beans.PropertyChangeEvent;
0024 import java.beans.PropertyChangeListener;
0025 import java.io.*;
0026 import java.net.MalformedURLException;
0027 import java.net.URL;
0028 import java.text.NumberFormat;
0029 import java.util.*;
0030 import java.util.List;
0031 import java.util.Timer;
0032 import java.util.regex.Matcher;
0033 import java.util.regex.Pattern;
0034 import java.lang.reflect.Constructor;
0035 import java.lang.reflect.Proxy;
0036 import java.lang.reflect.Method;
0037 import java.lang.reflect.InvocationHandler;
0038 import java.lang.SecurityException;
0039 
0040 import javax.swing.*;
0041 import javax.swing.event.*;
0042 import javax.swing.tree.*;
0043 
0044 import org.apache.log4j.*;
0045 
0046 import junit.framework.Assert;
0047 
0048 import com.ontotext.gate.vr.Gaze;
0049 
0050 import gate.*;
0051 import gate.creole.*;
0052 import gate.creole.gazetteer.Gazetteer;
0053 import gate.creole.annic.Constants;
0054 import gate.event.*;
0055 import gate.persist.PersistenceException;
0056 import gate.security.*;
0057 import gate.swing.*;
0058 import gate.util.*;
0059 import gate.util.persistence.PersistenceManager;
0060 import gate.util.reporting.*;
0061 import gate.util.reporting.exceptions.BenchmarkReportException;
0062 
0063 /**
0064  * The main Gate GUI frame.
0065  */
0066 public class MainFrame extends JFrame implements ProgressListener,
0067                                      StatusListener, CreoleListener {
0068 
0069   protected static final Logger log = Logger.getLogger(MainFrame.class);
0070 
0071   protected JMenuBar menuBar;
0072 
0073   protected JSplitPane mainSplit;
0074 
0075   protected JSplitPane leftSplit;
0076 
0077   protected JLabel statusBar;
0078 
0079   protected JButton alertButton;
0080 
0081   protected JProgressBar progressBar;
0082 
0083   protected JProgressBar globalProgressBar;
0084 
0085   protected XJTabbedPane mainTabbedPane;
0086 
0087   protected JScrollPane lowerScroll;
0088 
0089   /**
0090    * Popup used for right click actions on the Applications node.
0091    */
0092   protected JPopupMenu appsPopup;
0093 
0094   /**
0095    * Popup used for right click actions on the Datastores node.
0096    */
0097   protected JPopupMenu dssPopup;
0098 
0099   /**
0100    * Popup used for right click actions on the LRs node.
0101    */
0102   protected JPopupMenu lrsPopup;
0103 
0104   /**
0105    * Popup used for right click actions on the PRs node.
0106    */
0107   protected JPopupMenu prsPopup;
0108 
0109   protected JCheckBoxMenuItem verboseModeItem;
0110 
0111   protected JTree resourcesTree;
0112 
0113   protected JScrollPane resourcesTreeScroll;
0114 
0115   protected DefaultTreeModel resourcesTreeModel;
0116 
0117   protected DefaultMutableTreeNode resourcesTreeRoot;
0118 
0119   protected DefaultMutableTreeNode applicationsRoot;
0120 
0121   protected DefaultMutableTreeNode languageResourcesRoot;
0122 
0123   protected DefaultMutableTreeNode processingResourcesRoot;
0124 
0125   protected DefaultMutableTreeNode datastoresRoot;
0126 
0127   protected Splash splash;
0128 
0129   protected PluginManagerUI pluginManager;
0130 
0131   protected LogArea logArea;
0132 
0133   protected JScrollPane logScroll;
0134 
0135   protected JToolBar toolbar;
0136 
0137   protected static XJFileChooser fileChooser;
0138 
0139   static private MainFrame instance;
0140 
0141   protected OptionsDialog optionsDialog;
0142 
0143   protected CartoonMinder animator;
0144 
0145   protected TabHighlighter logHighlighter;
0146 
0147   protected NewResourceDialog newResourceDialog;
0148 
0149   protected HelpFrame helpFrame;
0150 
0151   /**
0152    * Holds all the icons used in the Gate GUI indexed by filename. This
0153    * is needed so we do not need to decode the icon everytime we need it
0154    * as that would use unnecessary CPU time and memory. Access to this
0155    * data is available through the {@link #getIcon(String)} method.
0156    */
0157   protected static Map<String, Icon> iconByName = new HashMap<String, Icon>();
0158 
0159   protected static java.util.Collection<Component> guiRoots =
0160     new ArrayList<Component>();
0161 
0162   /**
0163    * Extensions for icon files to be tried in this order.
0164    */
0165   protected static final String[] ICON_EXTENSIONS = {""".png"".gif"};
0166 
0167   private static JDialog guiLock = null;
0168 
0169   static public Icon getIcon(String baseName) {
0170     Icon result = iconByName.get(baseName);
0171     for(int i = 0; i < ICON_EXTENSIONS.length && result == null; i++) {
0172       String extension = ICON_EXTENSIONS[i];
0173       String fileName = baseName + extension;
0174       URL iconURL;
0175       // if the ICON is an absolute path starting with '/', then just
0176       // load
0177       // it from that path. If it does not start with '/', treat it as
0178       // relative to gate/resources/img for backwards compatibility
0179       if(fileName.charAt(0== '/') {
0180         iconURL = Files.getResource(fileName);
0181       }
0182       else {
0183         iconURL = Files.getGateResource("/img/" + fileName);
0184       }
0185       if(iconURL != null) {
0186         result = new ImageIcon(iconURL);
0187         iconByName.put(baseName, result);
0188       }
0189     }
0190     return result;
0191   }
0192 
0193   static public MainFrame getInstance() {
0194     if(instance == nullinstance = new MainFrame();
0195     return instance;
0196   }
0197 
0198   /**
0199    * Get the file chooser.
0200    @return the current file chooser
0201    */
0202   static public XJFileChooser getFileChooser() {
0203     return fileChooser;
0204   }
0205 
0206   /**
0207    * Gets the original system output stream, which was later redirected
0208    * to the messages pane.
0209    *
0210    @return {@link PrintStream} value.
0211    */
0212   public PrintStream getOriginalOut() {
0213     return logArea.getOriginalOut();
0214   }
0215 
0216   /**
0217    * Gets the original system error output stream, which was later
0218    * redirected to the messages pane.
0219    *
0220    @return {@link PrintStream} value.
0221    */
0222   public PrintStream getOriginalErr() {
0223     return logArea.getOriginalErr();
0224   }
0225 
0226   /**
0227    * Locates the handle for a given resource.
0228    @param res the resource for which the handle is sought.
0229    @return the {@link Handle} for the resource, if it it was found.
0230    */
0231   protected Handle findHandleForResource(Resource res){
0232     Handle handle = null;
0233     // go through all the nodes
0234     Enumeration nodesEnum = resourcesTreeRoot.breadthFirstEnumeration();
0235     while(nodesEnum.hasMoreElements() && handle == null) {
0236       Object node = nodesEnum.nextElement();
0237       if(node instanceof DefaultMutableTreeNode) {
0238         DefaultMutableTreeNode dmtNode = (DefaultMutableTreeNode)node;
0239         if(dmtNode.getUserObject() instanceof Handle) {
0240           if(((Handle)dmtNode.getUserObject()).getTarget() == res) {
0241             handle = (Handle)dmtNode.getUserObject();
0242           }
0243         }
0244       }
0245     }
0246     return handle;
0247   }
0248 
0249   /**
0250    * Selects a resource if loaded in the system and not invisible.
0251    *
0252    @param res the resource to be selected.
0253    @return the {@link Handle} for the resource, null if not found.
0254    */
0255   public Handle select(Resource res) {
0256     // first find the handle for the resource
0257     Handle handle = findHandleForResource(res);
0258     // now select the handle if found
0259     if(handle != null) {
0260       select(handle);
0261     }
0262     return handle;
0263   }
0264 
0265   protected void select(Handle handle) {
0266     final JComponent largeView = handle.getLargeView();
0267     if(handle.viewsBuilt()
0268       && mainTabbedPane.indexOfComponent(handle.getLargeView()) != -1) {
0269       // select
0270       if(largeView != null) {
0271         mainTabbedPane.setSelectedComponent(largeView);
0272       }
0273     }
0274     else {
0275       // show
0276       if(largeView != null) {
0277         mainTabbedPane.addTab(handle.getTitle(), handle.getIcon(), largeView,
0278           handle.getTooltipText());
0279         mainTabbedPane.setSelectedComponent(handle.getLargeView());
0280         // put the focus on the new tab
0281         SwingUtilities.invokeLater(new Runnable() {
0282           public void run() {
0283             if (largeView != null) {
0284               if ((largeView instanceof JTabbedPane)
0285               && (((JTabbedPane)largeView).getSelectedComponent() != null)) {
0286                 ((JTabbedPane)largeView).getSelectedComponent().requestFocus();
0287               else {
0288                 largeView.requestFocus();
0289               }
0290             }
0291           }
0292         });
0293       }
0294     }
0295     // show the small view
0296     JComponent smallView = handle.getSmallView();
0297     if(smallView != null) {
0298       lowerScroll.getViewport().setView(smallView);
0299     }
0300     else {
0301       lowerScroll.getViewport().setView(null);
0302     }
0303   }// protected void select(ResourceHandle handle)
0304 
0305   public MainFrame() {
0306     this(null);
0307   }
0308 
0309   public MainFrame(GraphicsConfiguration gc) {
0310     this(false, gc);
0311   // MainFrame
0312 
0313   /**
0314    * Construct the frame.
0315    @param isShellSlacGIU true for embedded uses of GATE where a simpler GUI
0316    *                       should be displayed.
0317    @param gc graphics configuration used,
0318    *   see {@link javax.swing.JFrame#JFrame(java.awt.GraphicsConfiguration)}
0319    */
0320   public MainFrame(boolean isShellSlacGIU, GraphicsConfiguration gc) {
0321     super(gc);
0322     instance = this;
0323     guiRoots.add(this);
0324     if(fileChooser == null) {
0325       fileChooser = new XJFileChooser();
0326       fileChooser.setMultiSelectionEnabled(false);
0327       fileChooser.setAcceptAllFileFilterUsed(true);
0328       guiRoots.add(fileChooser);
0329 
0330       // the JFileChooser seems to size itself better once it's been
0331       // added to a top level container such as a dialog.
0332       JDialog dialog = new JDialog(this, ""true);
0333       java.awt.Container contentPane = dialog.getContentPane();
0334       contentPane.setLayout(new BorderLayout());
0335       contentPane.add(fileChooser, BorderLayout.CENTER);
0336       dialog.pack();
0337       dialog.getContentPane().removeAll();
0338       dialog.dispose();
0339       dialog = null;
0340     }
0341     enableEvents(AWTEvent.WINDOW_EVENT_MASK);
0342     initLocalData(isShellSlacGIU);
0343     initGuiComponents(isShellSlacGIU);
0344     initListeners(isShellSlacGIU);
0345   // MainFrame(boolean simple)
0346 
0347   protected void initLocalData(boolean isShellSlacGIU) {
0348     resourcesTreeRoot = new DefaultMutableTreeNode("GATE"true);
0349     applicationsRoot = new DefaultMutableTreeNode("Applications"true);
0350     if(isShellSlacGIU) {
0351       languageResourcesRoot = new DefaultMutableTreeNode("Documents"true);
0352     }
0353     else {
0354       languageResourcesRoot =
0355         new DefaultMutableTreeNode("Language Resources"true);
0356     // if
0357     processingResourcesRoot =
0358       new DefaultMutableTreeNode("Processing Resources"true);
0359     datastoresRoot = new DefaultMutableTreeNode("Datastores"true);
0360     resourcesTreeRoot.add(applicationsRoot);
0361     resourcesTreeRoot.add(languageResourcesRoot);
0362     resourcesTreeRoot.add(processingResourcesRoot);
0363     resourcesTreeRoot.add(datastoresRoot);
0364 
0365     resourcesTreeModel = new ResourcesTreeModel(resourcesTreeRoot, true);
0366   }
0367 
0368   protected void initGuiComponents(boolean isShellSlacGUI) {
0369     this.getContentPane().setLayout(new BorderLayout());
0370 
0371     Integer width = Gate.getUserConfig().getInt(GateConstants.MAIN_FRAME_WIDTH);
0372     Integer height =
0373       Gate.getUserConfig().getInt(GateConstants.MAIN_FRAME_HEIGHT);
0374     this.setSize(new Dimension(width == null 800 : width,
0375       height == null 600 : height));
0376 
0377     // TODO: when upgrading to Java 1.6 use setIconImages() instead
0378     this.setIconImage(Toolkit.getDefaultToolkit().getImage(
0379       Files.getGateResource("/img/gate-icon.png")));
0380     resourcesTree = new ResourcesTree();
0381     resourcesTree.setModel(resourcesTreeModel);
0382     resourcesTree.setRowHeight(0);
0383 
0384     resourcesTree.setEditable(true);
0385     ResourcesTreeCellRenderer treeCellRenderer =
0386       new ResourcesTreeCellRenderer();
0387     resourcesTree.setCellRenderer(treeCellRenderer);
0388     resourcesTree.setCellEditor(new ResourcesTreeCellEditor(resourcesTree,
0389       treeCellRenderer));
0390 
0391     resourcesTree.setRowHeight(0);
0392     // expand all nodes
0393     resourcesTree.expandRow(0);
0394     resourcesTree.expandRow(1);
0395     resourcesTree.expandRow(2);
0396     resourcesTree.expandRow(3);
0397     resourcesTree.expandRow(4);
0398     resourcesTree.getSelectionModel().setSelectionMode(
0399       TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
0400     resourcesTree.setEnabled(true);
0401     ToolTipManager.sharedInstance().registerComponent(resourcesTree);
0402     resourcesTreeScroll = new JScrollPane(resourcesTree);
0403 
0404     resourcesTree.setDragEnabled(true);
0405     resourcesTree.setTransferHandler(new TransferHandler() {
0406       // drag and drop that export a list of the selected documents
0407       public int getSourceActions(JComponent c) {
0408         return COPY;
0409       }
0410       protected Transferable createTransferable(JComponent c) {
0411         TreePath[] paths = resourcesTree.getSelectionPaths();
0412         if(paths == null) { return new StringSelection("")}
0413         Handle handle;
0414         List<String> documentsNames = new ArrayList<String>();
0415         for(TreePath path : paths) {
0416           if(path != null) {
0417             Object value = path.getLastPathComponent();
0418             value = ((DefaultMutableTreeNode)value).getUserObject();
0419             if(value instanceof Handle) {
0420               handle = (Handle)value;
0421               if(handle.getTarget() instanceof Document) {
0422                 documentsNames.add(((Document)handle.getTarget()).getName());
0423               }
0424             }
0425           }
0426         }
0427         return new StringSelection("ResourcesTree"
0428           + Arrays.toString(documentsNames.toArray()));
0429       }
0430       protected void exportDone(JComponent c, Transferable data, int action) {
0431       }
0432       public boolean canImport(JComponent c, DataFlavor[] flavors) {
0433         return false;
0434       }
0435       public boolean importData(JComponent c, Transferable t) {
0436         return false;
0437       }
0438     });
0439 
0440     lowerScroll = new JScrollPane();
0441     JPanel lowerPane = new JPanel();
0442     lowerPane.setLayout(new OverlayLayout(lowerPane));
0443 
0444     JPanel animationPane = new JPanel();
0445     animationPane.setOpaque(false);
0446     animationPane.setLayout(new BoxLayout(animationPane, BoxLayout.X_AXIS));
0447 
0448     JPanel vBox = new JPanel();
0449     vBox.setLayout(new BoxLayout(vBox, BoxLayout.Y_AXIS));
0450     vBox.setOpaque(false);
0451 
0452     JPanel hBox = new JPanel();
0453     hBox.setLayout(new BoxLayout(hBox, BoxLayout.X_AXIS));
0454     hBox.setOpaque(false);
0455 
0456     vBox.add(Box.createVerticalGlue());
0457     vBox.add(animationPane);
0458 
0459     hBox.add(vBox);
0460     hBox.add(Box.createHorizontalGlue());
0461 
0462     lowerPane.add(hBox);
0463     lowerPane.add(lowerScroll);
0464 
0465     animator = new CartoonMinder(animationPane);
0466     Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
0467       animator, "MainFrame animation");
0468     thread.setDaemon(true);
0469     thread.setPriority(Thread.MIN_PRIORITY);
0470     thread.start();
0471 
0472     leftSplit =
0473       new JSplitPane(JSplitPane.VERTICAL_SPLIT, resourcesTreeScroll, lowerPane);
0474     leftSplit.setResizeWeight(0.7);
0475     leftSplit.setContinuousLayout(true);
0476     leftSplit.setOneTouchExpandable(true);
0477 
0478     // Create a new logArea and redirect the Out and Err output to it.
0479     logArea = new LogArea();
0480     logScroll = new JScrollPane(logArea);
0481     // Out has been redirected to the logArea
0482 
0483     Out.prln("GATE " + Main.version + " build " + Main.build + " started at "
0484       new Date().toString());
0485     Out.prln("and using Java " + System.getProperty("java.version"" " +
0486       System.getProperty("java.vendor"" on " +
0487       System.getProperty("os.name"" " +
0488       System.getProperty("os.arch"" " +
0489       System.getProperty("os.version"".");
0490     mainTabbedPane = new XJTabbedPane(JTabbedPane.TOP);
0491     mainTabbedPane.insertTab("Messages", null, logScroll, "GATE log"0);
0492 
0493     logHighlighter = new TabHighlighter(mainTabbedPane, logScroll, Color.red);
0494 
0495     mainSplit =
0496       new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftSplit, mainTabbedPane);
0497     mainSplit.setDividerLocation(leftSplit.getPreferredSize().width + 10);
0498     this.getContentPane().add(mainSplit, BorderLayout.CENTER);
0499     mainSplit.setContinuousLayout(true);
0500     mainSplit.setOneTouchExpandable(true);
0501 
0502     // status and progress bars
0503     statusBar = new JLabel();
0504     statusBar.setBorder(BorderFactory.createEmptyBorder(0500));
0505 
0506     UIManager.put("ProgressBar.cellSpacing"0);
0507     progressBar = new JProgressBar(JProgressBar.HORIZONTAL);
0508     progressBar.setBorder(BorderFactory.createEmptyBorder());
0509     progressBar.setForeground(new Color(15075150));
0510     progressBar.setStringPainted(false);
0511 
0512     globalProgressBar = new JProgressBar(JProgressBar.HORIZONTAL);
0513     globalProgressBar.setBorder(BorderFactory.createEmptyBorder());
0514     globalProgressBar.setForeground(new Color(15075150));
0515     globalProgressBar.setStringPainted(true);
0516 
0517     Icon alertIcon = getIcon("crystal-clear-app-error");
0518     alertButton = new JButton(alertIcon);
0519     alertButton.setToolTipText("There was no error");
0520     alertButton.setBorder(BorderFactory.createEmptyBorder(0305));
0521     alertButton.setPreferredSize(new Dimension(alertIcon.getIconWidth(),
0522       alertIcon.getIconHeight()));
0523     alertButton.setEnabled(false);
0524 
0525     JPanel southBox = new JPanel(new GridBagLayout());
0526     GridBagConstraints gbc = new GridBagConstraints();
0527     gbc.fill = GridBagConstraints.BOTH;
0528     gbc.anchor = GridBagConstraints.WEST;
0529     gbc.weightx = 1;
0530     southBox.add(statusBar, gbc);
0531     gbc.insets = new Insets(0303);
0532     gbc.anchor = GridBagConstraints.EAST;
0533     gbc.weightx = 0;
0534     southBox.add(progressBar, gbc);
0535     southBox.add(globalProgressBar, gbc);
0536     southBox.add(alertButton, gbc);
0537 
0538     this.getContentPane().add(southBox, BorderLayout.SOUTH);
0539     progressBar.setVisible(false);
0540     globalProgressBar.setVisible(false);
0541 
0542     // extra stuff
0543     newResourceDialog =
0544       new NewResourceDialog(this, "Resource parameters"true);
0545 
0546     // build the Help->About dialog
0547     JPanel splashBox = new JPanel();
0548     splashBox.setBackground(Color.WHITE);
0549 
0550     splashBox.setLayout(new GridBagLayout());
0551     GridBagConstraints constraints = new GridBagConstraints();
0552     constraints.weightx = 1;
0553     constraints.insets = new Insets(2222);
0554     constraints.gridy = 0;
0555     constraints.fill = GridBagConstraints.BOTH;
0556 
0557     JLabel gifLbl = new JLabel(getIcon("splash"));
0558     splashBox.add(gifLbl, constraints);
0559 
0560     constraints.gridy = 2;
0561     constraints.gridwidth = 2;
0562     constraints.fill = GridBagConstraints.HORIZONTAL;
0563     String splashHtml;
0564     try {
0565       splashHtml = Files.getGateResourceAsString("splash.html");
0566     }
0567     catch(IOException e) {
0568       splashHtml = "GATE";
0569       log.error("Couldn't get splash.html resource.", e);
0570     }
0571     JLabel htmlLbl = new JLabel(splashHtml);
0572     htmlLbl.setHorizontalAlignment(SwingConstants.CENTER);
0573     splashBox.add(htmlLbl, constraints);
0574 
0575     constraints.gridy = 3;
0576     htmlLbl =
0577       new JLabel("<HTML><FONT color=\"blue\">Version <B>" + Main.version
0578         "</B></FONT>" ", <FONT color=\"red\">build <B>" + Main.build
0579         "</B></FONT>" "<P><B>JVM version</B>: "
0580         + System.getProperty("java.version"" from "
0581         + System.getProperty("java.vendor""</HTML>");
0582     constraints.fill = GridBagConstraints.HORIZONTAL;
0583     splashBox.add(htmlLbl, constraints);
0584 
0585     constraints.gridy = 4;
0586     constraints.gridwidth = 2;
0587     constraints.fill = GridBagConstraints.NONE;
0588     final JButton okButton = new JButton("OK");
0589     okButton.addActionListener(new ActionListener() {
0590       public void actionPerformed(ActionEvent e) {
0591         splash.setVisible(false);
0592       }
0593     });
0594     okButton.setBackground(Color.white);
0595     splashBox.add(okButton, constraints);
0596     splash = new Splash(this, splashBox);
0597     // make Enter and Escape keys closing the splash window
0598     splash.getRootPane().setDefaultButton(okButton);
0599     InputMap inputMap = ((JComponent)splash.getContentPane())
0600       .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
0601     ActionMap actionMap = ((JComponent)splash.getContentPane()).getActionMap();
0602     inputMap.put(KeyStroke.getKeyStroke("ENTER")"Apply");
0603     actionMap.put("Apply"new AbstractAction() {
0604       public void actionPerformed(ActionEvent e) {
0605         okButton.doClick();
0606       }
0607     });
0608     inputMap.put(KeyStroke.getKeyStroke("ESCAPE")"Cancel");
0609     actionMap.put("Cancel"new AbstractAction() {
0610       public void actionPerformed(ActionEvent e) {
0611         okButton.doClick();
0612       }
0613     });
0614 
0615     // MENUS
0616     menuBar = new JMenuBar();
0617 
0618     JMenu fileMenu = new XJMenu("File", null, this);
0619     fileMenu.setMnemonic(KeyEvent.VK_F);
0620 
0621     LiveMenu newAPPMenu = new LiveMenu(LiveMenu.APP);
0622     newAPPMenu.setText("New Application");
0623     newAPPMenu.setIcon(getIcon("applications"));
0624     fileMenu.add(newAPPMenu);
0625 
0626     LiveMenu newLRMenu = new LiveMenu(LiveMenu.LR);
0627     newLRMenu.setText("New Language Resource");
0628     newLRMenu.setIcon(getIcon("lrs"));
0629     fileMenu.add(newLRMenu);
0630 
0631     LiveMenu newPRMenu = new LiveMenu(LiveMenu.PR);
0632     newPRMenu.setText("New Processing Resource");
0633     newPRMenu.setIcon(getIcon("prs"));
0634     fileMenu.add(newPRMenu);
0635 
0636     final JMenu dsMenu = new XJMenu("Datastores",
0637       "Repositories for large data"this);
0638     dsMenu.setIcon(getIcon("datastores"));
0639     dsMenu.add(new XJMenuItem(new NewDSAction()this));
0640     dsMenu.add(new XJMenuItem(new OpenDSAction()this));
0641     fileMenu.add(dsMenu);
0642 
0643     fileMenu.addSeparator();
0644     fileMenu.add(new XJMenuItem(new LoadResourceFromFileAction()this));
0645 
0646     RecentAppsMenu recentAppsMenu = new RecentAppsMenu();
0647     recentAppsMenu.setText("Recent Applications");
0648     recentAppsMenu.setIcon(getIcon("open-application"));
0649     fileMenu.add(recentAppsMenu);
0650 
0651     final JMenu loadANNIEMenu = new XJMenu("Load ANNIE System",
0652       "Application that adds morphosyntaxic and semantic annotations"this);
0653     loadANNIEMenu.setIcon(getIcon("annie-application"));
0654     loadANNIEMenu.add(new XJMenuItem(new LoadANNIEWithDefaultsAction()this));
0655     loadANNIEMenu
0656       .add(new XJMenuItem(new LoadANNIEWithoutDefaultsAction()this));
0657     fileMenu.add(loadANNIEMenu);
0658 
0659     // fileMenu.add(new XJMenuItem(new LoadCreoleRepositoryAction(),
0660     // this));
0661 
0662     // LingPipe action
0663     fileMenu.add(new XJMenuItem(new LoadApplicationAction(
0664             "Load LingPipe System""LingPipe""resources/lingpipe.gapp"),
0665             this));
0666 
0667     // OpenNLP action
0668     fileMenu.add(new XJMenuItem(new LoadApplicationAction(
0669             "Load OpenNLP System""OpenNLP""resources/opennlp.gapp")this));
0670 
0671     fileMenu.add(new XJMenuItem(new ManagePluginsAction()this));
0672 
0673     if(!Gate.runningOnMac()) {
0674       fileMenu.addSeparator();
0675       fileMenu.add(new XJMenuItem(new ExitGateAction()this));
0676     }
0677 
0678     menuBar.add(fileMenu);
0679 
0680     JMenu optionsMenu = new XJMenu("Options", null, this);
0681     optionsMenu.setMnemonic(KeyEvent.VK_O);
0682 
0683     boolean optionsMenuHasEntries = false;
0684 
0685     optionsDialog = new OptionsDialog(MainFrame.this);
0686     if(!Gate.runningOnMac()) {
0687       optionsMenu.add(new XJMenuItem(new AbstractAction("Configuration") {
0688         private static final long serialVersionUID = 1L;
0689         {
0690           putValue(SHORT_DESCRIPTION, "Edit GATE options");
0691         }
0692 
0693         public void actionPerformed(ActionEvent evt) {
0694           optionsDialog.showDialog();
0695           optionsDialog.dispose();
0696         }
0697       }this));
0698       optionsMenuHasEntries = true;
0699     }
0700 
0701     JMenu imMenu = null;
0702     List<Locale> installedLocales = new ArrayList<Locale>();
0703     try {
0704       // if this fails guk is not present
0705       Class.forName("guk.im.GateIMDescriptor");
0706       // add the Gate input methods
0707       installedLocales.addAll(Arrays.asList(new guk.im.GateIMDescriptor()
0708         .getAvailableLocales()));
0709     }
0710     catch(Exception e) {
0711       // something happened; most probably guk not present.
0712       // just drop it, is not vital.
0713     }
0714     try {
0715       // add the MPI IMs
0716       // if this fails mpi IM is not present
0717       Class.forName("mpi.alt.java.awt.im.spi.lookup.LookupDescriptor");
0718 
0719       installedLocales.addAll(Arrays
0720         .asList(new mpi.alt.java.awt.im.spi.lookup.LookupDescriptor()
0721           .getAvailableLocales()));
0722     }
0723     catch(Exception e) {
0724       // something happened; most probably MPI not present.
0725       // just drop it, is not vital.
0726     }
0727 
0728     Collections.sort(installedLocales, new Comparator<Locale>() {
0729       public int compare(Locale o1, Locale o2) {
0730         return o1.getDisplayName().compareTo(o2.getDisplayName());
0731       }
0732     });
0733     JMenuItem item;
0734     if(!installedLocales.isEmpty()) {
0735       imMenu = new XJMenu("Input Methods");
0736       ButtonGroup bg = new ButtonGroup();
0737       item = new LocaleSelectorMenuItem();
0738       imMenu.add(item);
0739       item.setSelected(true);
0740       imMenu.addSeparator();
0741       bg.add(item);
0742       for(Locale locale : installedLocales) {
0743         item = new LocaleSelectorMenuItem(locale);
0744         imMenu.add(item);
0745         bg.add(item);
0746       }
0747     }
0748     if(imMenu != null) {
0749       optionsMenu.add(imMenu);
0750       optionsMenuHasEntries = true;
0751     }
0752 
0753     if(optionsMenuHasEntries) {
0754       menuBar.add(optionsMenu);
0755     }
0756 
0757     ToolsMenu toolsMenu = new ToolsMenu("Tools", null, this);
0758     toolsMenu.setMnemonic(KeyEvent.VK_T);
0759     toolsMenu.add(new XJMenuItem(new NewAnnotDiffAction()this));
0760 
0761     final JMenuItem reportClearMenuItem = new XJMenuItem(
0762       new AbstractAction("Clear Profiling History") {
0763       putValue(SHORT_DESCRIPTION,
0764         "Clear profiling history otherwise the report is cumulative.")}
0765       public void actionPerformed(ActionEvent evt) {
0766         // create a new log file
0767         File logFile = new File(System.getProperty("java.io.tmpdir"),
0768           "gate-benchmark-log.txt");
0769         logFile.deleteOnExit();
0770         if (logFile.exists() && !logFile.delete()) {
0771           log.info("Error when deleting the file:\n" +
0772             logFile.getAbsolutePath());
0773         }
0774       }
0775     }this);
0776     JMenu reportMenu = new XJMenu("Profiling Reports",
0777       "Generates profiling reports from processing resources"this);
0778     reportMenu.setIcon(getIcon("gazetteer"));
0779     reportMenu.add(new XJMenuItem(
0780       new AbstractAction("Start Profiling Applications") {
0781       putValue(SHORT_DESCRIPTION,
0782         "Toggles the profiling of processing resources")}
0783 
0784       // stores the value held by the benchmarking switch before we started
0785       // this profiling run.
0786       boolean benchmarkWasEnabled;
0787 
0788       public void actionPerformed(ActionEvent evt) {
0789         if (getValue(NAME).equals("Start Profiling Applications")) {
0790           reportClearMenuItem.setEnabled(false);
0791           // store old value of benchmark switch
0792           benchmarkWasEnabled = Benchmark.isBenchmarkingEnabled();
0793           Benchmark.setBenchmarkingEnabled(true);
0794           Layout layout = new PatternLayout("%m%n");
0795           File logFile = new File(System.getProperty("java.io.tmpdir"),
0796             "gate-benchmark-log.txt");
0797           logFile.deleteOnExit();
0798           Appender appender;
0799           try {
0800             appender =
0801               new FileAppender(layout, logFile.getAbsolutePath()true);
0802           catch (IOException e) {
0803             e.printStackTrace();
0804             return;
0805           }
0806           appender.setName("gate-benchmark");
0807           Benchmark.logger.addAppender(appender);
0808           putValue(NAME, "Stop Profiling Applications");
0809         else {
0810           // reset old value of benchmark switch - i.e. if benchmarking was
0811           // disabled before the user selected "start profiling" then we
0812           // disable it again now, but if it was already enabled before they
0813           // started profiling then we assume it was turned on explicitly and
0814           // leave it alone.
0815           Benchmark.setBenchmarkingEnabled(benchmarkWasEnabled);
0816           Benchmark.logger.removeAppender("gate-benchmark");
0817           putValue(NAME, "Start Profiling Applications");
0818           reportClearMenuItem.setEnabled(true);
0819         }
0820       }
0821     }this));
0822     reportMenu.add(reportClearMenuItem);
0823     reportMenu.add(new XJMenuItem(new AbstractAction("Help on this tool") {
0824       public void actionPerformed(ActionEvent e) {
0825         showHelpFrame("chap:profiling""Profiling Processing Resources");
0826       }
0827     }this));
0828     reportMenu.addSeparator();
0829 
0830     final JCheckBoxMenuItem reportZeroTimesCheckBox = new JCheckBoxMenuItem();
0831     reportZeroTimesCheckBox.setAction(
0832       new AbstractAction("Report Zero Time Entries") {
0833       public void actionPerformed(ActionEvent evt) {
0834         Gate.getUserConfig().put(MainFrame.class.getName()+".reportzerotime",
0835           reportZeroTimesCheckBox.isSelected());
0836       }
0837     });
0838     reportZeroTimesCheckBox.setSelected(Gate.getUserConfig().getBoolean(
0839         MainFrame.class.getName()+".reportzerotimes"));
0840     ButtonGroup group = new ButtonGroup();
0841     final JRadioButtonMenuItem reportSortExecution = new JRadioButtonMenuItem();
0842     reportSortExecution.setAction(new AbstractAction("Sort by Execution") {
0843       public void actionPerformed(ActionEvent evt) {
0844         Gate.getUserConfig().put(
0845           MainFrame.class.getName()+".reportsorttime"false);
0846       }
0847     });
0848     reportSortExecution.setSelected(!Gate.getUserConfig().getBoolean(
0849       MainFrame.class.getName()+".reportsorttime"));
0850     group.add(reportSortExecution);
0851     final JRadioButtonMenuItem reportSortTime = new JRadioButtonMenuItem();
0852     reportSortTime.setAction(new AbstractAction("Sort by Time") {
0853       public void actionPerformed(ActionEvent evt) {
0854         Gate.getUserConfig().put(
0855           MainFrame.class.getName()+".reportsorttime"true);
0856       }
0857     });
0858     reportSortTime.setSelected(Gate.getUserConfig().getBoolean(
0859       MainFrame.class.getName()+".reportsorttime"));
0860     group.add(reportSortTime);
0861     reportMenu.add(new XJMenuItem(
0862       new AbstractAction("Report on Processing Resources") {
0863       putValue(SHORT_DESCRIPTION,
0864         "Report time taken by each processing resource")}
0865       public void actionPerformed(ActionEvent evt) {
0866         PRTimeReporter report = new PRTimeReporter();
0867         report.setBenchmarkFile(new File(System.getProperty("java.io.tmpdir"),
0868           "gate-benchmark-log.txt"));
0869         report.setSuppressZeroTimeEntries(!reportZeroTimesCheckBox.isSelected());
0870         report.setSortOrder(reportSortTime.isSelected() ?
0871           PRTimeReporter.SORT_TIME_TAKEN : PRTimeReporter.SORT_EXEC_ORDER);
0872         try {
0873           report.executeReport();
0874         catch (BenchmarkReportException e) {
0875           e.printStackTrace();
0876           return;
0877         }
0878         showHelpFrame("file://" + report.getReportFile(),
0879           "processing times report");
0880       }
0881     }this));
0882     reportMenu.add(reportZeroTimesCheckBox);
0883     reportMenu.add(reportSortTime);
0884     reportMenu.add(reportSortExecution);
0885     reportMenu.addSeparator();
0886 
0887     reportMenu.add(new XJMenuItem(
0888       new AbstractAction("Report on Documents Processed") {
0889         putValue(SHORT_DESCRIPTION, "Report most time consuming documents")}
0890         public void actionPerformed(ActionEvent evt) {
0891           DocTimeReporter report = new DocTimeReporter();
0892           report.setBenchmarkFile(new File(System.getProperty("java.io.tmpdir"),
0893             "gate-benchmark-log.txt"));
0894           String maxDocs = Gate.getUserConfig().getString(
0895             MainFrame.class.getName()+".reportmaxdocs");
0896           if (maxDocs != null) {
0897             report.setMaxDocumentInReport((maxDocs.equals("All")) ?
0898               DocTimeReporter.ALL_DOCS : Integer.valueOf(maxDocs));
0899           }
0900           String prRegex = Gate.getUserConfig().getString(
0901             MainFrame.class.getName()+".reportprregex");
0902           if (prRegex != null) {
0903             report.setPRMatchingRegex((prRegex.equals("")) ?
0904               DocTimeReporter.MATCH_ALL_PR_REGEX : prRegex);
0905           }
0906           try {
0907             report.executeReport();
0908           catch (BenchmarkReportException e) {
0909             e.printStackTrace();
0910             return;
0911           }
0912           showHelpFrame("file://" + report.getReportFile(),
0913             "documents time report");
0914         }
0915       }this));
0916     String maxDocs = Gate.getUserConfig().getString(
0917       MainFrame.class.getName()+".reportmaxdocs");
0918     if (maxDocs == null) { maxDocs = "10"}
0919     reportMenu.add(new XJMenuItem(
0920       new AbstractAction("Set Max Documents (" + maxDocs + ")") {
0921         public void actionPerformed(ActionEvent evt) {
0922           Object response = JOptionPane.showInputDialog(instance,
0923               "Set the maximum of documents to report""Report options",
0924               JOptionPane.QUESTION_MESSAGE, null,
0925               new Object[]{"All""10""20""30""40""50""100"}"10");
0926           if (response != null) {
0927             Gate.getUserConfig().put(
0928               MainFrame.class.getName()+".reportmaxdocs",response);
0929             putValue(NAME, "Set Max Documents (" + response + ")");
0930           }
0931         }
0932       }this));
0933     String prRegex = Gate.getUserConfig().getString(
0934       MainFrame.class.getName()+".reportprregex");
0935     if (prRegex == null || prRegex.equals("")) { prRegex = "All"}
0936     reportMenu.add(new XJMenuItem(
0937       new AbstractAction("Set PR Matching Regex (" + prRegex + ")") {
0938         public void actionPerformed(ActionEvent evt) {
0939           Object response = JOptionPane.showInputDialog(instance,
0940             "Set the processing resource regex filter\n" +
0941             "Leave empty to not filter""Report options",
0942               JOptionPane.QUESTION_MESSAGE);
0943           if (response != null) {
0944             Gate.getUserConfig().put(
0945               MainFrame.class.getName()+".reportprregex",response);
0946             if (response.equals("")) { response = "All"}
0947             putValue(NAME, "Set PR Matching Regex (" + response + ")");
0948           }
0949         }
0950       }this));
0951     toolsMenu.add(reportMenu);
0952 
0953     toolsMenu.add(new XJMenuItem(new NewBootStrapAction()this));
0954     final JMenu corpusEvalMenu = new XJMenu("Corpus Benchmark",
0955       "Compares processed and human-annotated annotations"this);
0956     corpusEvalMenu.setIcon(getIcon("corpus-benchmark"));
0957     toolsMenu.add(corpusEvalMenu);
0958     corpusEvalMenu.add(new XJMenuItem(new NewCorpusEvalAction()this));
0959     corpusEvalMenu.addSeparator();
0960     corpusEvalMenu.add(new XJMenuItem(
0961       new GenerateStoredCorpusEvalAction()this));
0962     corpusEvalMenu.addSeparator();
0963     corpusEvalMenu.add(new XJMenuItem(
0964       new StoredMarkedCorpusEvalAction()this));
0965     corpusEvalMenu.add(new XJMenuItem(new CleanMarkedCorpusEvalAction()this));
0966     corpusEvalMenu.addSeparator();
0967     verboseModeItem =
0968       new JCheckBoxMenuItem(new VerboseModeCorpusEvalToolAction());
0969     corpusEvalMenu.add(verboseModeItem);
0970     toolsMenu.add(new XJMenuItem(
0971       new AbstractAction("Unicode Editor", getIcon("unicode")) {
0972       putValue(SHORT_DESCRIPTION, "Editor for testing character encoding")}
0973       private static final long serialVersionUID = 1L;
0974       public void actionPerformed(ActionEvent evt) {
0975         new guk.Editor();
0976       }
0977     }this));
0978 
0979     // add separator.  plugin menu items will appear after this separator
0980     toolsMenu.addSeparator();
0981     toolsMenu.staticItemsAdded();
0982     if (toolsMenu.getMenuComponent(toolsMenu.getMenuComponentCount()-1)
0983         instanceof JSeparator) { // remove separator if no tools
0984       toolsMenu.remove(toolsMenu.getMenuComponentCount()-1);
0985     }
0986 
0987     menuBar.add(toolsMenu);
0988 
0989     JMenu helpMenu = new XJMenu("Help", null, MainFrame.this);
0990     helpMenu.setMnemonic(KeyEvent.VK_H);
0991     helpMenu.add(new XJMenuItem(new HelpUserGuideAction()this));
0992     helpMenu.add(new XJMenuItem(new HelpUserGuideInContextAction()this));
0993     helpMenu.add(new XJMenuItem(new AbstractAction("Keyboard Shortcuts") {
0994       public void actionPerformed(ActionEvent e) {
0995         showHelpFrame("sec:developer:keyboard""shortcuts");
0996       }
0997     }this));
0998     helpMenu.addSeparator();
0999     helpMenu.add(new XJMenuItem(new AbstractAction("Using GATE Developer") {
1000       this.putValue(Action.SHORT_DESCRIPTION, "To read first")}
1001       public void actionPerformed(ActionEvent e) {
1002         showHelpFrame("chap:developer""Using GATE Developer");
1003       }
1004     }this));
1005     helpMenu.add(new XJMenuItem(new AbstractAction("Demo Movies") {
1006       this.putValue(Action.SHORT_DESCRIPTION, "Movie tutorials")}
1007       public void actionPerformed(ActionEvent e) {
1008         showHelpFrame("http://gate.ac.uk/demos/developer-videos/""movies");
1009       }
1010     }this));
1011     helpMenu.add(new XJMenuItem(new HelpMailingListAction()this));
1012     helpMenu.addSeparator();
1013     JCheckBoxMenuItem toggleToolTipsCheckBoxMenuItem =
1014       new JCheckBoxMenuItem(new ToggleToolTipsAction());
1015     javax.swing.ToolTipManager toolTipManager =
1016       ToolTipManager.sharedInstance();
1017     if (Gate.getUserConfig().getBoolean(
1018         MainFrame.class.getName()+".hidetooltips")) {
1019       toolTipManager.setEnabled(false);
1020       toggleToolTipsCheckBoxMenuItem.setSelected(false);
1021     else {
1022       toolTipManager.setEnabled(true);
1023       toggleToolTipsCheckBoxMenuItem.setSelected(true);
1024     }
1025     helpMenu.add(toggleToolTipsCheckBoxMenuItem);
1026     helpMenu.add(new XJMenuItem(new AbstractAction("What's New") {
1027       this.putValue(Action.SHORT_DESCRIPTION,
1028           "List new features and important changes")}
1029       public void actionPerformed(ActionEvent e) {
1030         showHelpFrame("chap:changes""changes");
1031       }
1032     }this));
1033     if(!Gate.runningOnMac()) {
1034       helpMenu.add(new XJMenuItem(new HelpAboutAction()this));
1035     }
1036     menuBar.add(helpMenu);
1037 
1038     this.setJMenuBar(menuBar);
1039 
1040     // popups
1041     lrsPopup = new XJPopupMenu();
1042     LiveMenu lrsMenu = new LiveMenu(LiveMenu.LR);
1043     lrsMenu.setText("New");
1044     lrsPopup.add(lrsMenu);
1045     guiRoots.add(lrsPopup);
1046     guiRoots.add(lrsMenu);
1047 
1048     prsPopup = new XJPopupMenu();
1049     LiveMenu prsMenu = new LiveMenu(LiveMenu.PR);
1050     prsMenu.setText("New");
1051     prsPopup.add(prsMenu);
1052     guiRoots.add(prsPopup);
1053     guiRoots.add(prsMenu);
1054 
1055     dssPopup = new XJPopupMenu();
1056     dssPopup.add(new NewDSAction());
1057     dssPopup.add(new OpenDSAction());
1058     guiRoots.add(dssPopup);
1059 
1060     // TOOLBAR
1061     toolbar = new JToolBar(JToolBar.HORIZONTAL);
1062     toolbar.setFloatable(false);
1063     JButton button = new JButton(new LoadResourceFromFileAction());
1064     button.setToolTipText(button.getText());
1065     button.setText("");
1066     toolbar.add(button);
1067     toolbar.addSeparator();
1068 
1069     JPopupMenu annieMenu = new JPopupMenu();
1070     annieMenu.add(new LoadANNIEWithDefaultsAction());
1071     annieMenu.add(new LoadANNIEWithoutDefaultsAction());
1072     JMenuButton menuButton = new JMenuButton(annieMenu);
1073     menuButton.setIcon(getIcon("annie-application"));
1074     menuButton.setToolTipText("Load ANNIE System");
1075     toolbar.add(menuButton);
1076     toolbar.addSeparator();
1077 
1078     LiveMenu tbNewLRMenu = new LiveMenu(LiveMenu.LR);
1079     menuButton = new JMenuButton(tbNewLRMenu);
1080     menuButton.setToolTipText("New Language Resource");
1081     menuButton.setIcon(getIcon("lrs"));
1082     toolbar.add(menuButton);
1083 
1084     LiveMenu tbNewPRMenu = new LiveMenu(LiveMenu.PR);
1085     menuButton = new JMenuButton(tbNewPRMenu);
1086     menuButton.setToolTipText("New Processing Resource");
1087     menuButton.setIcon(getIcon("prs"));
1088     toolbar.add(menuButton);
1089 
1090     LiveMenu tbNewAppMenu = new LiveMenu(LiveMenu.APP);
1091     menuButton = new JMenuButton(tbNewAppMenu);
1092     menuButton.setToolTipText("New Application");
1093     menuButton.setIcon(getIcon("applications"));
1094     toolbar.add(menuButton);
1095     toolbar.addSeparator();
1096 
1097     JPopupMenu tbDsMenu = new JPopupMenu();
1098     tbDsMenu.add(new NewDSAction());
1099     tbDsMenu.add(new OpenDSAction());
1100     menuButton = new JMenuButton(tbDsMenu);
1101     menuButton.setToolTipText("Datastores");
1102     menuButton.setIcon(getIcon("datastores"));
1103     toolbar.add(menuButton);
1104 
1105     toolbar.addSeparator();
1106     button = new JButton(new ManagePluginsAction());
1107     button.setToolTipText(button.getText());
1108     button.setText("");
1109     toolbar.add(button);
1110     toolbar.addSeparator();
1111     button = new JButton(new NewAnnotDiffAction());
1112     button.setToolTipText(button.getText());
1113     button.setText("");
1114     toolbar.add(button);
1115     toolbar.add(Box.createHorizontalGlue());
1116 
1117     this.getContentPane().add(toolbar, BorderLayout.NORTH);
1118   }
1119 
1120   protected void initListeners(boolean isShellSlacGIU) {
1121     Gate.getCreoleRegister().addCreoleListener(this);
1122 
1123     resourcesTree.addKeyListener(new KeyAdapter() {
1124       public void keyPressed(KeyEvent e) {
1125         if(e.getKeyCode() == KeyEvent.VK_ENTER) {
1126           // shows in the central tabbed pane, the selected resources
1127           // in the resource tree when the Enter key is pressed
1128           (new ShowSelectedResourcesAction()).actionPerformed(null);
1129         else if(e.getKeyCode() == KeyEvent.VK_DELETE) {
1130           // close selected resources from GATE
1131           (new CloseSelectedResourcesAction()).actionPerformed(null);
1132         else if(e.getKeyCode() == KeyEvent.VK_DELETE
1133                && e.getModifiers() == InputEvent.SHIFT_DOWN_MASK) {
1134           // close recursively selected resources from GATE
1135           (new CloseRecursivelySelectedResourcesAction()).actionPerformed(null);
1136         }
1137       }
1138     });
1139 
1140     resourcesTree.addMouseListener(new MouseAdapter() {
1141       public void mousePressed(MouseEvent e) {
1142         TreePath path =
1143           resourcesTree.getClosestPathForLocation(e.getX(), e.getY());
1144         if(e.isPopupTrigger()
1145         && !resourcesTree.isPathSelected(path)) {
1146           // if right click outside the selection then reset selection
1147           resourcesTree.getSelectionModel().setSelectionPath(path);
1148         }
1149         processMouseEvent(e);
1150       }
1151       public void mouseReleased(MouseEvent e) {
1152           processMouseEvent(e);
1153       }
1154       public void mouseClicked(MouseEvent e) {
1155         processMouseEvent(e);
1156       }
1157       protected void processMouseEvent(MouseEvent e){
1158         // where inside the tree?
1159         int x = e.getX();
1160         int y = e.getY();
1161         TreePath path = resourcesTree.getClosestPathForLocation(x, y);
1162         JPopupMenu popup = null;
1163         Handle handle = null;
1164         if(path != null) {
1165           Object value = path.getLastPathComponent();
1166           if(value == resourcesTreeRoot) {
1167             // no default item for this menu
1168           }
1169           else if(value == applicationsRoot) {
1170             appsPopup = new XJPopupMenu();
1171             LiveMenu appsMenu = new LiveMenu(LiveMenu.APP);
1172             appsMenu.setText("New");
1173             appsPopup.add(appsMenu);
1174             guiRoots.add(appsPopup);
1175             guiRoots.add(appsMenu);
1176             appsPopup.add(new XJMenuItem(new LoadResourceFromFileAction(),
1177               MainFrame.this));
1178             Component[] components = new RecentAppsMenu().getMenuComponents();
1179             if (components.length > 0) {
1180               appsPopup.addSeparator();
1181               appsPopup.add("Recent Applications:");
1182             }
1183             for (Component menuItem : components) {
1184                 // add each menu item from the application recent menu
1185                 appsPopup.add(menuItem);
1186             }
1187             popup = appsPopup;
1188           }
1189           else if(value == languageResourcesRoot) {
1190             popup = lrsPopup;
1191           }
1192           else if(value == processingResourcesRoot) {
1193             popup = prsPopup;
1194           }
1195           else if(value == datastoresRoot) {
1196             popup = dssPopup;
1197           }
1198           else {
1199             value = ((DefaultMutableTreeNode)value).getUserObject();
1200             if(value instanceof Handle) {
1201               handle = (Handle)value;
1202               fileChooser.setResource(handle.getTarget().getClass().getName());
1203               if(e.isPopupTrigger()) { popup = handle.getPopup()}
1204             }
1205           }
1206         }
1207         // popup menu
1208         if(e.isPopupTrigger()) {
1209           if(resourcesTree.getSelectionCount() 1) {
1210             // multiple selection in tree
1211             popup = new XJPopupMenu();
1212 
1213             // add a close all action
1214             popup.add(new XJMenuItem(new CloseSelectedResourcesAction(),
1215                     MainFrame.this));
1216 
1217             // add a close recursively all action
1218             TreePath[] selectedPaths = resourcesTree.getSelectionPaths();
1219             for(TreePath selectedPath : selectedPaths) {
1220               Object userObject = ((DefaultMutableTreeNode)
1221                 selectedPath.getLastPathComponent()).getUserObject();
1222               if(userObject instanceof NameBearerHandle
1223                 && ((NameBearerHandle)userObject).getTarget()
1224                   instanceof Controller) {
1225                 // there is at least one application
1226                 popup.add(new XJMenuItem(new
1227                   CloseRecursivelySelectedResourcesAction(), MainFrame.this));
1228                 break;
1229               }
1230             }
1231 
1232             // add a show all action
1233             selectedPaths = resourcesTree.getSelectionPaths();
1234             for(TreePath selectedPath : selectedPaths) {
1235               Object userObject = ((DefaultMutableTreeNode)
1236                 selectedPath.getLastPathComponent()).getUserObject();
1237               if (userObject instanceof Handle
1238               && ( ((Handle)userObject).getLargeView() == null
1239                 || (mainTabbedPane.indexOfComponent(
1240                   ((Handle)userObject).getLargeView()) == -1)) ) {
1241                 // there is at least one resource not shown
1242                 popup.add(new XJMenuItem(new ShowSelectedResourcesAction(),
1243                   MainFrame.this));
1244                 break;
1245               }
1246             }
1247 
1248             // add a hide all action
1249             selectedPaths = resourcesTree.getSelectionPaths();
1250             for(TreePath selectedPath : selectedPaths) {
1251               Object userObject = ((DefaultMutableTreeNode)
1252                 selectedPath.getLastPathComponent()).getUserObject();
1253               if (userObject instanceof Handle
1254               && ((Handle)userObject).viewsBuilt()
1255               && ((Handle)userObject).getLargeView() != null
1256               && (mainTabbedPane.indexOfComponent(
1257                 ((Handle)userObject).getLargeView()) != -1)) {
1258                 // there is at least one resource shown
1259                 popup.add(new XJMenuItem(new CloseViewsForSelectedResourcesAction(),
1260                   MainFrame.this));
1261                 break;
1262               }
1263             }
1264 
1265             popup.show(resourcesTree, e.getX(), e.getY());
1266           }
1267           else if(popup != null) {
1268             if(handle != null) {
1269 
1270               // add a close action
1271               if(handle instanceof NameBearerHandle) {
1272                 popup.insert(new XJMenuItem(((NameBearerHandle)handle)
1273                         .getCloseAction(), MainFrame.this)0);
1274               }
1275 
1276               // if application then add a close recursively action
1277               if(handle instanceof NameBearerHandle
1278               && handle.getTarget() instanceof Controller) {
1279                 popup.insert(new XJMenuItem(((NameBearerHandle)handle)
1280                   .getCloseRecursivelyAction(), MainFrame.this)1);
1281               }
1282 
1283               // add a show/hide action
1284               if (handle.viewsBuilt() &&
1285                   handle.getLargeView() != null
1286                   && (mainTabbedPane.indexOfComponent(
1287                           handle.getLargeView()) != -1)) {
1288                popup.insert(new XJMenuItem(new CloseViewAction(handle),
1289                  MainFrame.this)2);
1290               else {
1291                 popup.insert(new XJMenuItem(new ShowResourceAction(handle),
1292                   MainFrame.this)2);
1293               }
1294 
1295               // add a rename action
1296               popup.insert(new XJMenuItem(new RenameResourceAction(path),
1297                 MainFrame.this)3);
1298 
1299               // add a help action
1300               if(handle instanceof NameBearerHandle) {
1301                 popup.insert(new XJMenuItem(new HelpOnItemTreeAction(
1302                   (NameBearerHandle)handle), MainFrame.this)4);
1303               }
1304             }
1305 
1306             popup.show(resourcesTree, e.getX(), e.getY());
1307           }
1308         }
1309         else if(e.getID() == MouseEvent.MOUSE_CLICKED
1310              && e.getClickCount() == 2
1311              && handle != null) {
1312             // double click - show the resource
1313             select(handle);
1314         }
1315       }
1316     });
1317 
1318     resourcesTree.addTreeSelectionListener(new TreeSelectionListener() {
1319       public void valueChanged(TreeSelectionEvent e) {
1320         if (!Gate.getUserConfig().getBoolean(
1321           MainFrame.class.getName()+".treeselectview")) {
1322           return;
1323         }
1324         // synchronise the selected tabbed pane with
1325         // the resource tree selection
1326         if (resourcesTree.getSelectionPaths() != null
1327          && resourcesTree.getSelectionPaths().length == 1) {
1328           Object value = e.getPath().getLastPathComponent();
1329           Object object = ((DefaultMutableTreeNode)value).getUserObject();
1330           if (object instanceof Handle
1331               && ((Handle)object).viewsBuilt()
1332               && (mainTabbedPane.indexOfComponent(
1333                       ((Handle)object).getLargeView()) != -1)) {
1334             select((Handle)object);
1335           }
1336         }
1337       }
1338     });
1339 
1340     // define keystrokes action bindings at the level of the main window
1341     InputMap inputMap = ((JComponent)this.getContentPane()).
1342       getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1343     inputMap.put(KeyStroke.getKeyStroke("control F4")"Close resource");
1344     inputMap.put(KeyStroke.getKeyStroke("shift F4")"Close recursively");
1345     inputMap.put(KeyStroke.getKeyStroke("control H")"Hide");
1346     inputMap.put(KeyStroke.getKeyStroke("control shift H")"Hide all");
1347     inputMap.put(KeyStroke.getKeyStroke("control S")"Save As XML");
1348 
1349     // add the support of the context menu key in tables and trees
1350     // TODO: remove when Swing will take care of the context menu key
1351     if (inputMap.get(KeyStroke.getKeyStroke("CONTEXT_MENU")) == null) {
1352       inputMap.put(KeyStroke.getKeyStroke("CONTEXT_MENU")"Show context menu");
1353     }
1354     ActionMap actionMap =
1355       ((JComponent)instance.getContentPane()).getActionMap();
1356     actionMap.put("Show context menu"new AbstractAction() {
1357       public void actionPerformed(ActionEvent e) {
1358         KeyboardFocusManager focusManager =
1359           KeyboardFocusManager.getCurrentKeyboardFocusManager();
1360         // get the current focused component
1361         Component focusedComponent = focusManager.getFocusOwner();
1362         if (focusedComponent != null) {
1363           Point menuLocation = null;
1364           Rectangle selectionRectangle = null;
1365           if (focusedComponent instanceof JTable
1366           && ((JTable)focusedComponent).getSelectedRowCount() 0) {
1367             // selection in a JTable
1368             JTable table = (JTable)focusedComponent;
1369             selectionRectangle = table.getCellRect(
1370               table.getSelectionModel().getLeadSelectionIndex(),
1371               table.convertColumnIndexToView(table.getSelectedColumn()),
1372               false);
1373           else if (focusedComponent instanceof JTree
1374           && ((JTree)focusedComponent).getSelectionCount() 0) {
1375             // selection in a JTree
1376             JTree tree = (JTree)focusedComponent;
1377             selectionRectangle = tree.getRowBounds(
1378               tree.getSelectionModel().getLeadSelectionRow());
1379           else {
1380             // for other component set the menu location at the top left corner
1381             menuLocation = new Point(focusedComponent.getX()-1,
1382                                      focusedComponent.getY()-1);
1383           }
1384           if (menuLocation == null) {
1385             // menu location at the bottom left of the JTable or JTree
1386             menuLocation = new Point(
1387               new Double(selectionRectangle.getMinX()+1).intValue(),
1388               new Double(selectionRectangle.getMaxY()-1).intValue());
1389           }
1390 
1391           // generate a right/button 3/popup menu mouse click
1392           focusedComponent.dispatchEvent(
1393             new MouseEvent(focusedComponent, MouseEvent.MOUSE_PRESSED,
1394               e.getWhen(), MouseEvent.BUTTON3_DOWN_MASK,
1395               menuLocation.x, menuLocation.y,
1396               1, true, MouseEvent.BUTTON3));
1397         }
1398       }
1399     });
1400 
1401     mainTabbedPane.getModel().addChangeListener(new ChangeListener() {
1402       public void stateChanged(ChangeEvent e) {
1403         // find the handle in the resources tree for the main view
1404         JComponent largeView =
1405           (JComponent)mainTabbedPane.getSelectedComponent();
1406         Enumeration nodesEnum = resourcesTreeRoot.preorderEnumeration();
1407         boolean done = false;
1408         DefaultMutableTreeNode node = resourcesTreeRoot;
1409         while(!done && nodesEnum.hasMoreElements()) {
1410           node = (DefaultMutableTreeNode)nodesEnum.nextElement();
1411           done =
1412             node.getUserObject() instanceof Handle
1413               && ((Handle)node.getUserObject()).viewsBuilt()
1414               && ((Handle)node.getUserObject()).getLargeView() == largeView;
1415         }
1416         ActionMap actionMap =
1417           ((JComponent)instance.getContentPane()).getActionMap();
1418         if(done) {
1419           Handle handle = (Handle)node.getUserObject();
1420           if (Gate.getUserConfig().getBoolean(
1421             MainFrame.class.getName()+".viewselecttree")) {
1422             // synchronise the selection in the tabbed pane with
1423             // the one in the resources tree
1424             TreePath nodePath = new TreePath(node.getPath());
1425             resourcesTree.setSelectionPath(nodePath);
1426             resourcesTree.scrollPathToVisible(nodePath);
1427           }
1428           lowerScroll.getViewport().setView(handle.getSmallView());
1429 
1430           // redefine MainFrame actionMaps for the selected tab
1431           JComponent resource =
1432             (JComponent)mainTabbedPane.getSelectedComponent();
1433           actionMap.put("Close resource",
1434             resource.getActionMap().get("Close resource"));
1435           actionMap.put("Close recursively",
1436             resource.getActionMap().get("Close recursively"));
1437           actionMap.put("Hide"new CloseViewAction(handle));
1438           actionMap.put("Hide all"new HideAllAction());
1439           actionMap.put("Save As XML",
1440             resource.getActionMap().get("Save As XML"));
1441         }
1442         else {
1443           // the selected item is not a resource (maybe the log area?)
1444           lowerScroll.getViewport().setView(null);
1445           // disabled actions on the selected tabbed pane
1446           actionMap.put("Close resource"null);
1447           actionMap.put("Close recursively"null);
1448           actionMap.put("Hide"null);
1449           actionMap.put("Hide all"null);
1450           actionMap.put("Save As XML"null);
1451         }
1452       }
1453     });
1454 
1455     mainTabbedPane.addMouseListener(new MouseAdapter() {
1456       public void mousePressed(MouseEvent e) {
1457         processMouseEvent(e);
1458       }
1459       public void mouseReleased(MouseEvent e) {
1460         processMouseEvent(e);
1461       }
1462       protected void processMouseEvent(MouseEvent e){
1463         if(e.isPopupTrigger()) {
1464           int index = mainTabbedPane.getIndexAt(e.getPoint());
1465           if(index != -1) {
1466             JComponent view = (JComponent)mainTabbedPane.getComponentAt(index);
1467             Enumeration nodesEnum = resourcesTreeRoot.preorderEnumeration();
1468             boolean done = false;
1469             DefaultMutableTreeNode node = resourcesTreeRoot;
1470             while(!done && nodesEnum.hasMoreElements()) {
1471               node = (DefaultMutableTreeNode)nodesEnum.nextElement();
1472               done = node.getUserObject() instanceof Handle
1473                   && ((Handle)node.getUserObject()).viewsBuilt()
1474                   && ((Handle)node.getUserObject()).getLargeView() == view;
1475             }
1476             if(done) {
1477               Handle handle = (Handle)node.getUserObject();
1478               JPopupMenu popup = handle.getPopup();
1479 
1480               // add a hide action
1481               CloseViewAction cva = new CloseViewAction(handle);
1482               XJMenuItem menuItem = new XJMenuItem(cva, MainFrame.this);
1483               popup.insert(menuItem, 0);
1484 
1485               // add a hide all action
1486               if (mainTabbedPane.getTabCount() 2) {
1487                 HideAllAction haa = new HideAllAction();
1488                 menuItem = new XJMenuItem(haa, MainFrame.this);
1489                 popup.insert(menuItem, 1);
1490               }
1491 
1492               popup.show(mainTabbedPane, e.getX(), e.getY());
1493             }
1494           }
1495         }
1496       }
1497     });
1498 
1499     addComponentListener(new ComponentAdapter() {
1500       public void componentShown(ComponentEvent e) {
1501         leftSplit.setDividerLocation(0.7);
1502       }
1503       public void componentResized(ComponentEvent e) {
1504         // resize proportionally the status bar elements
1505         int width = MainFrame.this.getWidth();
1506         statusBar.setPreferredSize(new Dimension(width*65/100,
1507           statusBar.getPreferredSize().height));
1508         progressBar.setPreferredSize(new Dimension(width*20/100,
1509           progressBar.getPreferredSize().height));
1510         progressBar.setMinimumSize(new Dimension(800));
1511         globalProgressBar.setPreferredSize(new Dimension(width*10/100,
1512           globalProgressBar.getPreferredSize().height));
1513         globalProgressBar.setMinimumSize(new Dimension(800));
1514       }
1515     });
1516 
1517     if(isShellSlacGIU) {
1518       mainSplit.setDividerSize(0);
1519       mainSplit.getTopComponent().setVisible(false);
1520       mainSplit.getTopComponent().addComponentListener(new ComponentAdapter() {
1521         public void componentHidden(ComponentEvent e) {
1522         }
1523 
1524         public void componentMoved(ComponentEvent e) {
1525           mainSplit.setDividerLocation(0);
1526         }
1527 
1528         public void componentResized(ComponentEvent e) {
1529           mainSplit.setDividerLocation(0);
1530         }
1531 
1532         public void componentShown(ComponentEvent e) {
1533           mainSplit.setDividerLocation(0);
1534         }
1535       });
1536     // if
1537 
1538     // blink the messages tab when new information is displayed
1539     logArea.getDocument().addDocumentListener(
1540       new javax.swing.event.DocumentListener() {
1541         public void insertUpdate(javax.swing.event.DocumentEvent e) {
1542           changeOccured();
1543         }
1544 
1545         public void removeUpdate(javax.swing.event.DocumentEvent e) {
1546           changeOccured();
1547         }
1548 
1549         public void changedUpdate(javax.swing.event.DocumentEvent e) {
1550         }
1551 
1552         protected void changeOccured() {
1553           logHighlighter.highlight();
1554         }
1555       });
1556 
1557     logArea.addPropertyChangeListener("document"new PropertyChangeListener() {
1558       public void propertyChange(PropertyChangeEvent evt) {
1559         // add the document listener
1560         logArea.getDocument().addDocumentListener(
1561           new javax.swing.event.DocumentListener() {
1562             public void insertUpdate(javax.swing.event.DocumentEvent e) {
1563               changeOccured();
1564             }
1565 
1566             public void removeUpdate(javax.swing.event.DocumentEvent e) {
1567               changeOccured();
1568             }
1569 
1570             public void changedUpdate(javax.swing.event.DocumentEvent e) {
1571               changeOccured();
1572             }
1573 
1574             protected void changeOccured() {
1575               logHighlighter.highlight();
1576             }
1577           });
1578       }
1579     });
1580 
1581     Gate.listeners.put("gate.event.StatusListener", MainFrame.this);
1582     Gate.listeners.put("gate.event.ProgressListener", MainFrame.this);
1583     if(Gate.runningOnMac()) {
1584       // mac-specific initialisation
1585       initMacListeners();
1586     }
1587   }// protected void initListeners()
1588 
1589   /**
1590    * Set up the handlers to support the Macintosh Application menu. This
1591    * makes the About, Quit and Preferences menu items map to their
1592    * equivalents in GATE. If an exception occurs during this process we
1593    * print a warning.
1594    */
1595   protected void initMacListeners() {
1596     // What this method effectively does is:
1597     //
1598     // com.apple.eawt.Application app = Application.getApplication();
1599     // app.addApplicationListener(new ApplicationAdapter() {
1600     // public void handleAbout(ApplicationEvent e) {
1601     // e.setHandled(true);
1602     // new HelpAboutAction().actionPerformed(null);
1603     // }
1604     // public void handleQuit(ApplicationEvent e) {
1605     // e.setHandled(false);
1606     // new ExitGateAction().actionPerformed(null);
1607     // }
1608     // public void handlePreferences(ApplicationEvent e) {
1609     // e.setHandled(true);
1610     // optionsDialog.showDialog();
1611     // optionsDialog.dispose();
1612     // }
1613     // });
1614     //
1615     // app.setEnabledPreferencesMenu(true);
1616     //
1617     // except that it does it all by reflection so as not to
1618     // compile-time
1619     // depend on Apple classes.
1620     try {
1621       // load the Apple classes
1622       final Class eawtApplicationClass =
1623         Gate.getClassLoader().loadClass("com.apple.eawt.Application");
1624       final Class eawtApplicationListenerInterface =
1625         Gate.getClassLoader().loadClass("com.apple.eawt.ApplicationListener");
1626       final Class eawtApplicationEventClass =
1627         Gate.getClassLoader().loadClass("com.apple.eawt.ApplicationEvent");
1628 
1629       // method used in the InvocationHandler
1630       final Method appEventSetHandledMethod =
1631         eawtApplicationEventClass.getMethod("setHandled"boolean.class);
1632 
1633       // Invocation handler used to process Apple application events
1634       InvocationHandler handler = new InvocationHandler() {
1635         private Action aboutAction = new HelpAboutAction();
1636 
1637         private Action exitAction = new ExitGateAction();
1638 
1639         public Object invoke(Object proxy, Method method, Object[] args)
1640           throws Throwable {
1641           Object appEvent = args[0];
1642           if("handleAbout".equals(method.getName())) {
1643             appEventSetHandledMethod.invoke(appEvent, Boolean.TRUE);
1644             aboutAction.actionPerformed(null);
1645           }
1646           else if("handleQuit".equals(method.getName())) {
1647             appEventSetHandledMethod.invoke(appEvent, Boolean.FALSE);
1648             exitAction.actionPerformed(null);
1649           }
1650           else if("handlePreferences".equals(method.getName())) {
1651             appEventSetHandledMethod.invoke(appEvent, Boolean.TRUE);
1652             optionsDialog.showDialog();
1653             optionsDialog.dispose();
1654           }
1655 
1656           return null;
1657         }
1658       };
1659 
1660       // Create an ApplicationListener proxy instance
1661       Object applicationListenerObject =
1662         Proxy.newProxyInstance(Gate.getClassLoader(),
1663           new Class[]{eawtApplicationListenerInterface}, handler);
1664 
1665       // get hold of the Application object
1666       Method getApplicationMethod =
1667         eawtApplicationClass.getMethod("getApplication");
1668       Object applicationObject = getApplicationMethod.invoke(null);
1669 
1670       // enable the preferences menu item
1671       Method setEnabledPreferencesMenuMethod =
1672         eawtApplicationClass.getMethod("setEnabledPreferencesMenu",
1673           boolean.class);
1674       setEnabledPreferencesMenuMethod.invoke(applicationObject, Boolean.TRUE);
1675 
1676       // Register our proxy instance as an ApplicationListener
1677       Method addApplicationListenerMethod =
1678         eawtApplicationClass.getMethod("addApplicationListener",
1679           eawtApplicationListenerInterface);
1680       addApplicationListenerMethod.invoke(applicationObject,
1681         applicationListenerObject);
1682     }
1683     catch(Throwable error) {
1684       // oh well, we tried
1685       String message =
1686         "There was a problem setting up the Mac "
1687         "application\nmenu.  Your options/session will not be saved if "
1688         "you exit\nwith \u2318Q, use the close button at the top-left"
1689         "corner\nof this window instead.";
1690       alertButton.setAction(new AlertAction(error, message, null));
1691     }
1692   }
1693 
1694   public void progressChanged(int i) {
1695     // progressBar.setStringPainted(true);
1696     int oldValue = progressBar.getValue();
1697     // if((!stopAction.isEnabled()) &&
1698     // (Gate.getExecutable() != null)){
1699     // stopAction.setEnabled(true);
1700     // SwingUtilities.invokeLater(new Runnable(){
1701     // public void run(){
1702     // southBox.add(stopBtn, 0);
1703     // }
1704     // });
1705     // }
1706     if(!animator.isActive()) animator.activate();
1707     if(oldValue != i) {
1708       SwingUtilities.invokeLater(new ProgressBarUpdater(i));
1709     }
1710   }
1711 
1712   /**
1713    * Called when the process is finished.
1714    *
1715    */
1716   public void processFinished() {
1717     // progressBar.setStringPainted(false);
1718     // if(stopAction.isEnabled()){
1719     // stopAction.setEnabled(false);
1720     // SwingUtilities.invokeLater(new Runnable(){
1721     // public void run(){
1722     // southBox.remove(stopBtn);
1723     // }
1724     // });
1725     // }
1726     SwingUtilities.invokeLater(new ProgressBarUpdater(0));
1727     SwingUtilities.invokeLater(new Runnable() { public void run() {
1728       globalProgressBar.setVisible(false);
1729     }});
1730     animator.deactivate();
1731   }
1732   
1733   /**
1734    * Regular expression pattern for the "Start running" message.
1735    */
1736   private static final Pattern START_RUNNING_PATTERN =
1737     Pattern.compile("Start running .* on (\\d+) documents?");
1738 
1739   public void statusChanged(String text) {
1740     SwingUtilities.invokeLater(new StatusBarUpdater(text));
1741     if (text != null) {
1742       Matcher m = START_RUNNING_PATTERN.matcher(text);
1743       if (m.matches()) {
1744         // get the corpus size from the status text
1745         final int corpusSize = Integer.valueOf(m.group(1));
1746         SwingUtilities.invokeLater(new Runnable() { public void run() {
1747           // initialise the progress bar
1748           globalProgressBar.setMaximum(corpusSize);
1749           globalProgressBar.setValue(0);
1750           globalProgressBar.setString("0/" + corpusSize);
1751           globalProgressBar.setVisible(true);
1752         }});
1753       else if (text.startsWith("Finished running ")) {
1754         SwingUtilities.invokeLater(new Runnable() { public void run() {
1755           // update the progress bar with one document processed
1756           globalProgressBar.setValue(globalProgressBar.getValue() 1);
1757           globalProgressBar.setString(globalProgressBar.getValue() "/"
1758             + globalProgressBar.getMaximum());
1759         }});
1760       }
1761     }
1762   }
1763 
1764   public void resourceLoaded(CreoleEvent e) {
1765     final Resource res = e.getResource();
1766     if(Gate.getHiddenAttribute(res.getFeatures())
1767       || res instanceof VisualResourcereturn;
1768     SwingUtilities.invokeLater(new Runnable() {
1769       public void run() {
1770         NameBearerHandle handle = new NameBearerHandle(res, MainFrame.this);
1771         DefaultMutableTreeNode node = new DefaultMutableTreeNode(handle, false);
1772         if(res instanceof Controller) {
1773           resourcesTreeModel.insertNodeInto(node, applicationsRoot, 0);
1774         else if(res instanceof ProcessingResource) {
1775           resourcesTreeModel.insertNodeInto(node, processingResourcesRoot, 0);
1776         }
1777         else if(res instanceof LanguageResource) {
1778           resourcesTreeModel.insertNodeInto(node, languageResourcesRoot, 0);
1779         }
1780 
1781         handle.addProgressListener(MainFrame.this);
1782         handle.addStatusListener(MainFrame.this);
1783       }
1784     });
1785 
1786     // JPopupMenu popup = handle.getPopup();
1787     //
1788     // // Create a CloseViewAction and a menu item based on it
1789     // CloseViewAction cva = new CloseViewAction(handle);
1790     // XJMenuItem menuItem = new XJMenuItem(cva, this);
1791     // // Add an accelerator ATL+F4 for this action
1792     // menuItem.setAccelerator(KeyStroke.getKeyStroke(
1793     // KeyEvent.VK_H, ActionEvent.CTRL_MASK));
1794     // popup.insert(menuItem, 1);
1795     // popup.insert(new JPopupMenu.Separator(), 2);
1796     //
1797     // popup.insert(new XJMenuItem(
1798     // new RenameResourceAction(
1799     // new TreePath(resourcesTreeModel.getPathToRoot(node))),
1800     // MainFrame.this) , 3);
1801     //
1802     // // Put the action command in the component's action map
1803     // if (handle.getLargeView() != null)
1804     // handle.getLargeView().getActionMap().put("Hide current
1805     // view",cva);
1806     //
1807   }// resourceLoaded();
1808 
1809   public void resourceUnloaded(CreoleEvent e) {
1810     final Resource res = e.getResource();
1811     if(Gate.getHiddenAttribute(res.getFeatures())) return;
1812     Runnable runner = new Runnable() {
1813       public void run() {
1814         DefaultMutableTreeNode node;
1815         DefaultMutableTreeNode parent = null;
1816         if(res instanceof Controller) {
1817           parent = applicationsRoot;
1818         }else if(res instanceof ProcessingResource) {
1819           parent = processingResourcesRoot;
1820         }
1821         else if(res instanceof LanguageResource) {
1822           parent = languageResourcesRoot;
1823         }
1824         if(parent != null) {
1825           Enumeration children = parent.children();
1826           while(children.hasMoreElements()) {
1827             node = (DefaultMutableTreeNode)children.nextElement();
1828             if(((NameBearerHandle)node.getUserObject()).getTarget() == res) {
1829               resourcesTreeModel.removeNodeFromParent(node);
1830               Handle handle = (Handle)node.getUserObject();
1831               if(handle.viewsBuilt()) {
1832                 if(mainTabbedPane.indexOfComponent(handle.getLargeView()) != -1)
1833                   mainTabbedPane.remove(handle.getLargeView());
1834                 if(lowerScroll.getViewport().getView() == handle.getSmallView())
1835                   lowerScroll.getViewport().setView(null);
1836               }
1837               handle.cleanup();
1838               return;
1839             }
1840           }
1841         }
1842       }
1843     };
1844     SwingUtilities.invokeLater(runner);
1845   }
1846 
1847   /** Called when a {@link gate.DataStore} has been opened */
1848   public void datastoreOpened(CreoleEvent e) {
1849     DataStore ds = e.getDatastore();
1850     if(ds.getName() == null || ds.getName().length() == 0){
1851       String name = ds.getStorageUrl();
1852       StringBuilder nameBuilder = new StringBuilder();
1853       //quick and dirty FSA
1854       int state = 0;
1855       for(int i = name.length() -1; i >= && state != ; i--){
1856         char currentChar = name.charAt(i);
1857         switch (state) {
1858           case 0:
1859             //consuming slashes at the end
1860             if(currentChar == '/'){
1861               //consume
1862             }else{
1863               //we got the first non-slash char
1864               state = 1;
1865               nameBuilder.insert(0, currentChar);
1866             }
1867             break;
1868           case 1:
1869             //eating up name chars
1870             if(currentChar == '/'){
1871               //we're done!
1872               state = 2;
1873             }else{
1874               //we got a non-slash char
1875               nameBuilder.insert(0, currentChar);
1876             }
1877             break;
1878           default:
1879             throw new LuckyException("A phanthom state of things!");
1880         }
1881       }
1882       if(nameBuilder.length() 0name = nameBuilder.toString();
1883       ds.setName(name);
1884     }
1885 
1886     NameBearerHandle handle = new NameBearerHandle(ds, MainFrame.this);
1887     DefaultMutableTreeNode node = new DefaultMutableTreeNode(handle, false);
1888     resourcesTreeModel.insertNodeInto(node, datastoresRoot, 0);
1889     handle.addProgressListener(MainFrame.this);
1890     handle.addStatusListener(MainFrame.this);
1891 
1892     // JPopupMenu popup = handle.getPopup();
1893     // popup.addSeparator();
1894     // // Create a CloseViewAction and a menu item based on it
1895     // CloseViewAction cva = new CloseViewAction(handle);
1896     // XJMenuItem menuItem = new XJMenuItem(cva, this);
1897     // // Add an accelerator ATL+F4 for this action
1898     // menuItem.setAccelerator(KeyStroke.getKeyStroke(
1899     // KeyEvent.VK_H, ActionEvent.CTRL_MASK));
1900     // popup.add(menuItem);
1901     // // Put the action command in the component's action map
1902     // if (handle.getLargeView() != null)
1903     // handle.getLargeView().getActionMap().put("Hide current
1904     // view",cva);
1905   }// datastoreOpened();
1906 
1907   /** Called when a {@link gate.DataStore} has been created */
1908   public void datastoreCreated(CreoleEvent e) {
1909     datastoreOpened(e);
1910   }
1911 
1912   /** Called when a {@link gate.DataStore} has been closed */
1913   public void datastoreClosed(CreoleEvent e) {
1914     DataStore ds = e.getDatastore();
1915     DefaultMutableTreeNode node;
1916     DefaultMutableTreeNode parent = datastoresRoot;
1917     if(parent != null) {
1918       Enumeration children = parent.children();
1919       while(children.hasMoreElements()) {
1920         node = (DefaultMutableTreeNode)children.nextElement();
1921         if(((NameBearerHandle)node.getUserObject()).getTarget() == ds) {
1922           resourcesTreeModel.removeNodeFromParent(node);
1923           NameBearerHandle handle = (NameBearerHandle)node.getUserObject();
1924 
1925           if(handle.viewsBuilt()
1926             && mainTabbedPane.indexOfComponent(handle.getLargeView()) != -1) {
1927             mainTabbedPane.remove(handle.getLargeView());
1928           }
1929           if(lowerScroll.getViewport().getView() == handle.getSmallView()) {
1930             lowerScroll.getViewport().setView(null);
1931           }
1932           return;
1933         }
1934       }
1935     }
1936   }
1937 
1938   public void resourceRenamed(Resource resource, String oldName, String newName) {
1939     //first find the handle for the renamed resource
1940     Handle handle = findHandleForResource(resource);
1941     if(handle != null){
1942       //next see if there is a tab for this resource and rename it
1943       for(int i = 0; i < mainTabbedPane.getTabCount(); i++) {
1944         if(mainTabbedPane.getTitleAt(i).equals(oldName&&
1945            mainTabbedPane.getComponentAt(i== handle.getLargeView()) {
1946           mainTabbedPane.setTitleAt(i, newName);
1947           return;
1948         }
1949       }
1950     }
1951   }
1952 
1953   /**
1954    * Overridden so we can exit when window is closed
1955    */
1956   protected void processWindowEvent(WindowEvent e) {
1957     if(e.getID() == WindowEvent.WINDOW_CLOSING) {
1958       new ExitGateAction().actionPerformed(null);
1959     }
1960     super.processWindowEvent(e);
1961   }// processWindowEvent(WindowEvent e)
1962 
1963   /**
1964    * Returns the listeners map, a map that holds all the listeners that
1965    * are singletons (e.g. the status listener that updates the status
1966    * bar on the main frame or the progress listener that updates the
1967    * progress bar on the main frame). The keys used are the class names
1968    * of the listener interface and the values are the actual listeners
1969    * (e.g "gate.event.StatusListener" -> this). The returned map is the
1970    * actual data member used to store the listeners so any changes in
1971    * this map will be visible to everyone.
1972    @return the listeners map
1973    @deprecated Use {@link Gate#getListeners()} instead
1974    */
1975   public static java.util.Map<String, EventListener> getListeners() {
1976     return Gate.getListeners();
1977   }
1978 
1979   public static java.util.Collection<Component> getGuiRoots() {
1980     return guiRoots;
1981   }
1982 
1983   /**
1984    * This method will lock all input to the gui by means of a modal
1985    * dialog. If Gate is not currently running in GUI mode this call will
1986    * be ignored. A call to this method while the GUI is locked will
1987    * cause the GUI to be unlocked and then locked again with the new
1988    * message. If a message is provided it will show in the dialog.
1989    *
1990    @param message the message to be displayed while the GUI is locked
1991    */
1992   public synchronized static void lockGUI(final String message) {
1993     // check whether GUI is up
1994     if(getGuiRoots() == null || getGuiRoots().isEmpty()) return;
1995     // if the GUI is locked unlock it so we can show the new message
1996     unlockGUI();
1997 
1998     // this call needs to return so we'll show the dialog from a
1999     // different thread
2000     // the Swing thread sounds good for that
2001     SwingUtilities.invokeLater(new Runnable() {
2002       public void run() {
2003      // build the dialog contents
2004         Object[] options = new Object[]{new JButton(new StopAction())};
2005         JOptionPane pane =
2006           new JOptionPane(message, JOptionPane.WARNING_MESSAGE,
2007             JOptionPane.DEFAULT_OPTION, null, options, null);
2008 
2009         // build the dialog
2010         Component parentComp = (Component)((ArrayList)getGuiRoots()).get(0);
2011         JDialog dialog;
2012         Window parentWindow;
2013         if(parentComp instanceof Window)
2014           parentWindow = (Window)parentComp;
2015         else parentWindow = SwingUtilities.getWindowAncestor(parentComp);
2016         if(parentWindow instanceof Frame) {
2017           dialog = new JDialog((Frame)parentWindow, "Please wait"true) {
2018             private static final long serialVersionUID = 1L;
2019             protected void processWindowEvent(WindowEvent e) {
2020               if(e.getID() == WindowEvent.WINDOW_CLOSING) {
2021                 getToolkit().beep();
2022               }
2023             }
2024           };
2025         }
2026         else if(parentWindow instanceof Dialog) {
2027           dialog = new JDialog((Dialog)parentWindow, "Please wait"true) {
2028             private static final long serialVersionUID = 1L;
2029             protected void processWindowEvent(WindowEvent e) {
2030               if(e.getID() == WindowEvent.WINDOW_CLOSING) {
2031                 getToolkit().beep();
2032               }
2033             }
2034           };
2035         }
2036         else {
2037           dialog = new JDialog(JOptionPane.getRootFrame()"Please wait"true) {
2038             private static final long serialVersionUID = 1L;
2039             protected void processWindowEvent(WindowEvent e) {
2040               if(e.getID() == WindowEvent.WINDOW_CLOSING) {
2041                 getToolkit().beep();
2042               }
2043             }
2044           };
2045         }
2046         dialog.getContentPane().setLayout(new BorderLayout());
2047         dialog.getContentPane().add(pane, BorderLayout.CENTER);
2048         dialog.pack();
2049         dialog.setLocationRelativeTo(parentComp);
2050         dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
2051         guiLock = dialog;
2052 
2053         guiLock.setVisible(true);
2054       }
2055     });
2056 
2057     // this call should not return until the dialog is up to ensure
2058     // proper
2059     // sequentiality for lock - unlock calls
2060     while(guiLock == null || !guiLock.isShowing()) {
2061       try {
2062         Thread.sleep(100);
2063       }
2064       catch(InterruptedException ie) {
2065         log.debug("Interrupted sleep when the GUI is locked.", ie);
2066       }
2067     }
2068   }
2069 
2070   public synchronized static void unlockGUI() {
2071     // check whether GUI is up
2072     if(getGuiRoots() == null || getGuiRoots().isEmpty()) return;
2073 
2074     if(guiLock != null) {
2075       guiLock.setVisible(false);
2076       // completely dispose the dialog (causes it to disappear even if
2077       // displayed on a non-visible virtual display on Linux)
2078       // fix for bug 1369096
2079       // (http://sourceforge.net/tracker/index.php?func=detail&aid=1369096&group_id=143829&atid=756796)
2080       guiLock.dispose();
2081     }
2082     guiLock = null;
2083   }
2084 
2085   /** Flag to protect Frame title to be changed */
2086   private boolean titleChangable = false;
2087 
2088   public void setTitleChangable(boolean isChangable) {
2089     titleChangable = isChangable;
2090   // setTitleChangable(boolean isChangable)
2091 
2092   /** Override to avoid Protege to change Frame title */
2093   public synchronized void setTitle(String title) {
2094     if(titleChangable) {
2095       super.setTitle(title);
2096     // if
2097   // setTitle(String title)
2098 
2099   /**
2100    * Method is used in NewDSAction
2101    @return the new datastore or null if an error occurs
2102    */
2103   protected DataStore createSerialDataStore() {
2104     DataStore ds = null;
2105 
2106     // get the URL (a file in this case)
2107     fileChooser.setDialogTitle("Please create a new empty directory");
2108     fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2109     fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
2110     fileChooser.setResource("gate.persist.SerialDataStore");
2111     if(fileChooser.showOpenDialog(MainFrame.this)
2112       == JFileChooser.APPROVE_OPTION) {
2113       try {
2114         URL dsURL = fileChooser.getSelectedFile().toURI().toURL();
2115         ds =
2116           Factory.createDataStore("gate.persist.SerialDataStore", dsURL
2117             .toExternalForm());
2118       }
2119       catch(MalformedURLException mue) {
2120         JOptionPane.showMessageDialog(MainFrame.this,
2121           "Invalid location for the datastore\n " + mue.toString()"GATE",
2122           JOptionPane.ERROR_MESSAGE);
2123       }
2124       catch(PersistenceException pe) {
2125         JOptionPane.showMessageDialog(MainFrame.this,
2126           "Datastore creation error!\n " + pe.toString()"GATE",
2127           JOptionPane.ERROR_MESSAGE);
2128       // catch
2129     // if
2130 
2131     return ds;
2132   // createSerialDataStore()
2133 
2134   /**
2135    * Method is used in OpenDSAction
2136    @return the opened datastore or null if an error occurs
2137    */
2138   protected DataStore openSerialDataStore() {
2139     DataStore ds = null;
2140 
2141     // get the URL (a file in this case)
2142     fileChooser.setDialogTitle("Select the datastore directory");
2143     fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2144     fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
2145     fileChooser.setResource("gate.persist.SerialDataStore");
2146     if(fileChooser.showOpenDialog(MainFrame.this)
2147       == JFileChooser.APPROVE_OPTION) {
2148       try {
2149         URL dsURL = fileChooser.getSelectedFile().toURI().toURL();
2150         ds =
2151           Factory.openDataStore("gate.persist.SerialDataStore", dsURL
2152             .toExternalForm());
2153       }
2154       catch(MalformedURLException mue) {
2155         JOptionPane.showMessageDialog(MainFrame.this,
2156           "Invalid location for the datastore\n " + mue.toString()"GATE",
2157           JOptionPane.ERROR_MESSAGE);
2158       }
2159       catch(PersistenceException pe) {
2160         JOptionPane.showMessageDialog(MainFrame.this,
2161           "Datastore opening error!\n " + pe.toString()"GATE",
2162           JOptionPane.ERROR_MESSAGE);
2163       // catch
2164     // if
2165 
2166     return ds;
2167   // openSerialDataStore()
2168 
2169   /**
2170    * Method is used in ....OpenDSAction
2171    @return the opened datastore or null if an error occurs
2172    */
2173   protected DataStore openDocServiceDataStore() {
2174     DataStore ds = null;
2175     try {
2176       String DSLocation =
2177         JOptionPane.showInputDialog(MainFrame.this,
2178           "Enter document service URL",
2179           "http://localhost:8080/docservice/services/docservice");
2180       // System.out.println("DEBUG: MainFrame.openDocServiceDataStore()
2181       // DSLocation='" + DSLocation + "'");
2182       ds =
2183         Factory.openDataStore("gleam.docservice.gate.DocServiceDataStore",
2184           DSLocation);
2185     }
2186     catch(Exception error) {
2187       String message = "Error when opening the Datastore.";
2188       alertButton.setAction(new AlertAction(error, message, null));
2189     }
2190     return ds;
2191   // openWSDataStore()
2192 
2193   /*
2194    * synchronized void showWaitDialog() { Point location =
2195    * getLocationOnScreen(); location.translate(10, getHeight() -
2196    * waitDialog.getHeight() - southBox.getHeight() - 10);
2197    * waitDialog.setLocation(location); waitDialog.showDialog(new
2198    * Component[]{}); }
2199    *
2200    * synchronized void hideWaitDialog() { waitDialog.goAway(); }
2201    */
2202 
2203   /*
2204    * class NewProjectAction extends AbstractAction { public
2205    * NewProjectAction(){ super("New Project", new
2206    * ImageIcon(MainFrame.class.getResource(
2207    * "/gate/resources/img/newProject")));
2208    * putValue(SHORT_DESCRIPTION,"Create a new project"); } public void
2209    * actionPerformed(ActionEvent e){ fileChooser.setDialogTitle("Select
2210    * new project file");
2211    * fileChooser.setFileSelectionMode(fileChooser.FILES_ONLY);
2212    * if(fileChooser.showOpenDialog(parentFrame) ==
2213    * fileChooser.APPROVE_OPTION){ ProjectData pData = new
2214    * ProjectData(fileChooser.getSelectedFile(), parentFrame);
2215    * addProject(pData); } } }
2216    */
2217 
2218   /** This class represent an action which brings up the Annot Diff tool */
2219   class NewAnnotDiffAction extends AbstractAction {
2220     private static final long serialVersionUID = 1L;
2221     public NewAnnotDiffAction() {
2222       super("Annotation Diff", getIcon("annotation-diff"));
2223       putValue(SHORT_DESCRIPTION,
2224         "Compare annotations and features in one or two documents");
2225     }
2226     public void actionPerformed(ActionEvent e) {
2227       // find the handle in the resource tree for the displayed view
2228       Enumeration nodesEnum = resourcesTreeRoot.preorderEnumeration();
2229       DefaultMutableTreeNode node;
2230       Handle handle = null;
2231       while(nodesEnum.hasMoreElements()) {
2232         node = (DefaultMutableTreeNode)nodesEnum.nextElement();
2233         if ((node.getUserObject() instanceof Handle)
2234          && (mainTabbedPane.getSelectedComponent().equals(
2235             ((Handle)node.getUserObject()).getLargeView()))) {
2236           handle = (Handle)node.getUserObject();
2237           break;
2238         }
2239       }
2240       String documentName = null;
2241       if(handle != null
2242       && handle.getTarget() instanceof Document) {
2243         documentName = ((Document)handle.getTarget()).getName();
2244       }
2245       AnnotationDiffGUI frame;
2246       if (documentName != null) {
2247         // use the document displayed in the view to compute the differences
2248         frame = new AnnotationDiffGUI("Annotation Diff Tool",
2249           documentName, documentName, null, null, null, null);
2250       else {
2251         frame = new AnnotationDiffGUI("Annotation Diff Tool");
2252       }
2253       frame.pack();
2254       frame.setLocationRelativeTo(MainFrame.this);
2255       frame.setVisible(true);
2256     }
2257   }
2258 
2259   /**
2260    * This class represent an action which brings up the corpus
2261    * evaluation tool
2262    */
2263   class NewCorpusEvalAction extends AbstractAction {
2264     private static final long serialVersionUID = 1L;
2265     public NewCorpusEvalAction() {
2266       super("Default Mode");
2267       putValue(SHORT_DESCRIPTION, "Compares stored processed set with current" +
2268         " processed set and human-annotated set");
2269       putValue(SMALL_ICON, getIcon("corpus-benchmark"));
2270     }// newCorpusEvalAction
2271 
2272     public void actionPerformed(ActionEvent e) {
2273       Runnable runnable = new Runnable() {
2274         public void run() {
2275           fileChooser.setDialogTitle("Please select a directory which contains "
2276             "the documents to be evaluated");
2277           fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2278           fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
2279           fileChooser.setResource(CorpusBenchmarkTool.class.getName());
2280           int state = fileChooser.showOpenDialog(MainFrame.this);
2281           File startDir = fileChooser.getSelectedFile();
2282           if(state == JFileChooser.CANCEL_OPTION || startDir == nullreturn;
2283 
2284           fileChooser.setDialogTitle(
2285             "Please select the application that you want to run");
2286           fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
2287           fileChooser.setResource(
2288             CorpusBenchmarkTool.class.getName() ".application");
2289           state = fileChooser.showOpenDialog(MainFrame.this);
2290           File testApp = fileChooser.getSelectedFile();
2291           if(state == JFileChooser.CANCEL_OPTION || testApp == nullreturn;
2292 
2293           // first create the tool and set its parameters
2294           CorpusBenchmarkTool theTool = new CorpusBenchmarkTool();
2295           theTool.setStartDirectory(startDir);
2296           theTool.setApplicationFile(testApp);
2297           theTool.setVerboseMode(verboseModeItem.isSelected());
2298 
2299           Out.prln("Please wait while GATE tools are initialised.");
2300           // initialise the tool
2301           theTool.init();
2302           // and execute it
2303           theTool.execute();
2304           theTool.printStatistics();
2305 
2306           Out.prln("<BR>Overall average precision: "
2307             + theTool.getPrecisionAverage());
2308           Out.prln("<BR>Overall average recall: " + theTool.getRecallAverage());
2309           Out.prln("<BR>Overall average fMeasure : "
2310             + theTool.getFMeasureAverage());
2311           Out.prln("<BR>Finished!");
2312           theTool.unloadPRs();
2313         }
2314       };
2315       Thread thread =
2316         new Thread(Thread.currentThread().getThreadGroup(), runnable,
2317           "NewCorpusEvalAction");
2318       thread.setPriority(Thread.MIN_PRIORITY);
2319       thread.start();
2320     }// actionPerformed();
2321   }// class NewCorpusEvalAction
2322 
2323   /**
2324    * This class represent an action which brings up the corpus
2325    * evaluation tool
2326    */
2327   class StoredMarkedCorpusEvalAction extends AbstractAction {
2328     private static final long serialVersionUID = 1L;
2329     public StoredMarkedCorpusEvalAction() {
2330       super("Human Marked Against Stored Processing Results");
2331       putValue(SHORT_DESCRIPTION,
2332         "Compares stored processed set with human-annotated set");
2333       putValue(SMALL_ICON, getIcon("corpus-benchmark"));
2334     }// newCorpusEvalAction
2335 
2336     public void actionPerformed(ActionEvent e) {
2337       Runnable runnable = new Runnable() {
2338         public void run() {
2339           fileChooser.setDialogTitle("Please select a directory which contains "
2340             "the documents to be evaluated");
2341           fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2342           fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
2343           fileChooser.setResource(CorpusBenchmarkTool.class.getName());
2344           int state = fileChooser.showOpenDialog(MainFrame.this);
2345           File startDir = fileChooser.getSelectedFile();
2346           if(state == JFileChooser.CANCEL_OPTION || startDir == nullreturn;
2347 
2348           // first create the tool and set its parameters
2349           CorpusBenchmarkTool theTool = new CorpusBenchmarkTool();
2350           theTool.setStartDirectory(startDir);
2351           theTool.setMarkedStored(true);
2352           theTool.setVerboseMode(verboseModeItem.isSelected());
2353           // theTool.setMarkedDS(
2354           // MainFrame.this.datastoreModeCorpusEvalToolAction.isDatastoreMode());
2355 
2356           Out
2357             .prln("Evaluating human-marked documents against pre-stored results.");
2358           // initialise the tool
2359           theTool.init();
2360           // and execute it
2361           theTool.execute();
2362           theTool.printStatistics();
2363 
2364           Out.prln("<BR>Overall average precision: "
2365             + theTool.getPrecisionAverage());
2366           Out.prln("<BR>Overall average recall: " + theTool.getRecallAverage());
2367           Out.prln("<BR>Overall average fMeasure : "
2368             + theTool.getFMeasureAverage());
2369           Out.prln("<BR>Finished!");
2370           theTool.unloadPRs();
2371         }
2372       };
2373       Thread thread =
2374         new Thread(Thread.currentThread().getThreadGroup(), runnable,
2375           "StoredMarkedCorpusEvalAction");
2376       thread.setPriority(Thread.MIN_PRIORITY);
2377       thread.start();
2378     }// actionPerformed();
2379   }// class StoredMarkedCorpusEvalActionpusEvalAction
2380 
2381   /**
2382    * This class represent an action which brings up the corpus
2383    * evaluation tool
2384    */
2385   class CleanMarkedCorpusEvalAction extends AbstractAction {
2386     private static final long serialVersionUID = 1L;
2387     public CleanMarkedCorpusEvalAction() {
2388       super("Human Marked Against Current Processing Results");
2389       putValue(SHORT_DESCRIPTION,
2390         "Compares current processed set with human-annotated set");
2391       putValue(SMALL_ICON, getIcon("corpus-benchmark"));
2392     }// newCorpusEvalAction
2393 
2394     public void actionPerformed(ActionEvent e) {
2395       Runnable runnable = new Runnable() {
2396         public void run() {
2397           fileChooser.setDialogTitle("Please select a directory which contains "
2398             "the documents to be evaluated");
2399           fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2400           fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
2401           fileChooser.setResource(CorpusBenchmarkTool.class.getName());
2402           int state = fileChooser.showOpenDialog(MainFrame.this);
2403           File startDir = fileChooser.getSelectedFile();
2404           if(state == JFileChooser.CANCEL_OPTION || startDir == nullreturn;
2405 
2406           fileChooser.setDialogTitle(
2407             "Please select the application that you want to run");
2408           fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
2409           fileChooser.setResource(
2410             CorpusBenchmarkTool.class.getName() ".application");
2411           state = fileChooser.showOpenDialog(MainFrame.this);
2412           File testApp = fileChooser.getSelectedFile();
2413           if(state == JFileChooser.CANCEL_OPTION || testApp == nullreturn;
2414 
2415           // first create the tool and set its parameters
2416           CorpusBenchmarkTool theTool = new CorpusBenchmarkTool();
2417           theTool.setStartDirectory(startDir);
2418           theTool.setApplicationFile(testApp);
2419           theTool.setMarkedClean(true);
2420           theTool.setVerboseMode(verboseModeItem.isSelected());
2421 
2422           Out.prln("Evaluating human-marked documents against current processing results.");
2423           // initialise the tool
2424           theTool.init();
2425           // and execute it
2426           theTool.execute();
2427           theTool.printStatistics();
2428 
2429           Out.prln("Overall average precision: "
2430             + theTool.getPrecisionAverage());
2431           Out.prln("Overall average recall: " + theTool.getRecallAverage());
2432           Out
2433             .prln("Overall average fMeasure : " + theTool.getFMeasureAverage());
2434           Out.prln("Finished!");
2435           theTool.unloadPRs();
2436         }
2437       };
2438       Thread thread =
2439         new Thread(Thread.currentThread().getThreadGroup(), runnable,
2440           "CleanMarkedCorpusEvalAction");
2441       thread.setPriority(Thread.MIN_PRIORITY);
2442       thread.start();
2443     }// actionPerformed();
2444   }// class CleanMarkedCorpusEvalActionpusEvalAction
2445 
2446   /**
2447    * This class represent an action which brings up the corpus
2448    * evaluation tool
2449    */
2450   class GenerateStoredCorpusEvalAction extends AbstractAction {
2451     private static final long serialVersionUID = 1L;
2452     public GenerateStoredCorpusEvalAction() {
2453       super("Store Corpus for Future Evaluation");
2454       putValue(SHORT_DESCRIPTION, "Store corpus for future evaluation");
2455       putValue(SMALL_ICON, getIcon("corpus-benchmark"));
2456     }// newCorpusEvalAction
2457 
2458     public void actionPerformed(ActionEvent e) {
2459       Runnable runnable = new Runnable() {
2460         public void run() {
2461           fileChooser.setDialogTitle("Please select a directory which contains "
2462             "the documents to be evaluated");
2463           fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2464           fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
2465           fileChooser.setResource(CorpusBenchmarkTool.class.getName());
2466           int state = fileChooser.showOpenDialog(MainFrame.this);
2467           File startDir = fileChooser.getSelectedFile();
2468           if(state == JFileChooser.CANCEL_OPTION || startDir == nullreturn;
2469 
2470           fileChooser.setDialogTitle(
2471             "Please select the application that you want to run");
2472           fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
2473           fileChooser.setResource(
2474             CorpusBenchmarkTool.class.getName() ".application");
2475           state = fileChooser.showOpenDialog(MainFrame.this);
2476           File testApp = fileChooser.getSelectedFile();
2477           if(state == JFileChooser.CANCEL_OPTION || testApp == nullreturn;
2478 
2479           // first create the tool and set its parameters
2480           CorpusBenchmarkTool theTool = new CorpusBenchmarkTool();
2481           theTool.setStartDirectory(startDir);
2482           theTool.setApplicationFile(testApp);
2483           theTool.setGenerateMode(true);
2484 
2485           Out.prln("Processing and storing documents for future evaluation.");
2486           // initialise the tool
2487           theTool.init();
2488           // and execute it
2489           theTool.execute();
2490           theTool.unloadPRs();
2491           Out.prln("Finished!");
2492         }
2493       };
2494       Thread thread =
2495         new Thread(Thread.currentThread().getThreadGroup(), runnable,
2496           "GenerateStoredCorpusEvalAction");
2497       thread.setPriority(Thread.MIN_PRIORITY);
2498       thread.start();
2499     }// actionPerformed();
2500   }// class GenerateStoredCorpusEvalAction
2501 
2502   /**
2503    * This class represent an action which brings up the corpus
2504    * evaluation tool
2505    */
2506   class VerboseModeCorpusEvalToolAction extends AbstractAction {
2507     private static final long serialVersionUID = 1L;
2508     public VerboseModeCorpusEvalToolAction() {
2509       super("Verbose Mode");
2510     }// VerboseModeCorpusEvalToolAction
2511 
2512     public boolean isVerboseMode() {
2513       return verboseMode;
2514     }
2515 
2516     public void actionPerformed(ActionEvent e) {
2517       if(!(e.getSource() instanceof JCheckBoxMenuItem)) return;
2518       verboseMode = ((JCheckBoxMenuItem)e.getSource()).getState();
2519     }// actionPerformed();
2520 
2521     protected boolean verboseMode = false;
2522   }// class f
2523 
2524   /**
2525    * This class represent an action which brings up the corpus
2526    * evaluation tool
2527    */
2528   /*
2529    * class DatastoreModeCorpusEvalToolAction extends AbstractAction {
2530    * public DatastoreModeCorpusEvalToolAction() { super("Use a datastore
2531    * for human annotated texts"); putValue(SHORT_DESCRIPTION,"Use a
2532    * datastore for the human annotated texts"); }//
2533    * DatastoreModeCorpusEvalToolAction
2534    *
2535    * public boolean isDatastoreMode() {return datastoreMode;}
2536    *
2537    * public void actionPerformed(ActionEvent e) { if (! (e.getSource()
2538    * instanceof JCheckBoxMenuItem)) return; datastoreMode =
2539    * ((JCheckBoxMenuItem)e.getSource()).getState(); }//
2540    * actionPerformed(); protected boolean datastoreMode = false;
2541    * }//class DatastoreModeCorpusEvalToolListener
2542    */
2543 
2544   /**
2545    * Loads ANNIE with default parameters.
2546    */
2547   class LoadANNIEWithDefaultsAction extends AbstractAction implements
2548                                                           ANNIEConstants {
2549     private static final long serialVersionUID = 1L;
2550 
2551     public LoadANNIEWithDefaultsAction() {
2552       super("with Defaults");
2553       putValue(SHORT_DESCRIPTION, "Load ANNIE with default parameters");
2554       putValue(SMALL_ICON, getIcon("annie-application"));
2555     }
2556 
2557     public void actionPerformed(ActionEvent e) {
2558       Runnable runnable = new Runnable() {
2559         public void run() {
2560           lockGUI("ANNIE is being loaded...");
2561           try {
2562             long startTime = System.currentTimeMillis();
2563 
2564             // load ANNIE as an application from a gapp file
2565             PersistenceManager.loadObjectFromFile(new File(new File(
2566               Gate.getPluginsHome(), ANNIEConstants.PLUGIN_DIR),
2567                 ANNIEConstants.DEFAULT_FILE));
2568 
2569             long endTime = System.currentTimeMillis();
2570             statusChanged("ANNIE loaded in "
2571               + NumberFormat.getInstance().format(
2572                 (double)(endTime - startTime1000" seconds");
2573           }
2574           catch(Exception error) {
2575             String message =
2576               "There was an error when loading the ANNIE application.";
2577             alertButton.setAction(new AlertAction(error, message, null));
2578           }
2579           finally {
2580             unlockGUI();
2581           }
2582         }
2583       };
2584       Thread thread = new Thread(runnable, "LoadANNIEWithDefaultsAction");
2585       thread.setPriority(Thread.MIN_PRIORITY);
2586       thread.start();
2587     }
2588   }// class LoadANNIEWithDefaultsAction
2589 
2590   /**
2591    * Loads ANNIE without default parameters.
2592    */
2593   class LoadANNIEWithoutDefaultsAction extends AbstractAction implements
2594                                                              ANNIEConstants {
2595     private static final long serialVersionUID = 1L;
2596 
2597     public LoadANNIEWithoutDefaultsAction() {
2598       super("without Defaults");
2599       putValue(SHORT_DESCRIPTION, "Load ANNIE without default parameters");
2600       putValue(SMALL_ICON, getIcon("annie-application"));
2601     }
2602 
2603     public void actionPerformed(ActionEvent e) {
2604       Runnable runnable = new Runnable() {
2605         public void run() {
2606           lockGUI("ANNIE is being loaded...");
2607           final SerialAnalyserController controller;
2608           try {
2609             // load ANNIE as an application from a gapp file
2610             controller = (SerialAnalyserController)
2611               PersistenceManager.loadObjectFromFile(new File(new File(
2612                 Gate.getPluginsHome(), ANNIEConstants.PLUGIN_DIR),
2613                   ANNIEConstants.DEFAULT_FILE));
2614 
2615             statusChanged("ANNIE loaded!");
2616             unlockGUI();
2617           }
2618           catch(Exception error) {
2619             unlockGUI();
2620             String message =
2621               "There was an error when loading the ANNIE application.";
2622             alertButton.setAction(new AlertAction(error, message, null));
2623             return;
2624           }
2625 
2626           SwingUtilities.invokeLater(new Runnable() {
2627             public void run() {
2628               List<ProcessingResource> prs =
2629                 new ArrayList<ProcessingResource>(controller.getPRs());
2630               for(ProcessingResource pr : prs) {
2631                 try {
2632                   SwingUtilities.invokeLater(new Runnable() {
2633                     public void run() {
2634                       // select last processing resource in resources tree
2635                       int selectedRow = resourcesTree.getRowForPath(
2636                         new TreePath(processingResourcesRoot.getPath()));
2637                       selectedRow += processingResourcesRoot.getChildCount();
2638                       resourcesTree.setSelectionRow(selectedRow);
2639                       resourcesTree.scrollRowToVisible(selectedRow);
2640                     }
2641                   });
2642                   // get the parameters for each ANNIE PR
2643                   ResourceData resData = Gate.getCreoleRegister()
2644                     .get(pr.getClass().getName());
2645                   if (resData == null) {
2646                     throw new ResourceInstantiationException(
2647                       pr.getName() " was not possible to load.");
2648                   }
2649                   fileChooser.setResource(resData.getClassName());
2650                   if(newResourceDialog.show(resData, "Parameters for the new "
2651                     + resData.getName())) {
2652                     // add the PR with user parameters
2653                     controller.add((ProcessingResource)
2654                       Factory.createResource(pr.getClass().getName(),
2655                       newResourceDialog.getSelectedParameters()));
2656                   }
2657                   // remove the PR with default parameters
2658                   Factory.deleteResource(pr);
2659                 }
2660                 catch(ResourceInstantiationException error) {
2661                   String message = "There was an error when creating"
2662                     " the resource: " + pr.getName() ".";
2663                   alertButton.setAction(new AlertAction(error, message, null));
2664                 }
2665               // for(Object loadedPR : loadedPRs)
2666             }
2667           });
2668         }
2669       };
2670       Thread thread = new Thread(runnable, "LoadANNIEWithoutDefaultsAction");
2671       thread.setPriority(Thread.MIN_PRIORITY);
2672       thread.start();
2673     }
2674   }// class LoadANNIEWithoutDefaultsAction
2675 
2676   /**
2677    * Loads the application.
2678    */
2679   class LoadApplicationAction extends AbstractAction {
2680     private static final long serialVersionUID = 1L;
2681 
2682     private String pluginDir = null;
2683 
2684     private String applicationFile = null;
2685 
2686     public LoadApplicationAction(String caption, String pluginDir,
2687             String applicationFile) {
2688       super("Load " + pluginDir + " System");
2689       this.pluginDir = pluginDir;
2690       this.applicationFile = applicationFile;
2691       putValue(SHORT_DESCRIPTION, "Load " + pluginDir
2692               " with default parameters");
2693       putValue(SMALL_ICON, getIcon("open-application"));
2694     }
2695 
2696     public void actionPerformed(ActionEvent e) {
2697       Runnable runnable = new Runnable() {
2698         public void run() {
2699           lockGUI(pluginDir + " is being loaded...");
2700           try {
2701             long startTime = System.currentTimeMillis();
2702 
2703             // load LingPipe as an application from a gapp file
2704             PersistenceManager.loadObjectFromFile(new File(new File(Gate
2705                     .getPluginsHome(), pluginDir), applicationFile));
2706 
2707             long endTime = System.currentTimeMillis();
2708             statusChanged(pluginDir
2709                     " loaded in "
2710                     + NumberFormat.getInstance().format(
2711                             (double)(endTime - startTime1000" seconds");
2712           catch(Exception error) {
2713             String message =
2714                     "There was an error when loading the " + pluginDir
2715                             " application.";
2716             alertButton.setAction(new AlertAction(error, message, null));
2717           finally {
2718             unlockGUI();
2719           }
2720         }
2721       };
2722       Thread thread = new Thread(runnable, "LoadApplicationAction");
2723       thread.setPriority(Thread.MIN_PRIORITY);
2724       thread.start();
2725     }
2726   }// class LoadApplicationAction
2727 
2728   class NewBootStrapAction extends AbstractAction {
2729     private static final long serialVersionUID = 1L;
2730     public NewBootStrapAction() {
2731       super("BootStrap Wizard", getIcon("application"));
2732       putValue(SHORT_DESCRIPTION, "Create a generic resource to be completed");
2733     }// NewBootStrapAction
2734 
2735     public void actionPerformed(ActionEvent e) {
2736       BootStrapDialog bootStrapDialog = new BootStrapDialog(MainFrame.this);
2737       bootStrapDialog.setVisible(true);
2738     }// actionPerformed();
2739   }// class NewBootStrapAction
2740 
2741   class ManagePluginsAction extends AbstractAction {
2742     private static final long serialVersionUID = 1L;
2743     public ManagePluginsAction() {
2744       super("Manage CREOLE Plugins");
2745       putValue(SHORT_DESCRIPTION,
2746         "Load, unload, add and remove CREOLE plugins");
2747       putValue(SMALL_ICON, getIcon("creole-plugins"));
2748     }
2749 
2750     public void actionPerformed(ActionEvent e) {
2751       if(pluginManager == null) {
2752         pluginManager = new PluginManagerUI(MainFrame.this);
2753         // pluginManager.setLocationRelativeTo(MainFrame.this);
2754         pluginManager.setModal(true);
2755         getGuiRoots().add(pluginManager);
2756         pluginManager.pack();
2757         // size the window so that it doesn't go off-screen
2758         Dimension screenSize = /* Toolkit.getDefaultToolkit().getScreenSize(); */
2759         getGraphicsConfiguration().getBounds().getSize();
2760         Dimension dialogSize = pluginManager.getPreferredSize();
2761         int width =
2762           dialogSize.width > screenSize.width
2763             ? screenSize.width * 4
2764             : dialogSize.width;
2765         int height =
2766           dialogSize.height > screenSize.height
2767             ? screenSize.height * 4
2768             : dialogSize.height;
2769         pluginManager.setSize(width, height);
2770         pluginManager.validate();
2771         // center the window on screen
2772         int x = (screenSize.width - width2;
2773         int y = (screenSize.height - height2;
2774         pluginManager.setLocation(x, y);
2775       }
2776       fileChooser.setResource(PluginManagerUI.class.getName());
2777       pluginManager.setVisible(true);
2778       // free resources after the dialog is hidden
2779       pluginManager.dispose();
2780     }
2781   }
2782 
2783   /**
2784    * TODO: delete this method as it has moved to {@link PluginManagerUI}
2785    @deprecated
2786    */
2787   class LoadCreoleRepositoryAction extends AbstractAction {
2788     private static final long serialVersionUID = 1L;
2789     public LoadCreoleRepositoryAction() {
2790       super("Load a CREOLE Repository");
2791     }
2792 
2793     public void actionPerformed(ActionEvent e) {
2794       Box messageBox = Box.createHorizontalBox();
2795       Box leftBox = Box.createVerticalBox();
2796       JTextField urlTextField = new JTextField(20);
2797       leftBox.add(new JLabel("Type an URL"));
2798       leftBox.add(urlTextField);
2799       messageBox.add(leftBox);
2800 
2801       messageBox.add(Box.createHorizontalStrut(10));
2802       messageBox.add(new JLabel("or"));
2803       messageBox.add(Box.createHorizontalStrut(10));
2804 
2805       class URLfromFileAction extends AbstractAction {
2806         private static final long serialVersionUID = 1L;
2807         URLfromFileAction(JTextField textField) {
2808           super(null, getIcon("open-file"));
2809           putValue(SHORT_DESCRIPTION, "Click to select a directory");
2810           this.textField = textField;
2811         }
2812 
2813         public void actionPerformed(ActionEvent e) {
2814           fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2815           fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
2816           fileChooser.setResource("gate.CreoleRegister");
2817           int result = fileChooser.showOpenDialog(MainFrame.this);
2818           if(result == JFileChooser.APPROVE_OPTION) {
2819             try {
2820               textField.setText(fileChooser.getSelectedFile().toURI().toURL()
2821                 .toExternalForm());
2822             }
2823             catch(MalformedURLException mue) {
2824               throw new GateRuntimeException(mue.toString());
2825             }
2826           }
2827         }
2828 
2829         JTextField textField;
2830       // class URLfromFileAction extends AbstractAction
2831 
2832       Box rightBox = Box.createVerticalBox();
2833       rightBox.add(new JLabel("Select a directory"));
2834       JButton fileBtn = new JButton(new URLfromFileAction(urlTextField));
2835       rightBox.add(fileBtn);
2836       messageBox.add(rightBox);
2837 
2838       // JOptionPane.showInputDialog(
2839       // MainFrame.this,
2840       // "Select type of Datastore",
2841       // "Gate", JOptionPane.QUESTION_MESSAGE,
2842       // null, names,
2843       // names[0]);
2844 
2845       int res =
2846         JOptionPane.showConfirmDialog(MainFrame.this, messageBox,
2847           "Enter an URL to the directory containig the "
2848             "\"creole.xml\" file", JOptionPane.OK_CANCEL_OPTION,
2849           JOptionPane.QUESTION_MESSAGE, null);
2850       if(res == JOptionPane.OK_OPTION) {
2851         try {
2852           URL creoleURL = new URL(urlTextField.getText());
2853           Gate.getCreoleRegister().registerDirectories(creoleURL);
2854         }
2855         catch(Exception error) {
2856           String message =
2857             "There was a problem when registering your CREOLE directory.";
2858           alertButton.setAction(new AlertAction(error, message, null));
2859         }
2860       }
2861     }
2862   }// class LoadCreoleRepositoryAction extends AbstractAction
2863 
2864   class NewResourceAction extends AbstractAction {
2865     private static final long serialVersionUID = 1L;
2866     /** Used for creation of resource menu item and creation dialog */
2867     ResourceData rData;
2868 
2869     public NewResourceAction(ResourceData rData) {
2870       super(rData.getName());
2871       putValue(SHORT_DESCRIPTION, rData.getComment());
2872       this.rData = rData;
2873       putValue(SMALL_ICON, getIcon(rData.getIcon()));
2874     // NewResourceAction(ResourceData rData)
2875 
2876     public void actionPerformed(ActionEvent evt) {
2877       Runnable runnable = new Runnable() {
2878         public void run() {
2879           newResourceDialog.setTitle("Parameters for the new "
2880             + rData.getName());
2881           fileChooser.setResource(rData.getClassName());
2882           newResourceDialog.show(rData);
2883         }
2884       };
2885       SwingUtilities.invokeLater(runnable);
2886     // actionPerformed
2887   // class NewResourceAction extends AbstractAction
2888 
2889   static class StopAction extends AbstractAction {
2890     private static final long serialVersionUID = 1L;
2891     public StopAction() {
2892       super(" Stop! ");
2893       putValue(SHORT_DESCRIPTION, "Stops the current action");
2894     }
2895 
2896     public boolean isEnabled() {
2897       return Gate.getExecutable() != null;
2898     }
2899 
2900     public void actionPerformed(ActionEvent e) {
2901       Executable ex = Gate.getExecutable();
2902       if(ex != nullex.interrupt();
2903     }
2904   }
2905 
2906   /**
2907    * Method is used in NewDSAction
2908    @return the new datastore or null if an error occurs
2909    */
2910   protected DataStore createSearchableDataStore() {
2911     try {
2912 
2913       JPanel mainPanel = new JPanel(new GridBagLayout());
2914 
2915       final JTextField dsLocation = new JTextField(""20);
2916       dsLocation.setEditable(false);
2917       
2918       final JTextField indexLocation = new JTextField(""20);
2919       indexLocation.setToolTipText("directory to store the the lucene index");
2920 
2921       JTextField btat = new JTextField("Token"20);
2922       btat.setToolTipText("Examples: Token, AnnotationSetName.Token, "
2923         + Constants.DEFAULT_ANNOTATION_SET_NAME + ".Token");
2924       JCheckBox createTokensAutomatically =
2925         new JCheckBox("Create Tokens Automatically");
2926       createTokensAutomatically.setSelected(true);
2927       JTextField iuat = new JTextField(""20);
2928       iuat.setToolTipText("Examples: Sentence, AnnotationSetName.Sentence, "
2929         + Constants.DEFAULT_ANNOTATION_SET_NAME + ".Sentence");
2930 
2931       final List<String> inputASList = new ArrayList<String>();
2932       inputASList.add("Key");
2933       inputASList.add(Constants.DEFAULT_ANNOTATION_SET_NAME);
2934       
2935       final JTextField inputAS = new JTextField(""20);
2936       inputAS.setText("Key;"+Constants.DEFAULT_ANNOTATION_SET_NAME);
2937       inputAS.setEditable(false);
2938       
2939       JButton editInputAS = new JButton(getIcon("edit-list"));
2940       editInputAS.addActionListener(new ActionListener() {
2941         public void actionPerformed(ActionEvent ae) {
2942           ListEditorDialog listEditor =
2943             new ListEditorDialog(instance, inputASList, "java.lang.String");
2944           List result = listEditor.showDialog();
2945           if(result != null) {
2946             inputASList.clear();
2947             inputASList.addAll(result);
2948             if(inputASList.size() 0) {
2949               String text =
2950                 inputASList.get(0== null
2951                   ? Constants.DEFAULT_ANNOTATION_SET_NAME
2952                   : inputASList.get(0);
2953               for(int j = 1; j < inputASList.size(); j++) {
2954                 text +=
2955                   ";"
2956                     (inputASList.get(j== null
2957                       ? Constants.DEFAULT_ANNOTATION_SET_NAME
2958                       : inputASList.get(j));
2959               }
2960               inputAS.setText(text);
2961             }
2962             else {
2963               inputAS.setText("");
2964             }
2965           }
2966         }
2967       });
2968 
2969       JComboBox asie = new JComboBox(new String[]{"include""exclude"});
2970       inputAS.setToolTipText("Leave blank for indexing all annotation sets. \"" 
2971               + Constants.DEFAULT_ANNOTATION_SET_NAME + 
2972               "\" indicates the default annotation set");
2973 
2974       final List<String> fteList = new ArrayList<String>();
2975       fteList.add("SpaceToken");
2976       fteList.add("Split");
2977       final JTextField fte = new JTextField(""20);
2978       fte.setText("SpaceToken;Split");
2979       fte.setEditable(false);
2980       JButton editFTE = new JButton(getIcon("edit-list"));
2981       editFTE.addActionListener(new ActionListener() {
2982         public void actionPerformed(ActionEvent ae) {
2983           ListEditorDialog listEditor =
2984             new ListEditorDialog(instance, fteList, "java.lang.String");
2985           List result = listEditor.showDialog();
2986           if(result != null) {
2987             fteList.clear();
2988             fteList.addAll(result);
2989             if(fteList.size() 0) {
2990               String text =
2991                 fteList.get(0== null
2992                   ? Constants.DEFAULT_ANNOTATION_SET_NAME
2993                   : fteList.get(0);
2994               for(int j = 1; j < fteList.size(); j++) {
2995                 text +=
2996                   ";"
2997                     (fteList.get(j== null
2998                       ? Constants.DEFAULT_ANNOTATION_SET_NAME
2999                       : fteList.get(j));
3000               }
3001               fte.setText(text);
3002             }
3003             else {
3004               fte.setText("");
3005             }
3006           }
3007         }
3008       });
3009 
3010       JComboBox ftie = new JComboBox(new String[]{"include""exclude"});
3011       ftie.setSelectedIndex(1);
3012       fte.setToolTipText("Leave blank for inclusion of all features");
3013 
3014       JButton indexBrowse = new JButton(getIcon("open-file"));
3015       indexBrowse.addActionListener(new ActionListener() {
3016         public void actionPerformed(ActionEvent ae) {
3017           // first we need to ask for a new empty directory
3018           fileChooser.setDialogTitle(
3019             "Please create a new empty directory for datastore");
3020           fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
3021           fileChooser.setResource("gate.DataStore.index");
3022           if(fileChooser.showOpenDialog(MainFrame.this)
3023             == JFileChooser.APPROVE_OPTION) {
3024             try {
3025               indexLocation.setText(fileChooser.getSelectedFile().toURI()
3026                 .toURL().toExternalForm());
3027             }
3028             catch(Exception e) {
3029               indexLocation.setText("");
3030             }
3031           }
3032         }
3033       });
3034 
3035       GridBagConstraints constraints = new GridBagConstraints();
3036       constraints.gridx = GridBagConstraints.RELATIVE;
3037       constraints.gridy = 0;
3038       constraints.gridwidth = 3;
3039       constraints.anchor = GridBagConstraints.WEST;
3040       constraints.fill = GridBagConstraints.NONE;
3041       constraints.insets = new Insets(0005);
3042       mainPanel.add(new JLabel("Datastore URL:"), constraints);
3043 
3044       constraints = new GridBagConstraints();
3045       constraints.gridx = GridBagConstraints.RELATIVE;
3046       constraints.gridy = 0;
3047       constraints.gridwidth = 6;
3048       constraints.fill = GridBagConstraints.HORIZONTAL;
3049       constraints.insets = new Insets(00010);
3050       mainPanel.add(dsLocation, constraints);
3051 
3052       // second row
3053       constraints = new GridBagConstraints();
3054       constraints.gridx = GridBagConstraints.RELATIVE;
3055       constraints.gridy = 1;
3056       constraints.gridwidth = 3;
3057       constraints.anchor = GridBagConstraints.WEST;
3058       constraints.fill = GridBagConstraints.NONE;
3059       constraints.insets = new Insets(0005);
3060       mainPanel.add(new JLabel("Index Location:"), constraints);
3061 
3062       constraints = new GridBagConstraints();
3063       constraints.gridx = GridBagConstraints.RELATIVE;
3064       constraints.gridy = 1;
3065       constraints.gridwidth = 5;
3066       constraints.fill = GridBagConstraints.HORIZONTAL;
3067       constraints.insets = new Insets(00010);
3068       mainPanel.add(indexLocation, constraints);
3069 
3070       constraints = new GridBagConstraints();
3071       constraints.gridx = GridBagConstraints.RELATIVE;
3072       constraints.gridy = 1;
3073       constraints.gridwidth = 1;
3074       constraints.anchor = GridBagConstraints.NORTHWEST;
3075       mainPanel.add(indexBrowse, constraints);
3076       indexBrowse.setBorderPainted(false);
3077       indexBrowse.setContentAreaFilled(false);
3078 
3079       // third row row
3080       constraints = new GridBagConstraints();
3081       constraints.gridx = GridBagConstraints.RELATIVE;
3082       constraints.gridy = 2;
3083       constraints.gridwidth = 2;
3084       constraints.anchor = GridBagConstraints.WEST;
3085       constraints.fill = GridBagConstraints.NONE;
3086       constraints.insets = new Insets(0005);
3087       mainPanel.add(new JLabel("Annotation Sets:"), constraints);
3088 
3089       constraints = new GridBagConstraints();
3090       constraints.gridx = GridBagConstraints.RELATIVE;
3091       constraints.gridy = 2;
3092       constraints.gridwidth = 1;
3093       constraints.fill = GridBagConstraints.HORIZONTAL;
3094       constraints.insets = new Insets(00010);
3095       mainPanel.add(asie, constraints);
3096 
3097       constraints = new GridBagConstraints();
3098       constraints.gridx = GridBagConstraints.RELATIVE;
3099       constraints.gridy = 2;
3100       constraints.gridwidth = 5;
3101       constraints.fill = GridBagConstraints.HORIZONTAL;
3102       constraints.insets = new Insets(00010);
3103       mainPanel.add(inputAS, constraints);
3104 
3105       constraints = new GridBagConstraints();
3106       constraints.gridx = GridBagConstraints.RELATIVE;
3107       constraints.gridy = 2;
3108       constraints.gridwidth = 1;
3109       constraints.anchor = GridBagConstraints.NORTHWEST;
3110       mainPanel.add(editInputAS, constraints);
3111       editInputAS.setBorderPainted(false);
3112       editInputAS.setContentAreaFilled(false);
3113 
3114       // fourth row row
3115       constraints = new GridBagConstraints();
3116       constraints.gridx = GridBagConstraints.RELATIVE;
3117       constraints.gridy = 3;
3118       constraints.gridwidth = 3;
3119       constraints.anchor = GridBagConstraints.WEST;
3120       constraints.fill = GridBagConstraints.NONE;
3121       constraints.insets = new Insets(0005);
3122       mainPanel.add(new JLabel("Base Token Type:"), constraints);
3123 
3124       constraints = new GridBagConstraints();
3125       constraints.gridx = GridBagConstraints.RELATIVE;
3126       constraints.gridy = 3;
3127       constraints.gridwidth = 5;
3128       constraints.anchor = GridBagConstraints.NORTHWEST;
3129       mainPanel.add(btat, constraints);
3130 
3131       // fifth row
3132       constraints = new GridBagConstraints();
3133       constraints.gridx = 4;
3134       constraints.gridy = 4;
3135       constraints.gridwidth = 5;
3136       constraints.anchor = GridBagConstraints.WEST;
3137       constraints.fill = GridBagConstraints.NONE;
3138       constraints.insets = new Insets(0005);
3139       mainPanel.add(createTokensAutomatically, constraints);
3140 
3141       // sixth row
3142       constraints = new GridBagConstraints();
3143       constraints.gridx = GridBagConstraints.RELATIVE;
3144       constraints.gridy = 5;
3145       constraints.gridwidth = 3;
3146       constraints.anchor = GridBagConstraints.WEST;
3147       constraints.fill = GridBagConstraints.NONE;
3148       constraints.insets = new Insets(0005);
3149       mainPanel.add(new JLabel("Index Unit Type:"), constraints);
3150 
3151       constraints = new GridBagConstraints();
3152       constraints.gridx = GridBagConstraints.RELATIVE;
3153       constraints.gridy = 5;
3154       constraints.gridwidth = 5;
3155       constraints.anchor = GridBagConstraints.NORTHWEST;
3156       mainPanel.add(iuat, constraints);
3157 
3158       // seventh row
3159       constraints = new GridBagConstraints();
3160       constraints.gridx = GridBagConstraints.RELATIVE;
3161       constraints.gridy = 6;
3162       constraints.gridwidth = 2;
3163       constraints.anchor = GridBagConstraints.WEST;
3164       constraints.fill = GridBagConstraints.NONE;
3165       constraints.insets = new Insets(0005);
3166       mainPanel.add(new JLabel("Features:"), constraints);
3167 
3168       constraints = new GridBagConstraints();
3169       constraints.gridx = GridBagConstraints.RELATIVE;
3170       constraints.gridy = 6;
3171       constraints.gridwidth = 1;
3172       constraints.fill = GridBagConstraints.HORIZONTAL;
3173       constraints.insets = new Insets(00010);
3174       mainPanel.add(ftie, constraints);
3175 
3176       constraints = new GridBagConstraints();
3177       constraints.gridx = GridBagConstraints.RELATIVE;
3178       constraints.gridy = 6;
3179       constraints.gridwidth = 5;
3180       constraints.fill = GridBagConstraints.HORIZONTAL;
3181       constraints.insets = new Insets(00010);
3182       mainPanel.add(fte, constraints);
3183 
3184       constraints = new GridBagConstraints();
3185       constraints.gridx = GridBagConstraints.RELATIVE;
3186       constraints.gridy = 6;
3187       constraints.gridwidth = 1;
3188       constraints.anchor = GridBagConstraints.NORTHWEST;
3189       mainPanel.add(editFTE, constraints);
3190       editFTE.setBorderPainted(false);
3191       editFTE.setContentAreaFilled(false);
3192 
3193       // get the URL (a folder in this case)
3194       fileChooser.setDialogTitle("Please create a new empty directory");
3195       fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
3196       fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
3197       fileChooser.setResource("gate.persist.LuceneDataStoreImpl");
3198       int response = fileChooser.showOpenDialog(MainFrame.this);
3199       if(response == JFileChooser.APPROVE_OPTION) {
3200         try {
3201           File dsFolder = fileChooser.getSelectedFile();
3202           dsLocation.setText(dsFolder.toURI().toURL().toExternalForm());
3203           File indexFolder = 
3204             new File(dsFolder.getParentFile(), dsFolder.getName()+"-index");
3205           indexLocation.setText(indexFolder.toURI().toURL().toExternalForm());
3206         }
3207         catch(MalformedURLException mue) {
3208           JOptionPane.showMessageDialog(MainFrame.this,
3209             "Invalid location\n " + mue.toString()"GATE",
3210             JOptionPane.ERROR_MESSAGE);
3211         }
3212       else {
3213         return null;
3214       }
3215       
3216       
3217       boolean validEntry = false;
3218       while(!validEntry) {
3219         int returnValue =
3220           JOptionPane.showOptionDialog(MainFrame.this, mainPanel,
3221             "SearchableDataStore", JOptionPane.PLAIN_MESSAGE,
3222             JOptionPane.OK_CANCEL_OPTION, getIcon("empty"),
3223             new String[]{"OK""Cancel"}"OK");
3224         
3225         if(returnValue == JOptionPane.OK_OPTION) {
3226           
3227           // sanity check parameters
3228           
3229           if(dsLocation.getText().equals(indexLocation.getText())) {
3230             JOptionPane.showMessageDialog(MainFrame.this,
3231                     "Datastore and index cannot be stored in the same directory",
3232                     "Error", JOptionPane.ERROR_MESSAGE);
3233           }
3234           else {
3235             // check if index folder can be created
3236             try {
3237               File indexDir = 
3238                 new File(new URL(indexLocation.getText()).getFile());
3239               if(indexDir.exists() && indexDir.isFile()) {
3240                 JOptionPane.showMessageDialog(MainFrame.this,
3241                         indexDir.getAbsolutePath() 
3242                         " is a file on your disk. Index directory must be an" +
3243                         " empty folder.",
3244                         "Error", JOptionPane.ERROR_MESSAGE);
3245                 continue;
3246               else if(indexDir.isDirectory() && indexDir.list().length > 0) {
3247                 JOptionPane.showMessageDialog(instance,
3248                         "Index directory " + indexDir.getAbsolutePath() 
3249                         " must be an empty folder. ",
3250                         "Error", JOptionPane.ERROR_MESSAGE);
3251                 continue;
3252               else {
3253                 if(!indexDir.exists()) {
3254                   if(!indexDir.mkdirs()) {
3255                     JOptionPane.showMessageDialog(MainFrame.this,
3256                             "Cannot create index directory " 
3257                             indexDir.getAbsolutePath() "an empty folder. ",
3258                             "Error", JOptionPane.ERROR_MESSAGE);
3259                     continue;
3260                   }
3261                 }
3262               }
3263             catch(MalformedURLException mue) {
3264               JOptionPane.showMessageDialog(MainFrame.this,
3265                       "Invalid index location "+indexLocation.getText(),
3266                       "Error", JOptionPane.ERROR_MESSAGE);
3267               continue;
3268             catch(SecurityException se) {
3269               JOptionPane.showMessageDialog(MainFrame.this,
3270                       "Could not create a directory "+indexLocation.getText() 
3271                       " because "+se.getMessage(),
3272                       "Error", JOptionPane.ERROR_MESSAGE);
3273               continue;
3274             }
3275             
3276             // if here.. an empty index directory exists
3277             // break the loop by setting validEntry to true 
3278             validEntry = true;            
3279             DataStore ds =
3280               Factory.createDataStore("gate.persist.LuceneDataStoreImpl",
3281                 dsLocation.getText());
3282     
3283             // we need to set Indexer
3284             Class[] consParam = new Class[1];
3285             consParam[0= URL.class;
3286             Constructor constructor =
3287               Class.forName("gate.creole.annic.lucene.LuceneIndexer", true,
3288                 Gate.getClassLoader()).getConstructor(consParam);
3289             Object indexer =
3290               constructor.newInstance(new URL(indexLocation.getText()));
3291     
3292             Map<String, Object> parameters = new HashMap<String, Object>();
3293             parameters.put(Constants.INDEX_LOCATION_URL, new URL(indexLocation
3294               .getText()));
3295             parameters.put(Constants.BASE_TOKEN_ANNOTATION_TYPE, btat.getText());
3296             parameters.put(Constants.INDEX_UNIT_ANNOTATION_TYPE, iuat.getText());
3297             parameters.put(Constants.CREATE_TOKENS_AUTOMATICALLY,
3298               createTokensAutomatically.isSelected());
3299     
3300             if(inputAS.getText().trim().length() 0) {
3301               ArrayList<String> inputASList1 = new ArrayList<String>();
3302               String[] inputASArray = inputAS.getText().trim().split(";");
3303               if(inputASArray != null && inputASArray.length > 0) {
3304                 inputASList1.addAll(Arrays.asList(inputASArray));
3305               }
3306               if(asie.getSelectedIndex() == 0) {
3307                 // user has provided values for inclusion
3308                 parameters.put(Constants.ANNOTATION_SETS_NAMES_TO_INCLUDE,
3309                   inputASList1);
3310                 parameters.put(Constants.ANNOTATION_SETS_NAMES_TO_EXCLUDE,
3311                   new ArrayList<String>());
3312               }
3313               else {
3314                 // user has provided values for exclusion
3315                 parameters.put(Constants.ANNOTATION_SETS_NAMES_TO_EXCLUDE,
3316                   inputASList1);
3317                 parameters.put(Constants.ANNOTATION_SETS_NAMES_TO_INCLUDE,
3318                   new ArrayList<String>());
3319               }
3320             }
3321             else {
3322               parameters.put(Constants.ANNOTATION_SETS_NAMES_TO_EXCLUDE,
3323                 new ArrayList<String>());
3324               parameters.put(Constants.ANNOTATION_SETS_NAMES_TO_INCLUDE,
3325                 new ArrayList<String>());
3326             }
3327     
3328             if(fte.getText().trim().length() 0) {
3329               ArrayList<String> fteList1 = new ArrayList<String>();
3330               String[] inputASArray = fte.getText().trim().split(";");
3331               if(inputASArray != null && inputASArray.length > 0) {
3332                 fteList1.addAll(Arrays.asList(inputASArray));
3333               }
3334               if(ftie.getSelectedIndex() == 0) {
3335                 // user has provided values for inclusion
3336                 parameters.put(Constants.FEATURES_TO_INCLUDE, fteList1);
3337                 parameters.put(Constants.FEATURES_TO_EXCLUDE,
3338                   new ArrayList<String>());
3339               }
3340               else {
3341                 // user has provided values for exclusion
3342                 parameters.put(Constants.FEATURES_TO_EXCLUDE, fteList1);
3343                 parameters.put(Constants.FEATURES_TO_INCLUDE,
3344                   new ArrayList<String>());
3345               }
3346             }
3347             else {
3348               parameters
3349                 .put(Constants.FEATURES_TO_EXCLUDE, new ArrayList<String>());
3350               parameters
3351                 .put(Constants.FEATURES_TO_INCLUDE, new ArrayList<String>());
3352             }
3353     
3354             Class[] params = new Class[2];
3355             params[0=
3356               Class.forName("gate.creole.annic.Indexer", true, Gate
3357                 .getClassLoader());
3358             params[1= Map.class;
3359             Method indexerMethod = ds.getClass().getMethod("setIndexer", params);
3360             indexerMethod.invoke(ds, indexer, parameters);
3361     
3362             // Class[] searchConsParams = new Class[0];
3363             Constructor searcherConst =
3364               Class.forName("gate.creole.annic.lucene.LuceneSearcher", true,
3365                 Gate.getClassLoader()).getConstructor();
3366             Object searcher = searcherConst.newInstance();
3367             Class[] searchParams = new Class[1];
3368             searchParams[0=
3369               Class.forName("gate.creole.annic.Searcher", true, Gate
3370                 .getClassLoader());
3371             Method searcherMethod =
3372               ds.getClass().getMethod("setSearcher", searchParams);
3373             searcherMethod.invoke(ds, searcher);
3374             return ds;
3375           }
3376         }
3377         else {
3378           validEntry = true;
3379         }
3380       }
3381       return null;
3382     }
3383     catch(Exception e) {
3384       throw new GateRuntimeException(e);
3385     }
3386   // createSearchableDataStore()
3387 
3388   /**
3389    * Method is used in OpenDSAction
3390    @return the opened datastore or null if an error occurs
3391    */
3392   protected DataStore openSearchableDataStore() {
3393     DataStore ds = null;
3394 
3395     // get the URL (a file in this case)
3396     fileChooser.setDialogTitle("Select the datastore directory");
3397     fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
3398     fileChooser.setResource("gate.DataStore.data");
3399     if(fileChooser.showOpenDialog(MainFrame.this)
3400       == JFileChooser.APPROVE_OPTION) {
3401       try {
3402         URL dsURL = fileChooser.getSelectedFile().toURI().toURL();
3403         ds =
3404           Factory.openDataStore("gate.persist.LuceneDataStoreImpl", dsURL
3405             .toExternalForm());
3406       }
3407       catch(MalformedURLException mue) {
3408         JOptionPane.showMessageDialog(MainFrame.this,
3409           "Invalid location for the datastore\n " + mue.toString()"GATE",
3410           JOptionPane.ERROR_MESSAGE);
3411       }
3412       catch(PersistenceException pe) {
3413         JOptionPane.showMessageDialog(MainFrame.this,
3414           "Datastore opening error!\n " + pe.toString()"GATE",
3415           JOptionPane.ERROR_MESSAGE);
3416       // catch
3417     // if
3418 
3419     return ds;
3420   // openSerialDataStore()
3421 
3422   class NewDSAction extends AbstractAction {
3423     private static final long serialVersionUID = 1L;
3424     public NewDSAction() {
3425       super("Create Datastore");
3426       putValue(SHORT_DESCRIPTION, "Create a new datastore");
3427       putValue(SMALL_ICON, getIcon("datastore"));
3428     }
3429 
3430     public void actionPerformed(ActionEvent e) {
3431       Map<String,String> dsTypes = DataStoreRegister.getDataStoreClassNames();
3432       HashMap<String,String> dsTypeByName = new HashMap<String,String>();
3433       for(Map.Entry<String, String> entry : dsTypes.entrySet()) {
3434         dsTypeByName.put(entry.getValue(), entry.getKey());
3435       }
3436 
3437       if(!dsTypeByName.isEmpty()) {
3438         JLabel label = new JLabel("Select a type of Datastore:");
3439         final JList list = new JList(dsTypeByName.keySet().toArray());
3440         String initialSelection = Gate.getUserConfig().getString(
3441           MainFrame.class.getName()+".datastoretype");
3442         if (dsTypeByName.containsKey(initialSelection)) {
3443           list.setSelectedValue(initialSelection, true);
3444         else {
3445           list.setSelectedIndex(0);
3446         }
3447         list.setVisibleRowCount(Math.min(10, list.getModel().getSize()));
3448         list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
3449         final JOptionPane optionPane = new JOptionPane(
3450           new Object[]{label, new JScrollPane(list)},
3451           JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION,
3452           getIcon("datastore")new String[]{"OK""Cancel""Help"}"OK");
3453         final JDialog dialog = new JDialog(
3454           MainFrame.this, "Create a datastore"true);
3455         dialog.setContentPane(optionPane);
3456         list.addMouseListener(new MouseAdapter() {
3457           public void mouseClicked(MouseEvent e) {
3458             if (e.getClickCount() == 2) {
3459               optionPane.setValue("OK");
3460               dialog.setVisible(false);
3461             }
3462           }
3463         });
3464         optionPane.addPropertyChangeListener(new PropertyChangeListener() {
3465           public void propertyChange(PropertyChangeEvent e) {
3466             Object value = optionPane.getValue();
3467             if (value == null || value.equals(JOptionPane.UNINITIALIZED_VALUE)) {
3468               return;
3469             }
3470             if (dialog.isVisible()
3471             && e.getSource() == optionPane
3472             && e.getPropertyName().equals(JOptionPane.VALUE_PROPERTY)) {
3473               if (optionPane.getValue().equals("Help")) {
3474                 // don't close the dialog
3475                 optionPane.setValue(JOptionPane.UNINITIALIZED_VALUE);
3476                 showHelpFrame("sec:datastores""gate.persist.SerialDataStore");
3477               else {
3478                 dialog.setVisible(false);
3479               }
3480             }
3481           }
3482         });
3483         dialog.pack();
3484         dialog.setLocationRelativeTo(MainFrame.this);
3485         dialog.setVisible(true);
3486         Object answer = optionPane.getValue();
3487         if(answer == null) { return}
3488         String className = dsTypeByName.get(list.getSelectedValue());
3489         if(answer.equals("OK"&& !list.isSelectionEmpty()) {
3490           Gate.getUserConfig().put(MainFrame.class.getName()+".datastoretype",
3491             list.getSelectedValue());
3492           if(className.equals("gate.persist.SerialDataStore")) {
3493             createSerialDataStore();
3494           }
3495           else if(className.equals("gate.persist.LuceneDataStoreImpl")) {
3496             createSearchableDataStore();
3497           }
3498           else if(className.equals("gate.persist.OracleDataStore")) {
3499             JOptionPane.showMessageDialog(MainFrame.this,
3500               "Oracle datastores can only be created "
3501                 "by your Oracle administrator!""GATE",
3502               JOptionPane.ERROR_MESSAGE);
3503           }
3504           else {
3505             throw new UnsupportedOperationException("Unimplemented option!\n"
3506               "Use a serial datastore");
3507           }
3508         }
3509       }
3510       else {
3511         // no ds types
3512         JOptionPane.showMessageDialog(MainFrame.this,
3513           "Could not find any registered types " "of datastores...\n"
3514             "Check your GATE installation!""GATE",
3515           JOptionPane.ERROR_MESSAGE);
3516 
3517       }
3518     }
3519   }// class NewDSAction extends AbstractAction
3520 
3521   class LoadResourceFromFileAction extends AbstractAction {
3522     private static final long serialVersionUID = 1L;
3523     public LoadResourceFromFileAction() {
3524       super("Restore Application from File");
3525       putValue(SHORT_DESCRIPTION,
3526         "Restores a previously saved application from a file");
3527       putValue(SMALL_ICON, getIcon("open-application"));
3528     }
3529 
3530     public void actionPerformed(ActionEvent e) {
3531       ExtensionFileFilter filter = new ExtensionFileFilter(
3532         "GATE Application files (.gapp, .xgapp)"".gapp"".xgapp");
3533       fileChooser.addChoosableFileFilter(filter);
3534       fileChooser.setFileFilter(filter);
3535       fileChooser.setDialogTitle("Select a file for this resource");
3536       fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
3537       fileChooser.setResource("lastapplication");
3538 
3539       if (fileChooser.showOpenDialog(MainFrame.this)
3540         == JFileChooser.APPROVE_OPTION) {
3541         final File file = fileChooser.getSelectedFile();
3542         Runnable runnable = new Runnable() { public void run() {
3543         try {
3544           Object resource = PersistenceManager.loadObjectFromFile(file);
3545           if(resource instanceof Resource) {
3546             Map<String, String> locations = fileChooser.getLocations();
3547             Resource res = (Resourceresource;
3548             // save also the location of the application with its name
3549             locations.put("application."+res.getName(),file.getCanonicalPath());
3550             locations.put("application.zip."+res.getName(),
3551               file.getCanonicalPath().replaceFirst("\\.[^.]{3,5}$"".zip"));
3552             // add this application to the list of recent applications
3553             String list = locations.get("applications");
3554             if (list == null) { list = ""}
3555             list = list.replaceFirst("\\Q"+res.getName()+"\\E(;|$)""");
3556             list = res.getName() ";" + list;
3557             locations.put("applications", list);
3558             fileChooser.setLocations(locations);
3559           }
3560         }
3561         catch(MalformedURLException e) {
3562           log.error("Error when saving the resource URL.", e);
3563         }
3564         catch (final Exception error) {
3565           SwingUtilities.invokeLater(new Runnable() {
3566             public void run() {
3567               String message = error.getMessage();
3568               alertButton.setAction(new AlertAction(error, message, null));
3569             }
3570           });
3571         }
3572         finally {
3573           processFinished();
3574         }
3575         }};
3576         Thread thread = new Thread(runnable, "LoadResourceFromFileAction");
3577         thread.setPriority(Thread.MIN_PRIORITY);
3578         thread.start();
3579       }
3580     }
3581   }
3582 
3583   /**
3584    * Closes the view associated to a resource. Does not remove the
3585    * resource from the system, only its view.
3586    */
3587   class CloseViewAction extends AbstractAction {
3588     private static final long serialVersionUID = 1L;
3589     public CloseViewAction(Handle handle) {
3590       super("Hide");
3591       putValue(SHORT_DESCRIPTION, "Hide this resource view");
3592       putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("control H"));
3593       this.handle = handle;
3594     }
3595 
3596     public void actionPerformed(ActionEvent e) {
3597       SwingUtilities.invokeLater(new Runnable() { public void run() {
3598         mainTabbedPane.remove(handle.getLargeView());
3599         mainTabbedPane.setSelectedIndex(mainTabbedPane.getTabCount() 1);
3600         // remove all GUI resources used by this handle
3601         handle.removeViews();
3602       }});
3603     }
3604 
3605     Handle handle;
3606   }
3607 
3608   class CloseViewsForSelectedResourcesAction extends AbstractAction {
3609     private static final long serialVersionUID = 1L;
3610     public CloseViewsForSelectedResourcesAction() {
3611       super("Hide all");
3612       putValue(SHORT_DESCRIPTION, "Hide the selected resources");
3613     }
3614 
3615     public void actionPerformed(ActionEvent e) {
3616       Runnable runner = new Runnable() {
3617         public void run() {
3618           TreePath[] paths = resourcesTree.getSelectionPaths();
3619           for(TreePath path : paths) {
3620             final Object value = ((DefaultMutableTreeNode)
3621               path.getLastPathComponent()).getUserObject();
3622             if(value instanceof Handle) {
3623               SwingUtilities.invokeLater(new Runnable() { public void run() {
3624                 new CloseViewAction((Handle)value).actionPerformed(null);
3625               }});
3626             }
3627           }
3628         }
3629       };
3630       Thread thread = new Thread(runner,
3631         "CloseViewsForSelectedResourcesAction");
3632       thread.setPriority(Thread.MIN_PRIORITY);
3633       thread.start();
3634     }
3635   }
3636 
3637   class RenameResourceAction extends AbstractAction {
3638     private static final long serialVersionUID = 1L;
3639     RenameResourceAction(TreePath path) {
3640       super("Rename");
3641       putValue(SHORT_DESCRIPTION, "Rename this resource");
3642       putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("F2"));
3643       this.path = path;
3644     }
3645 
3646     public void actionPerformed(ActionEvent e) {
3647       resourcesTree.startEditingAtPath(path);
3648     }
3649 
3650     TreePath path;
3651   }
3652 
3653   class CloseSelectedResourcesAction extends AbstractAction {
3654     private static final long serialVersionUID = 1L;
3655     public CloseSelectedResourcesAction() {
3656       super("Close all");
3657       putValue(SHORT_DESCRIPTION, "Close the selected resources");
3658     }
3659 
3660     public void actionPerformed(ActionEvent e) {
3661       Runnable runner = new Runnable() {
3662         public void run() {
3663           TreePath[] paths = resourcesTree.getSelectionPaths();
3664           for(TreePath path : paths) {
3665             final Object userObject = ((DefaultMutableTreeNode)
3666               path.getLastPathComponent()).getUserObject();
3667             if(userObject instanceof NameBearerHandle) {
3668               SwingUtilities.invokeLater(new Runnable() { public void run() {
3669                 ((NameBearerHandle)userObject).getCloseAction()
3670                   .actionPerformed(null);
3671               }});
3672             }
3673           }
3674         }
3675       };
3676       Thread thread = new Thread(runner, "CloseSelectedResourcesAction");
3677       thread.setPriority(Thread.MIN_PRIORITY);
3678       thread.start();
3679     }
3680   }
3681 
3682   class CloseRecursivelySelectedResourcesAction extends AbstractAction {
3683     private static final long serialVersionUID = 1L;
3684     public CloseRecursivelySelectedResourcesAction() {
3685       super("Close Recursively all");
3686       putValue(SHORT_DESCRIPTION, "Close recursively the selected resources");
3687     }
3688 
3689     public void actionPerformed(ActionEvent e) {
3690       Runnable runner = new Runnable() {
3691         public void run() {
3692           TreePath[] paths = resourcesTree.getSelectionPaths();
3693           for(TreePath path : paths) {
3694             final Object userObject = ((DefaultMutableTreeNode)
3695               path.getLastPathComponent()).getUserObject();
3696             if(userObject instanceof NameBearerHandle) {
3697               SwingUtilities.invokeLater(new Runnable() { public void run() {
3698                 ((NameBearerHandle)userObject).getCloseRecursivelyAction()
3699                   .actionPerformed(null);
3700               }});
3701             }
3702           }
3703         }
3704       };
3705       Thread thread = new Thread(runner,
3706         "CloseRecursivelySelectedResourcesAction");
3707       thread.setPriority(Thread.MIN_PRIORITY);
3708       thread.start();
3709     }
3710   }
3711 
3712   class HideAllAction extends AbstractAction {
3713     private static final long serialVersionUID = 1L;
3714     public HideAllAction() {
3715       super("Hide all");
3716       putValue(SHORT_DESCRIPTION, "Hide all resource views");
3717       putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("control shift H"));
3718     }
3719 
3720     public void actionPerformed(ActionEvent e) {
3721       // for each element in the tree look if it is in the tab panel
3722       // if yes, remove it from the tab panel
3723       Enumeration nodesEnum = resourcesTreeRoot.preorderEnumeration();
3724       DefaultMutableTreeNode node;
3725       while(nodesEnum.hasMoreElements()) {
3726         node = (DefaultMutableTreeNode)nodesEnum.nextElement();
3727         if ((node.getUserObject() instanceof Handle)
3728          && (mainTabbedPane.indexOfComponent(
3729             ((Handle)node.getUserObject()).getLargeView()) != -1)) {
3730           final Handle handle = (Handle)node.getUserObject();
3731           SwingUtilities.invokeLater(new Runnable() { public void run() {
3732             (new CloseViewAction(handle)).actionPerformed(null);
3733           }});
3734         }
3735       }
3736     }
3737   }
3738 
3739   class ShowSelectedResourcesAction extends AbstractAction {
3740     private static final long serialVersionUID = 1L;
3741     public ShowSelectedResourcesAction() {
3742       super("Show all");
3743       putValue(SHORT_DESCRIPTION, "Show the selected resources");
3744       putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("Enter"));
3745     }
3746 
3747     public void actionPerformed(ActionEvent e) {
3748       Runnable runner = new Runnable() {
3749         public void run() {
3750           TreePath[] paths = resourcesTree.getSelectionPaths();
3751           if (paths == null) { return}
3752           if (paths.length > 10) {
3753             Object[] possibleValues =
3754               "Open the "+paths.length+" objects""Don't open" };
3755             int selectedValue =
3756               JOptionPane.showOptionDialog(instance, "Do you want to open "
3757               +paths.length+" objects in the central tabbed pane ?",
3758               "Warning", JOptionPane.DEFAULT_OPTION,
3759               JOptionPane.QUESTION_MESSAGE, null,
3760               possibleValues, possibleValues[1]);
3761             if (selectedValue == 1
3762              || selectedValue == JOptionPane.CLOSED_OPTION) {
3763               return;
3764             }
3765           }
3766           for (TreePath path : paths) {
3767             if(path != null) {
3768               Object value = path.getLastPathComponent();
3769               value = ((DefaultMutableTreeNode)value).getUserObject();
3770               if(value instanceof Handle) {
3771                 final Handle handle = (Handle)value;
3772                 SwingUtilities.invokeLater(new Runnable() { public void run() {
3773                   select(handle);
3774                 }});
3775               }
3776             }
3777           }
3778         }
3779       };
3780       Thread thread = new Thread(runner, "ShowSelectedResourcesAction");
3781       thread.setPriority(Thread.MIN_PRIORITY);
3782       thread.start();
3783     }
3784   }
3785 
3786   class ShowResourceAction extends AbstractAction {
3787     private static final long serialVersionUID = 1L;
3788     Handle handle;
3789     public ShowResourceAction(Handle handle) {
3790       super("Show");
3791       putValue(SHORT_DESCRIPTION, "Show this resource");
3792       putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("Enter"));
3793       this.handle = handle;
3794     }
3795 
3796     public void actionPerformed(ActionEvent e) {
3797       SwingUtilities.invokeLater(new Runnable() {
3798         public void run() { select(handle)}
3799       });
3800     }
3801   }
3802 
3803   /**
3804    * Closes the view associated to a resource. Does not remove the
3805    * resource from the system, only its view.
3806    */
3807   class ExitGateAction extends AbstractAction {
3808     private static final long serialVersionUID = 1L;
3809     public ExitGateAction() {
3810       super("Exit GATE");
3811       putValue(SHORT_DESCRIPTION, "Closes the application");
3812       putValue(SMALL_ICON, getIcon("crystal-clear-action-exit"));
3813       putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("alt F4"));
3814     }
3815 
3816     public void actionPerformed(ActionEvent e) {
3817       Runnable runnable = new Runnable() {
3818         public void run() {
3819           // save the options
3820           OptionsMap userConfig = Gate.getUserConfig();
3821           try {
3822           if(userConfig.getBoolean(GateConstants.SAVE_OPTIONS_ON_EXIT)) {
3823             // save the window size
3824             Integer width = MainFrame.this.getWidth();
3825             Integer height = MainFrame.this.getHeight();
3826             userConfig.put(GateConstants.MAIN_FRAME_WIDTH, width);
3827             userConfig.put(GateConstants.MAIN_FRAME_HEIGHT, height);
3828             Gate.writeUserConfig();
3829           }
3830           else {
3831             // don't save options on close
3832             // save the option not to save the options
3833             OptionsMap originalUserConfig = Gate.getOriginalUserConfig();
3834             originalUserConfig.put(GateConstants.SAVE_OPTIONS_ON_EXIT, false);
3835             userConfig.clear();
3836             userConfig.putAll(originalUserConfig);
3837             Gate.writeUserConfig();
3838           }
3839           }
3840           catch(GateException error) {
3841             String message = "Failed to save config data.";
3842             alertButton.setAction(new AlertAction(error, message, null));
3843           }
3844 
3845           // save the session;
3846           File sessionFile = Gate.getUserSessionFile();
3847           if(userConfig.getBoolean(GateConstants.SAVE_SESSION_ON_EXIT)) {
3848             // save all the open applications
3849             try {
3850               ArrayList<Resource> appList = new ArrayList<Resource>(
3851                 Gate.getCreoleRegister().getAllInstances("gate.Controller"));
3852               // remove all hidden instances
3853               Iterator appIter = appList.iterator();
3854               while(appIter.hasNext()) {
3855                 if(Gate.getHiddenAttribute(((Controller)appIter.next())
3856                   .getFeatures())) { appIter.remove()}
3857               }
3858               // When saving the session file, save URLs relative to GATE home
3859               // but do not warn about them
3860               gate.util.persistence.PersistenceManager.saveObjectToFile(
3861                 appList, sessionFile, true, false);
3862             }
3863             catch(Exception error) {
3864               String message = "Failed to save session data.";
3865               alertButton.setAction(new AlertAction(error, message, null));
3866             }
3867           }
3868           else {
3869             // we don't want to save the session
3870             if(sessionFile.exists() && !sessionFile.delete()) {
3871               log.error("Error when deleting the session file.");
3872             }
3873           }
3874 
3875           // restore out and err streams as we're about to hide the
3876           // windows
3877           System.setErr(logArea.getOriginalErr());
3878           System.setOut(logArea.getOriginalOut());
3879           // now we need to dispose all GUI roots
3880           List<Component> roots = new ArrayList<Component>(getGuiRoots());
3881           while(!roots.isEmpty()) {
3882             Component aRoot = roots.remove(0);
3883             if(aRoot instanceof Window) {
3884               Window window = (Window)aRoot;
3885               roots.addAll(Arrays.asList(window.getOwnedWindows()));
3886               window.setVisible(false);
3887               window.dispose();
3888             }
3889           }
3890 
3891           // only hidden when closed
3892           if(helpFrame != nullhelpFrame.dispose();
3893 
3894           // trying to release all resources occupied by all
3895           try {
3896             //make a list of lists of resources of various kinds
3897             List<List<Resource>> listOfListOfResources =
3898               new ArrayList<List<Resource>>();
3899 //            listOfListOfResoruces.add(Gate.getCreoleRegister().getAllInstances(
3900 //                    gate.VisualResource.class.getName()));
3901             listOfListOfResources.add(Gate.getCreoleRegister().getAllInstances(
3902                     gate.LanguageResource.class.getName()));
3903             listOfListOfResources.add(Gate.getCreoleRegister().getAllInstances(
3904                     gate.ProcessingResource.class.getName()));
3905             listOfListOfResources.add(Gate.getCreoleRegister().getAllInstances(
3906                     gate.Controller.class.getName()));
3907 
3908             for(List<Resource> resources :listOfListOfResources){
3909               // we need to call the clean up method for each of these resources
3910               for(Resource aResource : resources) {
3911                 try {
3912                   Factory.deleteResource(aResource);
3913                 catch(Throwable e) {
3914                   // this may throw somekind of exception
3915                   // but we just ignore it as anyway we are closing everything
3916                   log.error(
3917                     "Some problems occurred when cleaning up the resources.", e);
3918                 }
3919               }
3920             }
3921 
3922             // close all the opened datastores
3923             if(Gate.getDataStoreRegister() != null) {
3924               Set dataStores = new HashSet(Gate.getDataStoreRegister());
3925               for(Object aDs : dataStores) {
3926                 try {
3927                   if(aDs instanceof DataStore) {
3928                     ((DataStore)aDs).close();
3929                   }
3930                 }
3931                 catch(Throwable e) {
3932                   log.error(
3933                     "Some problems occurred when closing the datastores.", e);
3934                 }
3935               }
3936             }
3937 
3938           }
3939           catch(GateException e) {
3940             // we just ignore this
3941             log.error("A problem occurred when exiting from GATE.", e);
3942           }
3943 
3944         }// run
3945       };// Runnable
3946       Thread thread =
3947         new Thread(Thread.currentThread().getThreadGroup(), runnable,
3948           "Shutdown thread");
3949       thread.setPriority(Thread.MIN_PRIORITY);
3950       thread.start();
3951     }
3952   }
3953 
3954   class OpenDSAction extends AbstractAction {
3955     private static final long serialVersionUID = 1L;
3956     public OpenDSAction() {
3957       super("Open Datastore");
3958       putValue(SHORT_DESCRIPTION, "Open a datastore");
3959       putValue(SMALL_ICON, getIcon("datastore"));
3960     }
3961 
3962     public void actionPerformed(ActionEvent e) {
3963       Map<String,String> dsTypes = DataStoreRegister.getDataStoreClassNames();
3964       HashMap<String,String> dsTypeByName = new HashMap<String,String>();
3965       for(Map.Entry<String, String> entry : dsTypes.entrySet()) {
3966         dsTypeByName.put(entry.getValue(), entry.getKey());
3967       }
3968 
3969       if(!dsTypeByName.isEmpty()) {
3970         JLabel label = new JLabel("Select a type of Datastore:");
3971         final JList list = new JList(dsTypeByName.keySet().toArray());
3972         String initialSelection = Gate.getUserConfig().getString(
3973           MainFrame.class.getName()+".datastoretype");
3974         if (dsTypeByName.containsKey(initialSelection)) {
3975           list.setSelectedValue(initialSelection, true);
3976         else {
3977           list.setSelectedIndex(0);
3978         }
3979         list.setVisibleRowCount(Math.min(10, list.getModel().getSize()));
3980         list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
3981         final JOptionPane optionPane = new JOptionPane(
3982           new Object[]{label, new JScrollPane(list)},
3983           JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION,
3984           getIcon("datastore")new String[]{"OK""Cancel""Help"}"OK");
3985         final JDialog dialog = new JDialog(
3986           MainFrame.this, "Open a datastore"true);
3987         dialog.setContentPane(optionPane);
3988         list.addMouseListener(new MouseAdapter() {
3989           public void mouseClicked(MouseEvent e) {
3990             if (e.getClickCount() == 2) {
3991               optionPane.setValue("OK");
3992               dialog.setVisible(false);
3993             }
3994           }
3995         });
3996         optionPane.addPropertyChangeListener(new PropertyChangeListener() {
3997           public void propertyChange(PropertyChangeEvent e) {
3998             Object value = optionPane.getValue();
3999             if (value == null || value.equals(JOptionPane.UNINITIALIZED_VALUE)) {
4000               return;
4001             }
4002             if (dialog.isVisible()
4003             && e.getSource() == optionPane
4004             && e.getPropertyName().equals(JOptionPane.VALUE_PROPERTY)) {
4005               if (optionPane.getValue().equals("Help")) {
4006                 // don't close the dialog
4007                 optionPane.setValue(JOptionPane.UNINITIALIZED_VALUE);
4008                 showHelpFrame("sec:datastores""gate.persist.SerialDataStore");
4009               else {
4010                 dialog.setVisible(false);
4011               }
4012             }
4013           }
4014         });
4015         dialog.pack();
4016         dialog.setLocationRelativeTo(MainFrame.this);
4017         dialog.setVisible(true);
4018         Object answer = optionPane.getValue();
4019         if(answer == null) { return}
4020         String className = dsTypeByName.get(list.getSelectedValue());
4021         if(answer.equals("OK"&& !list.isSelectionEmpty()) {
4022           Gate.getUserConfig().put(MainFrame.class.getName()
4023             ".datastoretype", list.getSelectedValue());
4024           if(className.indexOf("SerialDataStore"!= -1) {
4025             openSerialDataStore();
4026           }
4027           else if(className.indexOf("LuceneDataStoreImpl"!= -1) {
4028             openSearchableDataStore();
4029           }
4030           else if(className.indexOf("DocServiceDataStore"!= -1) {
4031             openDocServiceDataStore();
4032           }
4033           else if(className.equals("gate.persist.OracleDataStore")
4034             || className.equals("gate.persist.PostgresDataStore")) {
4035             List dbPaths = new ArrayList();
4036             for(Object o : DataStoreRegister.getConfigData().keySet()) {
4037               String keyName = (Stringo;
4038               if(keyName.startsWith("url")) {
4039                 dbPaths.add(DataStoreRegister.getConfigData().get(keyName));
4040               }
4041             }
4042             if(dbPaths.isEmpty())
4043               throw new GateRuntimeException(
4044                 "JDBC URL not configured in gate.xml");
4045             // by default make it the first
4046             String storageURL = (String)dbPaths.get(0);
4047             if(dbPaths.size() 1) {
4048               Object[] paths = dbPaths.toArray();
4049               answer =
4050                 JOptionPane.showInputDialog(MainFrame.this,
4051                   "Select a database""GATE", JOptionPane.QUESTION_MESSAGE,
4052                   null, paths, paths[0]);
4053               if(answer != null)
4054                 storageURL = (String)answer;
4055               else return;
4056             }
4057             DataStore ds = null;
4058             AccessController ac = null;
4059             try {
4060               // 1. login the user
4061               // ac = new AccessControllerImpl(storageURL);
4062               ac = Factory.createAccessController(storageURL);
4063               Assert.assertNotNull(ac);
4064               ac.open();
4065 
4066               Session mySession;
4067               User usr;
4068               Group grp;
4069               try {
4070                 String userName = "";
4071                 String userPass = "";
4072                 String group = "";
4073 
4074                 JPanel listPanel = new JPanel();
4075                 listPanel.setLayout(new BoxLayout(listPanel, BoxLayout.X_AXIS));
4076 
4077                 JPanel panel1 = new JPanel();
4078                 panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS));
4079                 panel1.add(new JLabel("User name: "));
4080                 panel1.add(new JLabel("Password: "));
4081                 panel1.add(new JLabel("Group: "));
4082 
4083                 JPanel panel2 = new JPanel();
4084                 panel2.setLayout(new BoxLayout(panel2, BoxLayout.Y_AXIS));
4085                 JTextField usrField = new JTextField(30);
4086                 panel2.add(usrField);
4087                 JPasswordField pwdField = new JPasswordField(30);
4088                 panel2.add(pwdField);
4089                 JComboBox grpField = new JComboBox(ac.listGroups().toArray());
4090                 grpField.setSelectedIndex(0);
4091                 panel2.add(grpField);
4092 
4093                 listPanel.add(panel1);
4094                 listPanel.add(Box.createHorizontalStrut(20));
4095                 listPanel.add(panel2);
4096 
4097                 if(OkCancelDialog.showDialog(MainFrame.this.getContentPane(),
4098                   listPanel, "Please enter login details")) {
4099 
4100                   userName = usrField.getText();
4101                   userPass = new String(pwdField.getPassword());
4102                   group = (String)grpField.getSelectedItem();
4103 
4104                   if(userName.equals(""|| userPass.equals("")
4105                     || group.equals("")) {
4106                     JOptionPane
4107                       .showMessageDialog(
4108                         MainFrame.this,
4109                         "You must provide non-empty user name, password and group!",
4110                         "Login error", JOptionPane.ERROR_MESSAGE);
4111                     return;
4112                   }
4113                 }
4114                 else if(OkCancelDialog.userHasPressedCancel) { return}
4115 
4116                 grp = ac.findGroup(group);
4117                 usr = ac.findUser(userName);
4118                 mySession = ac.login(userName, userPass, grp.getID());
4119 
4120                 // save here the user name, pass and group in
4121                 // local gate.xml
4122 
4123               }
4124               catch(gate.security.SecurityException ex) {
4125                 JOptionPane.showMessageDialog(MainFrame.this, ex.getMessage(),
4126                   "Login error", JOptionPane.ERROR_MESSAGE);
4127                 ac.close();
4128                 return;
4129               }
4130 
4131               if(!ac.isValidSession(mySession)) {
4132                 JOptionPane.showMessageDialog(MainFrame.this,
4133                   "Incorrect session obtained. "
4134                     "Probably there is a problem with the database!",
4135                   "Login error", JOptionPane.ERROR_MESSAGE);
4136                 ac.close();
4137                 return;
4138               }
4139 
4140               // 2. open the oracle datastore
4141               ds = Factory.openDataStore(className, storageURL);
4142               // set the session, so all get/adopt/etc work
4143               ds.setSession(mySession);
4144 
4145               // 3. add the security data for this datastore
4146               // this saves the user and group information, so it
4147               // can
4148               // be used later when resources are created with
4149               // certain rights
4150               FeatureMap securityData = Factory.newFeatureMap();
4151               securityData.put("user", usr);
4152               securityData.put("group", grp);
4153               DataStoreRegister.addSecurityData(ds, securityData);
4154             }
4155             catch(PersistenceException pe) {
4156               JOptionPane.showMessageDialog(MainFrame.this,
4157                 "Datastore open error!\n " + pe.toString()"GATE",
4158                 JOptionPane.ERROR_MESSAGE);
4159             }
4160             catch(gate.security.SecurityException se) {
4161               JOptionPane.showMessageDialog(MainFrame.this,
4162                 "User identification error!\n " + se.toString()"GATE",
4163                 JOptionPane.ERROR_MESSAGE);
4164               try {
4165                 if(ac != nullac.close();
4166                 if(ds != nullds.close();
4167               }
4168               catch(gate.persist.PersistenceException ex) {
4169                 JOptionPane.showMessageDialog(MainFrame.this,
4170                   "Persistence error!\n " + ex.toString()"GATE",
4171                   JOptionPane.ERROR_MESSAGE);
4172               }
4173             }
4174 
4175           }
4176           else {
4177             JOptionPane.showMessageDialog(MainFrame.this,
4178               "Support for this type of datastores is not implemenented!\n",
4179               "GATE", JOptionPane.ERROR_MESSAGE);
4180           }
4181         }
4182       }
4183       else {
4184         // no ds types
4185         JOptionPane.showMessageDialog(MainFrame.this,
4186           "Could not find any registered types " "of datastores...\n"
4187             "Check your GATE installation!""GATE",
4188           JOptionPane.ERROR_MESSAGE);
4189 
4190       }
4191     }
4192   }// class OpenDSAction extends AbstractAction
4193 
4194   /**
4195    * A menu that self populates based on CREOLE register data before
4196    * being shown. Used for creating new resources of all possible types.
4197    */
4198   class LiveMenu extends XJMenu {
4199     public LiveMenu(int type) {
4200       super();
4201       this.type = type;
4202       init();
4203     }
4204 
4205     protected void init() {
4206       addMenuListener(new MenuListener() {
4207         public void menuCanceled(MenuEvent e) {
4208           // do nothing
4209         }
4210         public void menuDeselected(MenuEvent e) {
4211           // clear the status
4212           statusChanged("");
4213         }
4214         public void menuSelected(MenuEvent e) {
4215           removeAll();
4216           // find out the available types of LRs and repopulate the menu
4217           CreoleRegister reg = Gate.getCreoleRegister();
4218           List<String> resTypes;
4219           switch(type){
4220             case LR:
4221               resTypes = reg.getPublicLrTypes();
4222               break;
4223             case PR:
4224               resTypes = new ArrayList<String>reg.getPublicPrTypes() );
4225               //GATE default controllers are now also PRs, but we don't want
4226               //them here
4227               resTypes.removeAll(reg.getPublicControllerTypes());
4228               break;
4229             case APP:
4230               resTypes = reg.getPublicControllerTypes();
4231               break;
4232             default:
4233               throw new GateRuntimeException("Unknown LiveMenu type: " + type);
4234           }
4235 
4236           if(resTypes != null) {
4237             if (!resTypes.isEmpty()) {
4238               HashMap<String, ResourceData> resourcesByName
4239                 new HashMap<String, ResourceData>();
4240               Iterator<String> resIter = resTypes.iterator();
4241               while(resIter.hasNext()) {
4242                 ResourceData rData = reg.get(resIter.next());
4243                 resourcesByName.put(rData.getName(), rData);
4244               }
4245               List<String> resNames =
4246                 new ArrayList<String>(resourcesByName.keySet());
4247               Collections.sort(resNames);
4248               resIter = resNames.iterator();
4249               while(resIter.hasNext()) {
4250                 ResourceData rData = resourcesByName.get(resIter.next());
4251                 add(new XJMenuItem(new NewResourceAction(rData), MainFrame.this));
4252               }
4253             else if (type == PR) {
4254               // empty PR menu -> add an action to load ANNIE plugin
4255               add(new AbstractAction("Add ANNIE Resources to this Menu") {
4256                 putValue(SHORT_DESCRIPTION, "Load the ANNIE plugin.")}
4257                 public void actionPerformed(ActionEvent e) {
4258                 try {
4259                   URL pluginUrl = new File(Gate.getPluginsHome(),
4260                     ANNIEConstants.PLUGIN_DIR).toURI().toURL();
4261                   Gate.getCreoleRegister().registerDirectories(pluginUrl);
4262                   Gate.addAutoloadPlugin(pluginUrl);
4263                 catch(Exception ex) {
4264                   log.error("Unable to load ANNIE plugin.", ex);
4265                 }
4266               }});
4267             }
4268           }
4269 
4270           // fire the status listener events
4271           switch(type){
4272             case LR:
4273               statusChanged("Data used for annotating");
4274               break;
4275             case PR:
4276               statusChanged("Processes that annotate data");
4277               break;
4278             case APP:
4279               statusChanged("Run processes on data");
4280               break;
4281             default:
4282               statusChanged("Unknown resource: " + type);
4283           }
4284         }
4285       });
4286     }
4287 
4288     protected int type;
4289 
4290     /**
4291      * Switch for using LR data.
4292      */
4293     public static final int LR = 1;
4294 
4295     /**
4296      * Switch for using PR data.
4297      */
4298     public static final int PR = 2;
4299 
4300     /**
4301      * Switch for using Controller data.
4302      */
4303     public static final int APP = 3;
4304   }
4305 
4306   /**
4307    *  Recent applications menu that remembers previously loaded applications.
4308    */
4309   class RecentAppsMenu extends XJMenu {
4310     public RecentAppsMenu() {
4311       super();
4312       init();
4313       addMenuItems();
4314     }
4315 
4316     protected void init() {
4317       addMenuListener(new MenuListener() {
4318         public void menuCanceled(MenuEvent e) {
4319           // do nothing
4320         }
4321         public void menuDeselected(MenuEvent e) {
4322           // clear the status
4323           statusChanged("");
4324         }
4325         public void menuSelected(MenuEvent e) {
4326           removeAll();
4327           addMenuItems();
4328           if (getMenuComponentCount() == 0) {
4329             add("No Recent Applications");
4330           }
4331         }
4332       });
4333     }
4334 
4335     protected void addMenuItems() {
4336     final Map<String, String> locations = fileChooser.getLocations();
4337     final String list = locations.get("applications");
4338     if (list == null || list.equals("")) { return}
4339     for (final String name : list.split(";")) {
4340       final String location = locations.get("application." + name);
4341       final XJMenuItem item = new XJMenuItem(new AbstractAction(name,
4342         MainFrame.getIcon("open-application")) {
4343         this.putValue(Action.SHORT_DESCRIPTION, location)}
4344         public void actionPerformed(ActionEvent e) {
4345           Runnable runnable = new Runnable() { public void run() {
4346           try File file = new File(location);
4347             PersistenceManager.loadObjectFromFile(file);
4348           catch(Exception e) {
4349             String message = "Couldn't reload application.\n" + e.getMessage();
4350             alertButton.setAction(new AlertAction(e, message, null));
4351             if (instanceof IOException) {
4352               // remove selected element from the applications list
4353               locations.put("applications", list.replaceFirst(name + "(;|$)"""));
4354               fileChooser.setLocations(locations);
4355             }
4356           finally processFinished()}}};
4357           Thread thread = new Thread(runnable ,"Reload application");
4358           thread.setPriority(Thread.MIN_PRIORITY);
4359           thread.start();
4360       }}, MainFrame.this);
4361       item.addMenuKeyListener(new MenuKeyListener() {
4362         public void menuKeyTyped(MenuKeyEvent e) { /* do nothing */ }
4363         public void menuKeyPressed(MenuKeyEvent e) {
4364           if (e.getKeyCode() == KeyEvent.VK_DELETE) {
4365             // remove selected element from the applications list
4366             locations.put("applications", list.replaceFirst(name + "(;|$)"""));
4367             fileChooser.setLocations(locations);
4368             // TODO: update the menu
4369 //            item.setVisible(false);
4370 //            item.revalidate();
4371           }
4372         }
4373         public void menuKeyReleased(MenuKeyEvent e) {/* do nothing */ }
4374       });
4375       add(item);
4376     }
4377     add(new XJMenuItem(new AbstractAction("Clear List") {
4378       public void actionPerformed(ActionEvent e) {
4379         // clear the applications list
4380         locations.put("applications""");
4381         fileChooser.setLocations(locations);
4382     }}, MainFrame.this));
4383     }
4384   }
4385 
4386   /**
4387    * The "Tools" menu, which includes some static menu items
4388    * (added in initGuiComponents) and some dynamic items contributed
4389    * by plugins.
4390    @author ian
4391    */
4392   class ToolsMenu extends XJMenu implements CreoleListener {
4393 
4394     /**
4395      * The first position in the menu that can be used by dynamic
4396      * items.
4397      */
4398     protected int firstPluginItem = 0;
4399 
4400     protected IdentityHashMap<Resource, List<JMenuItem>> itemsByResource =
4401       new IdentityHashMap<Resource, List<JMenuItem>>();
4402 
4403     public ToolsMenu(String name, String description, StatusListener listener) {
4404       super(name, description, listener);
4405       Gate.getCreoleRegister().addCreoleListener(this);
4406     }
4407 
4408     /**
4409      * Called when the static items have been added to inform the menu
4410      * that it can start doing its dynamic stuff.
4411      */
4412     public void staticItemsAdded() {
4413       firstPluginItem = getItemCount();
4414       processExistingTools();
4415     }
4416 
4417     /**
4418      * Populate the menu with all actions coming from tools that are
4419      * already loaded.
4420      */
4421     protected void processExistingTools() {
4422       Set<String> toolTypes = Gate.getCreoleRegister().getToolTypes();
4423       for(String type : toolTypes) {
4424         List<Resource> instances = Gate.getCreoleRegister()
4425                     .get(type).getInstantiations();
4426         for(Resource res : instances) {
4427           if(res instanceof ActionsPublisher) {
4428             toolLoaded(res);
4429           }
4430         }
4431       }
4432     }
4433 
4434     /**
4435      * If the resource just loaded is a tool (according to the creole
4436      * register) then see if it publishes any actions and if so, add
4437      * them to the menu in the appropriate places.
4438      */
4439     public void resourceLoaded(CreoleEvent e) {
4440       Resource res = e.getResource();
4441       if(Gate.getCreoleRegister().get(res.getClass().getName()).isTool()
4442               && res instanceof ActionsPublisher) {
4443         toolLoaded(res);
4444       }
4445     }
4446 
4447     /**
4448      * Add the actions published by the given tool to their appropriate
4449      * places on the Tools menu.
4450      @param res the tool instance (which must implement ActionsPublisher)
4451      */
4452     protected void toolLoaded(Resource res) {
4453       List<Action> actions = ((ActionsPublisher)res).getActions();
4454       List<JMenuItem> items = new ArrayList<JMenuItem>();
4455       for(Action a : actions) {
4456         items.add(addMenuItem(a));
4457       }
4458       itemsByResource.put(res, items);
4459     }
4460 
4461     protected JMenuItem addMenuItem(Action a) {
4462       // start by searching this menu
4463       XJMenu menuToUse = this;
4464       int firstIndex = firstPluginItem;
4465       // if the action has a menu path set, navigate the path to find the
4466       // right menu.
4467       String[] menuPath = (String[])a.getValue(GateConstants.MENU_PATH_KEY);
4468       if(menuPath != null) {
4469         PATH_ELEMENT: for(String pathElement : menuPath) {
4470           int i;
4471           for(i = firstIndex; i < menuToUse.getItemCount(); i++) {
4472             JMenuItem item = menuToUse.getItem(i);
4473             if(item instanceof XJMenu && item.getText().equals(pathElement)) {
4474               // found the menu for this path element, move on to the next one
4475               firstIndex = 0;
4476               menuToUse = (XJMenu)item;
4477               continue PATH_ELEMENT;
4478             }
4479             else if(item.getText().compareTo(pathElement0) {
4480               // we've gone beyond where this menu should be in alpha
4481               // order
4482               break;
4483             }
4484           }
4485           // if we get to here, we didn't find a menu to use - add one
4486           XJMenu newMenu = new XJMenu(pathElement, pathElement, this.listener);
4487           menuToUse.add(newMenu);
4488           firstIndex = 0;
4489           menuToUse = newMenu;
4490         }
4491       }
4492 
4493       // we now have the right menu, add the action at the right place
4494       int pos = firstIndex;
4495       while(pos < menuToUse.getItemCount()) {
4496         JMenuItem item = menuToUse.getItem(pos);
4497         if(item != null && item.getText().compareTo((String)a.getValue(Action.NAME)) 0) {
4498           break;
4499         }
4500         pos++;
4501       }
4502       // finally, add the menu item and return it
4503       return menuToUse.insert(new XJMenuItem(a, this.listener), pos);
4504     }
4505 
4506     /**
4507      * If the resource just unloaded is one that contributed some menu
4508      * items then remove them again.
4509      */
4510     public void resourceUnloaded(CreoleEvent e) {
4511       Resource res = e.getResource();
4512       List<JMenuItem> items = itemsByResource.remove(res);
4513       if(items != null) {
4514         for(JMenuItem item : items) {
4515           removeMenuItem(item);
4516         }
4517       }
4518     }
4519 
4520     protected void removeMenuItem(JMenuItem itemToRemove) {
4521       Action a = itemToRemove.getAction();
4522       // start by searching this menu
4523       XJMenu menuToUse = this;
4524       int firstIndex = firstPluginItem;
4525       // keep track of the parent menu
4526       XJMenu parentMenu = null;
4527       // if the action has a menu path set, navigate the path to find the
4528       // right menu.
4529       String[] menuPath = (String[])a.getValue(GateConstants.MENU_PATH_KEY);
4530       if(menuPath != null) {
4531         PATH_ELEMENT: for(String pathElement : menuPath) {
4532           int i;
4533           for(i = firstIndex; i < menuToUse.getItemCount(); i++) {
4534             JMenuItem item = menuToUse.getItem(i);
4535             if(item instanceof XJMenu && item.getText().equals(pathElement)) {
4536               // found the menu for this path element, move on to the next one
4537               firstIndex = 0;
4538               parentMenu = menuToUse;
4539               menuToUse = (XJMenu)item;
4540               continue PATH_ELEMENT;
4541             }
4542           }
4543           // we've reached the end of a menu without finding the sub-menu
4544           // we were looking for.  This shouldn't happen, but if it does then
4545           // we can ignore it as if there's no menu to remove the thing from
4546           // then there's nothing to remove either.
4547           return;
4548         }
4549       }
4550 
4551       // we have a menu to remove the item from: remove it
4552       menuToUse.remove(itemToRemove);
4553       if(menuToUse.getItemCount() == && parentMenu != null) {
4554         // sub-menu is empty, remove it from parent
4555         parentMenu.remove(menuToUse);
4556       }
4557     }
4558 
4559     // remaining CreoleListener methods not used
4560     public void datastoreClosed(CreoleEvent e) { }
4561     public void datastoreCreated(CreoleEvent e) { }
4562     public void datastoreOpened(CreoleEvent e) { }
4563     public void resourceRenamed(Resource resource, String oldName,
4564             String newName) { }
4565   }
4566 
4567   /**
4568    * Overrides default JTree behaviour for tooltips.
4569    */
4570   class ResourcesTree extends JTree {
4571     private static final long serialVersionUID = 1L;
4572 
4573     public ResourcesTree() {
4574       myToolTip = new ResourceToolTip();
4575     }
4576 
4577     /**
4578      * Overrides <code>JTree</code>'s <code>getToolTipText</code>
4579      * method in order to allow custom tips to be used.
4580      *
4581      @param event the <code>MouseEvent</code> that initiated the
4582      *          <code>ToolTip</code> display
4583      @return a string containing the tooltip or <code>null</code> if
4584      *         <code>event</code> is null
4585      */
4586     public String getToolTipText(MouseEvent event) {
4587       String res = super.getToolTipText(event);
4588       if(event != null) {
4589         Point p = event.getPoint();
4590         int selRow = getRowForLocation(p.x, p.y);
4591         if(selRow != -1) {
4592           TreePath path = getPathForRow(selRow);
4593           Object lastPath = path.getLastPathComponent();
4594           Object value = ((DefaultMutableTreeNode)lastPath).getUserObject();
4595           myToolTip.setValue(value);
4596         }
4597       }
4598       // if we always return the same text, the tooltip manager thinks
4599       // the
4600       // size and location don't need changing.
4601       return res;
4602     }
4603 
4604     public JToolTip createToolTip() {
4605       return myToolTip;
4606     }
4607 
4608     ResourceToolTip myToolTip;
4609   }
4610 
4611   /**
4612    * Implementation of a custom tool tip to be used for showing extended
4613    * information about CREOLE resources.
4614    *
4615    */
4616   class ResourceToolTip extends JToolTip {
4617     private static final long serialVersionUID = 1L;
4618     public ResourceToolTip() {
4619       this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
4620 
4621       tipComponent = new JPanel();
4622       tipComponent.setOpaque(false);
4623       tipComponent.setLayout(new BoxLayout(tipComponent, BoxLayout.X_AXIS));
4624       tipComponent.setBorder(BorderFactory.createEmptyBorder(1111));
4625 
4626       iconLabel = new JLabel(getIcon("annie-application"));
4627       iconLabel.setText(null);
4628       iconLabel.setOpaque(false);
4629       tipComponent.add(iconLabel);
4630 
4631       textLabel = new JLabel();
4632       textLabel.setOpaque(false);
4633       tipComponent.add(Box.createHorizontalStrut(10));
4634       tipComponent.add(textLabel);
4635 
4636       add(tipComponent);
4637     }
4638 
4639     /**
4640      * Label used for the icon
4641      */
4642     JLabel iconLabel;
4643 
4644     /**
4645      * Label used for the text
4646      */
4647     JLabel textLabel;
4648 
4649     /**
4650      * The actual component displaying the tooltip.
4651      */
4652     JPanel tipComponent;
4653 
4654     public void setTipText(String tipText) {
4655       // textLabel.setText(tipText);
4656     }
4657 
4658     /**
4659      * Sets the value to be displayed
4660      *
4661      @param value to be displayed as tooltip
4662      */
4663     public void setValue(Object value) {
4664       if(value != null) {
4665         if(value instanceof String) {
4666           String text = (Stringvalue;
4667           if (text.equals("GATE")) {
4668             textLabel.setText("Resources tree root ");
4669             iconLabel.setIcon(getIcon("root"));
4670           else if (text.equals("Applications")) {
4671             textLabel.setText("Applications: run processes on data ");
4672             iconLabel.setIcon(getIcon("applications"));
4673           else if (text.equals("Language Resources")) {
4674             textLabel.setText("Language Resources: data used for annotating ");
4675             iconLabel.setIcon(getIcon("lrs"));
4676           else if (text.equals("Processing Resources")) {
4677             textLabel.setText(
4678               "Processing Resources: processes that annotate data ");
4679             iconLabel.setIcon(getIcon("prs"));
4680           else if (text.equals("Datastores")) {
4681             textLabel.setText("Datastores: repositories for large data ");
4682             iconLabel.setIcon(getIcon("datastores"));
4683           else {
4684             textLabel.setText(text);
4685             iconLabel.setIcon(null);
4686           }
4687         }
4688         else if(value instanceof NameBearerHandle) {
4689           NameBearerHandle handle = (NameBearerHandle)value;
4690           textLabel.setText(handle.getTooltipText());
4691           iconLabel.setIcon(handle.getIcon());
4692         }
4693         else {
4694           textLabel.setText(null);
4695           iconLabel.setIcon(null);
4696         }
4697       }
4698     }
4699 
4700     public Dimension getPreferredSize() {
4701       Dimension d = tipComponent.getPreferredSize();
4702       Insets ins = getInsets();
4703       return new Dimension(d.width + ins.left + ins.right, d.height + ins.top
4704         + ins.bottom);
4705     }
4706 
4707   }
4708 
4709   class HelpAboutAction extends AbstractAction {
4710     private static final long serialVersionUID = 1L;
4711     public HelpAboutAction() {
4712       super("About");
4713       putValue(SHORT_DESCRIPTION, "Show developers names and version");
4714     }
4715 
4716     public void actionPerformed(ActionEvent e) {
4717       splash.showSplash();
4718     }
4719   }
4720 
4721   class HelpMailingListAction extends AbstractAction {
4722     private static final long serialVersionUID = 1L;
4723     String keywords;
4724     public HelpMailingListAction() {
4725       super("Search in Mailing List");
4726       putValue(SHORT_DESCRIPTION,
4727         "Search keywords in GATE users mailing list");
4728       this.keywords = null;
4729     }
4730     public HelpMailingListAction(String keywords) {
4731       super("Search in Mailing List");
4732       this.keywords = keywords;
4733     }
4734     public void actionPerformed(ActionEvent e) {
4735       if (keywords == null) {
4736         keywords = JOptionPane.showInputDialog(instance,
4737             "Please enter your search keywords.",
4738             (Stringthis.getValue(NAME),
4739             JOptionPane.QUESTION_MESSAGE);
4740         if (keywords == null || keywords.trim().length() == 0) { return}
4741       }
4742       try {
4743       showHelpFrame("http://sourceforge.net/search/index.php?" +
4744        "group_id=143829&form_submit=Search&type_of_search=mlists" +
4745        "&q=" + java.net.URLEncoder.encode(keywords, "UTF-8"),
4746        "mailing list");
4747 
4748       catch (UnsupportedEncodingException error) {
4749         String message = "The Character Encoding is not supported.";
4750         alertButton.setAction(new AlertAction(error, message, null));
4751       finally {
4752         keywords = null;
4753       }
4754     }
4755   }
4756 
4757   class HelpUserGuideAction extends AbstractAction {
4758     private static final long serialVersionUID = 1L;
4759     public HelpUserGuideAction() {
4760       super("User Guide Contents");
4761       putValue(SHORT_DESCRIPTION, "Contents of the online user guide");
4762     }
4763 
4764     public void actionPerformed(ActionEvent e) {
4765       showHelpFrame("""help contents");
4766     }
4767   }
4768 
4769   public void showHelpFrame(String urlString, String resourceName) {
4770     final URL url;
4771     if (resourceName == null) { resourceName = "unknown"}
4772     if (urlString != null
4773     && !urlString.startsWith("http://")
4774     && !urlString.startsWith("file://")) {
4775       urlString = "http://gate.ac.uk/userguide/" + urlString;
4776     }
4777     try {
4778       url = new URL(urlString);
4779     catch (MalformedURLException e) {
4780       JOptionPane.showMessageDialog(MainFrame.this,
4781         (urlString == null?
4782         "There is no help page for this resource !\n\n" +
4783         "Find the developper of the resource:\n" +
4784         resourceName + "\n" "and force him/her to put one."
4785         :
4786         "The URL of the page for " + resourceName + " is invalid.\n"
4787         + urlString,
4788         "GATE", JOptionPane.INFORMATION_MESSAGE);
4789       return;
4790     }
4791     Runnable runnable = new Runnable() {
4792       public void run() {
4793         StringBuilder actualURL = new StringBuilder(url.toString());
4794         if (url.toString().startsWith("http://gate.ac.uk/userguide/")) {
4795           // add gateVersion=... to the end of the URL
4796           int insertPoint = actualURL.length();
4797           if(url.getRef() != null) {
4798             // adjust for a #something on the end
4799             insertPoint -= url.getRef().length() 1;
4800           }
4801           if(url.getQuery() == null) {
4802             actualURL.insert(insertPoint, '?');
4803           }
4804           else {
4805             actualURL.insert(insertPoint, "&");
4806           }
4807           actualURL.insert(insertPoint + 1"gateVersion=" + gate.Main.version);
4808         }
4809 
4810         Action[] actions = {
4811           new AbstractAction("Show configuration") {
4812             public void actionPerformed(ActionEvent e) {
4813               optionsDialog.showDialog();
4814               optionsDialog.dispose();
4815         }}};
4816 
4817         String commandLine = Gate.getUserConfig().getString(
4818           MainFrame.class.getName()+".browsercommandline");
4819 
4820         if(commandLine == null || commandLine.equals("")
4821         || commandLine.equals("Set dynamically when you display help.")) {
4822           // try to find the default browser
4823           Process process = null;
4824           try {
4825             // Windows
4826             commandLine = "rundll32 url.dll,FileProtocolHandler "
4827               + actualURL.toString();
4828             try process = Runtime.getRuntime().exec(commandLine);
4829             catch (IOException ioe2) {/* skip to next try catch */}
4830             if (process == null || process.waitFor() != 0) {
4831             // Linux
4832             commandLine = "xdg-open " + actualURL.toString();
4833             try process = Runtime.getRuntime().exec(commandLine);
4834             catch (IOException ioe3) {/* skip to next try catch */}
4835             if (process == null || process.waitFor() != 0) {
4836             // Linux KDE
4837             commandLine = "kfmclient exec " + actualURL.toString();
4838             try process = Runtime.getRuntime().exec(commandLine);
4839             catch (IOException ioe4) {/* skip to next try catch */}
4840             if (process == null || process.waitFor() != 0) {
4841             // Linux Gnome
4842             commandLine = "gnome-open " + actualURL.toString();
4843             try process = Runtime.getRuntime().exec(commandLine);
4844             catch (IOException ioe5) {/* skip to next try catch */}
4845             if (process == null || process.waitFor() != 0) {
4846             // Mac
4847             commandLine = "open " + actualURL.toString();
4848             try process = Runtime.getRuntime().exec(commandLine);
4849             catch (IOException ioe1) {/* skip to next try catch */}
4850             if (process == null || process.waitFor() != 0) {
4851             String message = "Unable to determine the default browser.\n"
4852               "Will use a Java browser. To use a custom command line\n"
4853               "go to the Options menu then Configuration.";
4854             alertButton.setAction(new AlertAction(null, message, actions));
4855             // Java help browser
4856             displayJavaHelpBrowser(actualURL.toString());
4857             }}}}}
4858           catch(SecurityException se) {
4859             JOptionPane.showMessageDialog(instance,
4860               se.getMessage()"Help Error", JOptionPane.ERROR_MESSAGE);
4861             log.error("Help browser Error", se);
4862           catch (InterruptedException ie) {
4863             JOptionPane.showMessageDialog(instance,
4864               ie.getMessage()"Help Error", JOptionPane.ERROR_MESSAGE);
4865             log.error("Help browser Error", ie);
4866           }
4867 
4868         else if(!commandLine.equals("Internal Java browser.")) {
4869           // external browser
4870           commandLine = commandLine.replaceFirst("%file", actualURL.toString());
4871           try {
4872             Runtime.getRuntime().exec(commandLine);
4873           }
4874           catch(Exception error) {
4875             String message = "Unable to call the custom browser command.\n" +
4876               "(" +  commandLine + ")\n\n" +
4877               "Please go to the Options menu then Configuration.";
4878             alertButton.setAction(new AlertAction(error, message, actions));
4879           }
4880 
4881         else {
4882           displayJavaHelpBrowser(actualURL.toString());
4883       }
4884       }
4885     };
4886     Thread thread = new Thread(runnable, "showHelpFrame");
4887     thread.start();
4888   }
4889 
4890   private void displayJavaHelpBrowser(String urlString) {
4891     if (helpFrame == null) {
4892       helpFrame = new HelpFrame();
4893       helpFrame.setSize(800600);
4894       helpFrame.setDefaultCloseOperation(HIDE_ON_CLOSE);
4895       // center on screen
4896       Dimension frameSize = helpFrame.getSize();
4897       Dimension ownerSize = Toolkit.getDefaultToolkit().getScreenSize();
4898       Point ownerLocation = new Point(00);
4899       helpFrame.setLocation(ownerLocation.x
4900          (ownerSize.width - frameSize.width2, ownerLocation.y
4901          (ownerSize.height - frameSize.height2);
4902     }
4903     try {
4904       helpFrame.setPage(new URL(urlString));
4905     catch (IOException error) {
4906       String message = "Error when loading help page.";
4907       alertButton.setAction(new AlertAction(error, message, null));
4908       return;
4909     }
4910     helpFrame.setVisible(false);
4911     helpFrame.setVisible(true);
4912   }
4913 
4914   class HelpUserGuideInContextAction extends AbstractAction {
4915     private static final long serialVersionUID = 1L;
4916     public HelpUserGuideInContextAction() {
4917       super("Contextual User Guide");
4918       putValue(SHORT_DESCRIPTION, "Online help for the selected component");
4919       putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("F1"));
4920     }
4921 
4922     public void actionPerformed(ActionEvent e) {
4923       // get the handle for the selected tab pane resource view
4924       // then call HelpOnItemTreeAction with this handle
4925       JComponent largeView = (JComponent)
4926         mainTabbedPane.getSelectedComponent();
4927       if (largeView == null) { return}
4928       Enumeration nodesEnum = resourcesTreeRoot.preorderEnumeration();
4929       boolean done = false;
4930       DefaultMutableTreeNode node = resourcesTreeRoot;
4931       while(!done && nodesEnum.hasMoreElements()) {
4932         node = (DefaultMutableTreeNodenodesEnum.nextElement();
4933         done = node.getUserObject() instanceof Handle
4934             && ((Handle)node.getUserObject()).viewsBuilt()
4935             && ((Handle)node.getUserObject()).getLargeView() == largeView;
4936       }
4937       if(done && (Handle)node.getUserObject() instanceof NameBearerHandle) {
4938         new HelpOnItemTreeAction((NameBearerHandle)node.getUserObject())
4939           .actionPerformed(null);
4940       else if (mainTabbedPane.getTitleAt(mainTabbedPane
4941                   .getSelectedIndex()).equals("Messages")) {
4942         showHelpFrame("sec:developer:gui""messages pane");
4943       else {
4944         showHelpFrame(null, node.getUserObject().getClass().getName());
4945       }
4946     }
4947   }
4948 
4949   class HelpOnItemTreeAction extends AbstractAction {
4950     private static final long serialVersionUID = 1L;
4951     HelpOnItemTreeAction(NameBearerHandle resource) {
4952       super("Help");
4953       putValue(SHORT_DESCRIPTION, "Help on this resource");
4954       this.resource = resource;
4955     }
4956 
4957     public void actionPerformed(ActionEvent e) {
4958       String helpURL = null;
4959       String resourceClassName = resource.getTarget().getClass().getName();
4960 
4961       if (resource.getTarget() instanceof Resource) {
4962         // search the help URL associated to the resource
4963         ResourceData rd = Gate.getCreoleRegister().get(resourceClassName);
4964         helpURL = rd.getHelpURL();
4965       }
4966 
4967       if(helpURL == null) {
4968         // otherwise search in the associated VRs of the resource
4969         List<String> vrList = Gate.getCreoleRegister()
4970           .getLargeVRsForResource(resourceClassName);
4971         for(String vrClass : vrList) {
4972           ResourceData vrd = Gate.getCreoleRegister().get(vrClass);
4973           if(vrd != null && vrd.getHelpURL() != null) {
4974             helpURL = vrd.getHelpURL();
4975             break;
4976           }
4977         }
4978       }
4979       showHelpFrame(helpURL, resourceClassName);
4980     }
4981 
4982     NameBearerHandle resource;
4983   }
4984 
4985   class ToggleToolTipsAction extends AbstractAction {
4986     public ToggleToolTipsAction() {
4987       super("Show Tooltips");
4988       putValue(SHORT_DESCRIPTION,
4989         "Tooltips appear in help balloon like this one");
4990     }
4991     public void actionPerformed(ActionEvent e) {
4992       Runnable runnable = new Runnable() {
4993         public void run() {
4994           javax.swing.ToolTipManager toolTipManager =
4995             ToolTipManager.sharedInstance();
4996           if (toolTipManager.isEnabled()) {
4997             toolTipManager.setEnabled(false);
4998             Gate.getUserConfig().put(
4999               MainFrame.class.getName()+".hidetooltips"false);
5000           else {
5001             toolTipManager.setEnabled(true);
5002             Gate.getUserConfig().put(
5003               MainFrame.class.getName()+".hidetooltips"true);
5004           }
5005         }
5006       };
5007       Thread thread = new Thread(runnable, "ToggleToolTipsAction");
5008       thread.start();
5009     }
5010   }
5011 
5012 
5013   protected class ResourcesTreeCellRenderer extends DefaultTreeCellRenderer {
5014     private static final long serialVersionUID = 1L;
5015     public ResourcesTreeCellRenderer() {
5016       setBorder(BorderFactory.createEmptyBorder(2222));
5017     }
5018 
5019     public Component getTreeCellRendererComponent(JTree tree, Object value,
5020       boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
5021       super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row,
5022         hasFocus);
5023       if(value == resourcesTreeRoot) {
5024         setIcon(MainFrame.getIcon("root"));
5025         setToolTipText("Resources tree root ");
5026       }
5027       else if(value == applicationsRoot) {
5028         setIcon(MainFrame.getIcon("applications"));
5029         setToolTipText("Run processes on data ");
5030       }
5031       else if(value == languageResourcesRoot) {
5032         setIcon(MainFrame.getIcon("lrs"));
5033         setToolTipText("Data used for annotating ");
5034       }
5035       else if(value == processingResourcesRoot) {
5036         setIcon(MainFrame.getIcon("prs"));
5037         setToolTipText("Processes that annotate data ");
5038       }
5039       else if(value == datastoresRoot) {
5040         setIcon(MainFrame.getIcon("datastores"));
5041         setToolTipText("Repositories for large data ");
5042       }
5043       else {
5044         // not one of the default root nodes
5045         value = ((DefaultMutableTreeNode)value).getUserObject();
5046         if(value instanceof Handle) {
5047           setIcon(((Handle)value).getIcon());
5048           setText(((Handle)value).getTitle());
5049           setToolTipText(((Handle)value).getTooltipText());
5050         }
5051       }
5052       return this;
5053     }
5054 
5055   }
5056 
5057   protected class ResourcesTreeCellEditor extends DefaultTreeCellEditor {
5058     ResourcesTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer) {
5059       super(tree, renderer);
5060     }
5061 
5062     /**
5063      * This is the original implementation from the super class with
5064      * some changes (i.e. shorter timer: 500 ms instead of 1200)
5065      */
5066     protected void startEditingTimer() {
5067       if(timer == null) {
5068         timer = new javax.swing.Timer(500this);
5069         timer.setRepeats(false);
5070       }
5071       timer.start();
5072     }
5073 
5074     /**
5075      * This is the original implementation from the super class with
5076      * some changes (i.e. correct discovery of icon)
5077      */
5078     public Component getTreeCellEditorComponent(JTree tree, Object value,
5079       boolean isSelected, boolean expanded, boolean leaf, int row) {
5080       Component retValue =
5081         super.getTreeCellEditorComponent(tree, value, isSelected, expanded,
5082           leaf, row);
5083       // lets find the actual icon
5084       if(renderer != null) {
5085         renderer.getTreeCellRendererComponent(tree, value, isSelected,
5086           expanded, leaf, row, false);
5087         editingIcon = renderer.getIcon();
5088       }
5089       return retValue;
5090     }
5091   }// protected class ResourcesTreeCellEditor extends
5092   // DefaultTreeCellEditor {
5093 
5094   protected class ResourcesTreeModel extends DefaultTreeModel {
5095     private static final long serialVersionUID = 1L;
5096     ResourcesTreeModel(TreeNode root, boolean asksAllowChildren) {
5097       super(root, asksAllowChildren);
5098     }
5099 
5100     public void valueForPathChanged(TreePath path, Object newValue) {
5101       DefaultMutableTreeNode aNode =
5102         (DefaultMutableTreeNode)path.getLastPathComponent();
5103       Object userObject = aNode.getUserObject();
5104       if(userObject instanceof Handle) {
5105         Handle handle = (Handle)userObject;
5106         Object target = handle.getTarget();
5107         if(target instanceof Resource) {
5108           Gate.getCreoleRegister().setResourceName((Resource)target,
5109             (String)newValue);
5110         else if(target instanceof NameBearer){
5111           //not a resource, we need to do it manually
5112           ((NameBearer)target).setName((String)newValue);
5113           //next see if there is a tab for this resource and rename it
5114           for(int i = 0; i < mainTabbedPane.getTabCount(); i++) {
5115             if(mainTabbedPane.getComponentAt(i== handle.getLargeView()) {
5116               mainTabbedPane.setTitleAt(i, (String)newValue);
5117               break;
5118             }
5119           }
5120         }
5121       }
5122       nodeChanged(aNode);
5123 
5124     }
5125   }
5126 
5127   class ProgressBarUpdater implements Runnable {
5128     ProgressBarUpdater(int newValue) {
5129       value = newValue;
5130     }
5131 
5132     public void run() {
5133       if(value == 0)
5134         progressBar.setVisible(false);
5135       else progressBar.setVisible(true);
5136       progressBar.setValue(value);
5137     }
5138 
5139     int value;
5140   }
5141 
5142   class StatusBarUpdater implements Runnable {
5143     StatusBarUpdater(String text) {
5144       this.text = text;
5145     }
5146 
5147     public void run() {
5148       statusBar.setText(text);
5149     }
5150 
5151     String text;
5152   }
5153 
5154   /**
5155    * During longer operations it is nice to keep the user entertained so
5156    * (s)he doesn't fall asleep looking at a progress bar that seems have
5157    * stopped. Also there are some operations that do not support
5158    * progress reporting so the progress bar would not work at all so we
5159    * need a way to let the user know that things are happening. We chose
5160    * for purpose to show the user a small cartoon in the form of an
5161    * animated gif. This class handles the displaying and updating of
5162    * those cartoons.
5163    */
5164   class CartoonMinder implements Runnable {
5165 
5166     CartoonMinder(JPanel targetPanel) {
5167       active = false;
5168       dying = false;
5169       this.targetPanel = targetPanel;
5170       imageLabel = new JLabel(getIcon("working"));
5171       imageLabel.setOpaque(false);
5172       imageLabel.setBorder(BorderFactory.createEmptyBorder(3333));
5173     }
5174 
5175     public boolean isActive() {
5176       boolean res;
5177       synchronized(lock) {
5178         res = active;
5179       }
5180       return res;
5181     }
5182 
5183     public void activate() {
5184       // add the label in the panel
5185       SwingUtilities.invokeLater(new Runnable() {
5186         public void run() {
5187           targetPanel.add(imageLabel);
5188         }
5189       });
5190       // wake the dormant thread
5191       synchronized(lock) {
5192         active = true;
5193       }
5194     }
5195 
5196     public void deactivate() {
5197       // send the thread to sleep
5198       synchronized(lock) {
5199         active = false;
5200       }
5201       // clear the panel
5202       SwingUtilities.invokeLater(new Runnable() {
5203         public void run() {
5204           targetPanel.removeAll();
5205           targetPanel.repaint();
5206         }
5207       });
5208     }
5209 
5210     public void dispose() {
5211       synchronized(lock) {
5212         dying = true;
5213       }
5214     }
5215 
5216     public void run() {
5217       boolean isDying;
5218       synchronized(lock) {
5219         isDying = dying;
5220       }
5221       while(!isDying) {
5222         boolean isActive;
5223         synchronized(lock) {
5224           isActive = active;
5225         }
5226         if(isActive && targetPanel.isVisible()) {
5227           SwingUtilities.invokeLater(new Runnable() {
5228             public void run() {
5229               // targetPanel.getParent().validate();
5230               // targetPanel.getParent().repaint();
5231               // ((JComponent)targetPanel.getParent()).paintImmediately(((JComponent)targetPanel.getParent()).getBounds());
5232               // targetPanel.doLayout();
5233 
5234               // targetPanel.requestFocus();
5235               targetPanel.getParent().getParent().invalidate();
5236               targetPanel.getParent().getParent().repaint();
5237               // targetPanel.paintImmediately(targetPanel.getBounds());
5238             }
5239           });
5240         }
5241         // sleep
5242         try {
5243           Thread.sleep(300);
5244         }
5245         catch(InterruptedException ie) {
5246           log.debug("Animation interrupted", ie);
5247         }
5248 
5249         synchronized(lock) {
5250           isDying = dying;
5251         }
5252       }// while(!isDying)
5253     }
5254 
5255     boolean dying;
5256 
5257     boolean active;
5258 
5259     final String lock = "lock";
5260 
5261     JPanel targetPanel;
5262 
5263     JLabel imageLabel;
5264   }
5265 
5266   class LocaleSelectorMenuItem extends JRadioButtonMenuItem {
5267     private static final long serialVersionUID = 1L;
5268     public LocaleSelectorMenuItem(Locale locale) {
5269       super(locale.getDisplayName());
5270       me = this;
5271       myLocale = locale;
5272       this.addActionListener(new ActionListener() {
5273         public void actionPerformed(ActionEvent e) {
5274           for(Component aRoot : MainFrame.getGuiRoots()) {
5275             if(aRoot instanceof Window) {
5276               me.setSelected(aRoot.getInputContext()
5277                 .selectInputMethod(myLocale));
5278             }
5279           }
5280         }
5281       });
5282     }
5283 
5284     public LocaleSelectorMenuItem() {
5285       super("System Default  >>" + Locale.getDefault().getDisplayName() "<<");
5286       me = this;
5287       myLocale = Locale.getDefault();
5288       this.addActionListener(new ActionListener() {
5289         public void actionPerformed(ActionEvent e) {
5290           for(Component aRoot : MainFrame.getGuiRoots()) {
5291             if(aRoot instanceof Window) {
5292               me.setSelected(aRoot.getInputContext()
5293                 .selectInputMethod(myLocale));
5294             }
5295           }
5296         }
5297       });
5298     }
5299 
5300     Locale myLocale;
5301 
5302     JRadioButtonMenuItem me;
5303   }// //class LocaleSelectorMenuItem extends JRadioButtonMenuItem
5304 
5305   /**
5306    * This class represent an action which brings up the Gazetteer Editor
5307    * tool
5308    */
5309   class NewGazetteerEditorAction extends AbstractAction {
5310     private static final long serialVersionUID = 1L;
5311     public NewGazetteerEditorAction() {
5312       super("Gazetteer Editor", getIcon("gazetteer"));
5313       putValue(SHORT_DESCRIPTION, "Start the Gazetteer Editor");
5314     }
5315 
5316     public void actionPerformed(ActionEvent e) {
5317       com.ontotext.gate.vr.Gaze editor = new com.ontotext.gate.vr.Gaze();
5318       try {
5319         JFrame frame = new JFrame();
5320         editor.init();
5321         frame.setTitle("Gazetteer Editor");
5322         frame.getContentPane().add(editor);
5323 
5324         Set<LanguageResource> gazetteers = new HashSet<LanguageResource>(
5325           Gate.getCreoleRegister().getLrInstances(
5326           "gate.creole.gazetteer.DefaultGazetteer"));
5327         if(gazetteers.isEmpty()) { return}
5328         for(LanguageResource gazetteer : gazetteers) {
5329           Gazetteer gaz = (Gazetteergazetteer;
5330           if(gaz.getListsURL().toString().endsWith(
5331             System.getProperty("gate.slug.gazetteer"))) editor.setTarget(gaz);
5332         }
5333 
5334         frame.setSize(Gaze.SIZE_X, Gaze.SIZE_Y);
5335         frame.setLocation(Gaze.POSITION_X, Gaze.POSITION_Y);
5336         frame.setVisible(true);
5337         editor.setVisible(true);
5338       }
5339       catch(ResourceInstantiationException error) {
5340         String message = "Failed to instanciate the gazetteer editor.";
5341         Action[] actions = {
5342           new AbstractAction("Load plugins manager") {
5343             public void actionPerformed(ActionEvent e) {
5344               (new ManagePluginsAction()).actionPerformed(null);
5345         }}};
5346         alertButton.setAction(new AlertAction(error, message, actions));
5347       }
5348     }// actionPerformed();
5349   }// class NewOntologyEditorAction
5350 
5351   class AlertAction extends AbstractAction {
5352     private Timer timer =
5353       new java.util.Timer("MainFrame alert tooltip hide timer"true);
5354 
5355     /**
5356      * Action for the alert button that shows a message in a popup.
5357      * A detailed dialog can be shown when the button or popup are clicked.
5358      * Log the message and error as soon as the action is created.
5359      @param error can be null in case of info message.
5360      @param message text to be displayed in a popup and dialogue
5361      @param actions actions the user can choose in the dialogue
5362      */
5363     public AlertAction(Throwable error, String message, Action[] actions) {
5364       if (error == null) {
5365         log.info(message);
5366       else {
5367         log.error(message, error);
5368       }
5369       String description = "<html>" (error == null ?
5370         "Important information:<br>" "There was a problem:<br>"+
5371         message.substring(0, Math.min(300, message.length()))
5372           .replaceAll("(.{40,50}(?:\\b|\\.|/))""$1<br>""</html>";
5373       final int lines = description.split("<br>").length;
5374       putValue(Action.SMALL_ICON, MainFrame.getIcon("crystal-clear-app-error"));
5375       putValue(Action.SHORT_DESCRIPTION, description);
5376 
5377       this.error = error;
5378       this.message = message;
5379       if (actions == null) {
5380         this.actions = new Action[1];
5381       else {
5382         this.actions = new Action[actions.length+1];
5383         System.arraycopy(actions, 0this.actions, 0, actions.length);
5384       }
5385       // add a 'search in mailing list' action
5386       this.actions[this.actions.length-1new HelpMailingListAction(message);
5387       // show for a few seconds a popup with the error message
5388       SwingUtilities.invokeLater(new Runnable() {
5389         public void run() {
5390           if (!instance.isShowing()) { return}
5391           alertButton.setEnabled(true);
5392           JToolTip toolTip = alertButton.createToolTip();
5393           toolTip.setTipText(alertButton.getToolTipText());
5394           PopupFactory popupFactory = PopupFactory.getSharedInstance();
5395           final Popup popup = popupFactory.getPopup(alertButton, toolTip,
5396             instance.getLocationOnScreen().x+instance.getWidth()/2-100,
5397             instance.getLocationOnScreen().y+instance.getHeight()-30-(lines*10));
5398           toolTip.addMouseListener(new MouseAdapter() {
5399             public void mouseClicked(MouseEvent e) {
5400               popup.hide();
5401               alertButton.doClick();
5402             }
5403           });
5404           popup.show();
5405           Date timeToRun = new Date(System.currentTimeMillis() 4000);
5406           timer.schedule(new TimerTask() {
5407             public void run() {
5408               SwingUtilities.invokeLater(new Runnable(){
5409                 public void run() {
5410                   popup.hide()// hide the tooltip after some time
5411                 }
5412               });
5413             }
5414           }, timeToRun);
5415         }
5416       });
5417     }
5418     public void actionPerformed(ActionEvent e) {
5419       ErrorDialog.show(error, message, instance, getIcon("root"), actions);
5420     }
5421     Throwable error;
5422     String message;
5423     Action[] actions;
5424   }
5425 
5426 // class MainFrame