MainFrame.java
0001 /*
0002  *  Copyright (c) 1995-2012, The University of Sheffield. See the file
0003  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
0004  *
0005  *  This file is part of GATE (see http://gate.ac.uk/), and is free
0006  *  software, licenced under the GNU Library General Public License,
0007  *  Version 2, June 1991 (in the distribution as file licence.html,
0008  *  and also available at http://gate.ac.uk/gate/licence.html).
0009  *
0010  *  Valentin Tablan 22/01/2001
0011  *
0012  *  $Id: MainFrame.java 19414 2016-06-10 09:12:54Z markagreenwood $
0013  *
0014  */
0015 
0016 package gate.gui;
0017 
0018 import gate.Controller;
0019 import gate.CreoleRegister;
0020 import gate.DataStore;
0021 import gate.DataStoreRegister;
0022 import gate.Document;
0023 import gate.Executable;
0024 import gate.Factory;
0025 import gate.Gate;
0026 import gate.GateConstants;
0027 import gate.LanguageResource;
0028 import gate.Main;
0029 import gate.ProcessingResource;
0030 import gate.Resource;
0031 import gate.VisualResource;
0032 import gate.creole.ANNIEConstants;
0033 import gate.creole.ConditionalSerialAnalyserController;
0034 import gate.creole.PackagedController;
0035 import gate.creole.ResourceData;
0036 import gate.creole.ResourceInstantiationException;
0037 import gate.creole.annic.Constants;
0038 import gate.event.CreoleEvent;
0039 import gate.event.CreoleListener;
0040 import gate.event.PluginListener;
0041 import gate.event.ProgressListener;
0042 import gate.event.StatusListener;
0043 import gate.gui.creole.manager.PluginUpdateManager;
0044 import gate.persist.PersistenceException;
0045 import gate.resources.img.svg.AvailableIcon;
0046 import gate.resources.img.svg.GATEIcon;
0047 import gate.resources.img.svg.GATEVersionIcon;
0048 import gate.resources.img.svg.ReadyMadeIcon;
0049 import gate.swing.JMenuButton;
0050 import gate.swing.XJFileChooser;
0051 import gate.swing.XJMenu;
0052 import gate.swing.XJMenuItem;
0053 import gate.swing.XJPopupMenu;
0054 import gate.swing.XJTabbedPane;
0055 import gate.util.Benchmark;
0056 import gate.util.CorpusBenchmarkTool;
0057 import gate.util.ExtensionFileFilter;
0058 import gate.util.Files;
0059 import gate.util.GateClassLoader;
0060 import gate.util.GateException;
0061 import gate.util.GateRuntimeException;
0062 import gate.util.LuckyException;
0063 import gate.util.NameBearer;
0064 import gate.util.OptionsMap;
0065 import gate.util.Out;
0066 import gate.util.persistence.PersistenceManager;
0067 import gate.util.reporting.DocTimeReporter;
0068 import gate.util.reporting.PRTimeReporter;
0069 import gate.util.reporting.exceptions.BenchmarkReportException;
0070 
0071 import java.awt.AWTEvent;
0072 import java.awt.BorderLayout;
0073 import java.awt.Color;
0074 import java.awt.Component;
0075 import java.awt.Dialog;
0076 import java.awt.Dimension;
0077 import java.awt.Frame;
0078 import java.awt.GraphicsConfiguration;
0079 import java.awt.GraphicsEnvironment;
0080 import java.awt.GridBagConstraints;
0081 import java.awt.GridBagLayout;
0082 import java.awt.Image;
0083 import java.awt.Insets;
0084 import java.awt.KeyboardFocusManager;
0085 import java.awt.Point;
0086 import java.awt.Rectangle;
0087 import java.awt.Toolkit;
0088 import java.awt.Window;
0089 import java.awt.datatransfer.DataFlavor;
0090 import java.awt.datatransfer.StringSelection;
0091 import java.awt.datatransfer.Transferable;
0092 import java.awt.event.ActionEvent;
0093 import java.awt.event.ActionListener;
0094 import java.awt.event.ComponentAdapter;
0095 import java.awt.event.ComponentEvent;
0096 import java.awt.event.InputEvent;
0097 import java.awt.event.KeyAdapter;
0098 import java.awt.event.KeyEvent;
0099 import java.awt.event.MouseAdapter;
0100 import java.awt.event.MouseEvent;
0101 import java.awt.event.WindowEvent;
0102 import java.beans.PropertyChangeEvent;
0103 import java.beans.PropertyChangeListener;
0104 import java.io.File;
0105 import java.io.IOException;
0106 import java.io.PrintStream;
0107 import java.io.UnsupportedEncodingException;
0108 import java.lang.reflect.Constructor;
0109 import java.lang.reflect.InvocationHandler;
0110 import java.lang.reflect.Method;
0111 import java.lang.reflect.Proxy;
0112 import java.net.MalformedURLException;
0113 import java.net.URI;
0114 import java.net.URISyntaxException;
0115 import java.net.URL;
0116 import java.text.NumberFormat;
0117 import java.util.ArrayList;
0118 import java.util.Arrays;
0119 import java.util.Collection;
0120 import java.util.Collections;
0121 import java.util.Date;
0122 import java.util.Enumeration;
0123 import java.util.HashMap;
0124 import java.util.HashSet;
0125 import java.util.IdentityHashMap;
0126 import java.util.Iterator;
0127 import java.util.List;
0128 import java.util.Map;
0129 import java.util.Set;
0130 import java.util.regex.Matcher;
0131 import java.util.regex.Pattern;
0132 
0133 import javax.swing.AbstractAction;
0134 import javax.swing.Action;
0135 import javax.swing.ActionMap;
0136 import javax.swing.BorderFactory;
0137 import javax.swing.Box;
0138 import javax.swing.BoxLayout;
0139 import javax.swing.ButtonGroup;
0140 import javax.swing.Icon;
0141 import javax.swing.ImageIcon;
0142 import javax.swing.InputMap;
0143 import javax.swing.JButton;
0144 import javax.swing.JCheckBox;
0145 import javax.swing.JCheckBoxMenuItem;
0146 import javax.swing.JComboBox;
0147 import javax.swing.JComponent;
0148 import javax.swing.JDialog;
0149 import javax.swing.JFileChooser;
0150 import javax.swing.JFrame;
0151 import javax.swing.JLabel;
0152 import javax.swing.JList;
0153 import javax.swing.JMenu;
0154 import javax.swing.JMenuBar;
0155 import javax.swing.JMenuItem;
0156 import javax.swing.JOptionPane;
0157 import javax.swing.JPanel;
0158 import javax.swing.JPopupMenu;
0159 import javax.swing.JProgressBar;
0160 import javax.swing.JRadioButtonMenuItem;
0161 import javax.swing.JScrollPane;
0162 import javax.swing.JSplitPane;
0163 import javax.swing.JTabbedPane;
0164 import javax.swing.JTable;
0165 import javax.swing.JTextField;
0166 import javax.swing.JToolBar;
0167 import javax.swing.JToolTip;
0168 import javax.swing.JTree;
0169 import javax.swing.KeyStroke;
0170 import javax.swing.ListSelectionModel;
0171 import javax.swing.OverlayLayout;
0172 import javax.swing.SwingConstants;
0173 import javax.swing.SwingUtilities;
0174 import javax.swing.ToolTipManager;
0175 import javax.swing.TransferHandler;
0176 import javax.swing.UIManager;
0177 import javax.swing.event.ChangeEvent;
0178 import javax.swing.event.ChangeListener;
0179 import javax.swing.event.MenuEvent;
0180 import javax.swing.event.MenuKeyEvent;
0181 import javax.swing.event.MenuKeyListener;
0182 import javax.swing.event.MenuListener;
0183 import javax.swing.event.TreeSelectionEvent;
0184 import javax.swing.event.TreeSelectionListener;
0185 import javax.swing.tree.DefaultMutableTreeNode;
0186 import javax.swing.tree.DefaultTreeCellEditor;
0187 import javax.swing.tree.DefaultTreeCellRenderer;
0188 import javax.swing.tree.DefaultTreeModel;
0189 import javax.swing.tree.TreeNode;
0190 import javax.swing.tree.TreePath;
0191 import javax.swing.tree.TreeSelectionModel;
0192 
0193 import org.apache.log4j.Appender;
0194 import org.apache.log4j.FileAppender;
0195 import org.apache.log4j.Layout;
0196 import org.apache.log4j.Logger;
0197 import org.apache.log4j.PatternLayout;
0198 
0199 /**
0200  * The main Gate GUI frame.
0201  */
0202 @SuppressWarnings("serial")
0203 public class MainFrame extends JFrame implements ProgressListener,
0204                                      StatusListener, CreoleListener, PluginListener {
0205 
0206   protected static final Logger log = Logger.getLogger(MainFrame.class);
0207 
0208   protected JMenuBar menuBar;
0209 
0210   protected JSplitPane mainSplit;
0211 
0212   protected JSplitPane leftSplit;
0213 
0214   protected JLabel statusBar;
0215 
0216   protected JProgressBar progressBar;
0217 
0218   protected JProgressBar globalProgressBar;
0219 
0220   protected XJTabbedPane mainTabbedPane;
0221 
0222   protected JScrollPane lowerScroll;
0223 
0224   /**
0225    * Popup used for right click actions on the Applications node.
0226    */
0227   protected JPopupMenu appsPopup;
0228   
0229   /**
0230    * Popup used for right click actions on the Datastores node.
0231    */
0232   protected JPopupMenu dssPopup;
0233 
0234   /**
0235    * Popup used for right click actions on the LRs node.
0236    */
0237   protected JPopupMenu lrsPopup;
0238 
0239   /**
0240    * Popup used for right click actions on the PRs node.
0241    */
0242   protected JPopupMenu prsPopup;
0243 
0244   protected JCheckBoxMenuItem verboseModeItem;
0245 
0246   protected JTree resourcesTree;
0247 
0248   protected JScrollPane resourcesTreeScroll;
0249 
0250   protected DefaultTreeModel resourcesTreeModel;
0251 
0252   protected DefaultMutableTreeNode resourcesTreeRoot;
0253 
0254   protected DefaultMutableTreeNode applicationsRoot;
0255 
0256   protected DefaultMutableTreeNode languageResourcesRoot;
0257 
0258   protected DefaultMutableTreeNode processingResourcesRoot;
0259 
0260   protected DefaultMutableTreeNode datastoresRoot;
0261 
0262   protected Splash splash;
0263 
0264   //protected PluginManagerUI pluginManager;
0265   protected PluginUpdateManager pluginManager;
0266 
0267   protected LogArea logArea;
0268 
0269   protected JToolBar toolbar;
0270 
0271   protected static XJFileChooser fileChooser;
0272 
0273   private static MainFrame instance;
0274 
0275   protected OptionsDialog optionsDialog;
0276 
0277   protected CartoonMinder animator;
0278 
0279   protected TabHighlighter logHighlighter;
0280 
0281   protected NewResourceDialog newResourceDialog;
0282 
0283   protected HelpFrame helpFrame;
0284 
0285   /**
0286    * Holds all the icons used in the Gate GUI indexed by filename. This
0287    * is needed so we do not need to decode the icon everytime we need it
0288    * as that would use unnecessary CPU time and memory. Access to this
0289    * data is available through the {@link #getIcon(String)} method.
0290    */
0291   private static final Map<String, Icon> iconByName = new HashMap<String, Icon>();
0292 
0293   private static final Collection<Component> guiRoots =
0294     new ArrayList<Component>();
0295 
0296   /**
0297    * Extensions for icon files to be tried in this order.
0298    */
0299   protected static final String[] ICON_EXTENSIONS = {""".png"".gif"};
0300 
0301   private static JDialog guiLock = null;
0302 
0303   static public Icon getIcon(String baseName) {
0304     //is the icon in the cache?
0305     Icon result = iconByName.get(baseName);
0306     if (result != nullreturn result;
0307     
0308     for(int i = 0; i < ICON_EXTENSIONS.length ; i++) {
0309       String extension = ICON_EXTENSIONS[i];
0310       String fileName = baseName + extension;
0311       URL iconURL;
0312       // if the ICON is an absolute path starting with '/', then just
0313       // load
0314       // it from that path. If it does not start with '/', treat it as
0315       // relative to gate/resources/img for backwards compatibility
0316       if(fileName.charAt(0== '/') {
0317         iconURL = Files.getResource(fileName);
0318       }
0319       else {
0320         iconURL = Files.getGateResource("/img/" + fileName);
0321       }
0322       if(iconURL != null) {
0323         result = new ImageIcon(iconURL);
0324         iconByName.put(baseName, result);
0325         return result;
0326       }
0327     }
0328     
0329     // let's see if this is a new SVG based Icon which is actually a class and
0330     // not an image, so we just try and load it via reflection
0331     try {
0332       @SuppressWarnings("unchecked")
0333       Class<Icon> clazz =
0334           (Class<Icon>)Class.forName("gate.resources.img.svg." + baseName + "Icon",true,Gate.getClassLoader());
0335       Constructor<Icon> con = clazz.getConstructor(int.class,int.class);
0336       result = con.newInstance(24,24);
0337       iconByName.put(baseName, result);
0338       return result;
0339     catch(Exception e) {
0340       //do nothing
0341     }   
0342     
0343     //if we got to here then we haven't found anything
0344     return null;
0345   }
0346 
0347   static public MainFrame getInstance() {
0348     return getInstance(null);
0349   }
0350   
0351   static synchronized public MainFrame getInstance(GraphicsConfiguration gc) {
0352     if(instance == nullinstance = new MainFrame(gc);
0353     return instance;
0354   }  
0355 
0356   /**
0357    * Get the file chooser.
0358    @return the current file chooser
0359    */
0360   static public XJFileChooser getFileChooser() {
0361     return fileChooser;
0362   }
0363 
0364   /**
0365    * Gets the original system output stream, which was later redirected
0366    * to the messages pane.
0367    *
0368    @return {@link PrintStream} value.
0369    */
0370   public PrintStream getOriginalOut() {
0371     return logArea.getOriginalOut();
0372   }
0373 
0374   /**
0375    * Gets the original system error output stream, which was later
0376    * redirected to the messages pane.
0377    *
0378    @return {@link PrintStream} value.
0379    */
0380   public PrintStream getOriginalErr() {
0381     return logArea.getOriginalErr();
0382   }
0383 
0384   /**
0385    * Locates the handle for a given resource.
0386    @param res the resource for which the handle is sought.
0387    @return the {@link Handle} for the resource, if it it was found.
0388    */
0389   protected Handle findHandleForResource(Resource res){
0390     Handle handle = null;
0391     // go through all the nodes
0392     Enumeration<?> nodesEnum = resourcesTreeRoot.breadthFirstEnumeration();
0393     while(nodesEnum.hasMoreElements() && handle == null) {
0394       Object node = nodesEnum.nextElement();
0395       if(node instanceof DefaultMutableTreeNode) {
0396         DefaultMutableTreeNode dmtNode = (DefaultMutableTreeNode)node;
0397         if(dmtNode.getUserObject() instanceof Handle) {
0398           if(((Handle)dmtNode.getUserObject()).getTarget() == res) {
0399             handle = (Handle)dmtNode.getUserObject();
0400           }
0401         }
0402       }
0403     }
0404     return handle;
0405   }
0406 
0407   /**
0408    * Selects a resource if loaded in the system and not invisible.
0409    *
0410    @param res the resource to be selected.
0411    @return the {@link Handle} for the resource, null if not found.
0412    */
0413   public Handle select(Resource res) {
0414     // first find the handle for the resource
0415     Handle handle = findHandleForResource(res);
0416     // now select the handle if found
0417     if(handle != null) {
0418       select(handle);
0419     }
0420     return handle;
0421   }
0422 
0423   protected void select(Handle handle) {
0424     final JComponent largeView = handle.getLargeView();
0425     if(handle.viewsBuilt()
0426       && mainTabbedPane.indexOfComponent(handle.getLargeView()) != -1) {
0427       // select
0428       if(largeView != null) {
0429         mainTabbedPane.setSelectedComponent(largeView);
0430       }
0431     }
0432     else {
0433       // show
0434       if(largeView != null) {
0435         mainTabbedPane.addTab(handle.getTitle(), handle.getIcon(), largeView,
0436           handle.getTooltipText());
0437         mainTabbedPane.setSelectedComponent(handle.getLargeView());
0438         // put the focus on the new tab
0439         SwingUtilities.invokeLater(new Runnable() {
0440           @Override
0441           public void run() {
0442             if (largeView != null) {
0443               if ((largeView instanceof JTabbedPane)
0444               && (((JTabbedPane)largeView).getSelectedComponent() != null)) {
0445                 ((JTabbedPane)largeView).getSelectedComponent().requestFocus();
0446               else {
0447                 largeView.requestFocus();
0448               }
0449             }
0450           }
0451         });
0452       }
0453     }
0454     // show the small view
0455     JComponent smallView = handle.getSmallView();
0456     if(smallView != null) {
0457       lowerScroll.getViewport().setView(smallView);
0458     }
0459     else {
0460       lowerScroll.getViewport().setView(null);
0461     }
0462   }// protected void select(ResourceHandle handle)
0463 
0464   /**
0465    * Construct the frame.
0466    @param gc graphics configuration used,
0467    *   see {@link javax.swing.JFrame#JFrame(java.awt.GraphicsConfiguration)}
0468    */
0469   private MainFrame(GraphicsConfiguration gc) {
0470     super(gc);
0471         
0472     // I thought this should only be needed if the method was called
0473     // from outside the getInstance() method, but if we don't do this
0474     // then the GUI never appears. We probably should figure out why.
0475     instance = this;
0476     
0477     // set the WM class
0478     try {
0479       Toolkit xToolkit = Toolkit.getDefaultToolkit();
0480       java.lang.reflect.Field awtAppClassNameField =
0481       xToolkit.getClass().getDeclaredField("awtAppClassName");
0482       awtAppClassNameField.setAccessible(true);
0483       awtAppClassNameField.set(xToolkit, "GATE Developer " + Main.version);
0484     catch(Exception e) {
0485       // this happens every time on Windows and Mac so hide the exception
0486       // unless we are debugging something
0487       log.debug("Could not set WM Class (note that this is normal if you " +
0488           "are not on an X11-based window system)", e);
0489     }
0490     
0491     guiRoots.add(this);
0492     if(fileChooser == null) {
0493       fileChooser = new XJFileChooser();
0494       fileChooser.setMultiSelectionEnabled(false);
0495       fileChooser.setAcceptAllFileFilterUsed(true);
0496       guiRoots.add(fileChooser);
0497 
0498       // the JFileChooser seems to size itself better once it's been
0499       // added to a top level container such as a dialog.
0500       JDialog dialog = new JDialog(this, ""true);
0501       java.awt.Container contentPane = dialog.getContentPane();
0502       contentPane.setLayout(new BorderLayout());
0503       contentPane.add(fileChooser, BorderLayout.CENTER);
0504       dialog.pack();
0505       dialog.getContentPane().removeAll();
0506       dialog.dispose();
0507       dialog = null;
0508     }
0509     enableEvents(AWTEvent.WINDOW_EVENT_MASK);
0510     initLocalData();
0511     initGuiComponents();
0512     initListeners();
0513   // MainFrame(boolean simple)
0514 
0515   protected void initLocalData() {
0516     resourcesTreeRoot = new DefaultMutableTreeNode("GATE"true);
0517     applicationsRoot = new DefaultMutableTreeNode("Applications"true);
0518 
0519     languageResourcesRoot =
0520         new DefaultMutableTreeNode("Language Resources"true);
0521 
0522     processingResourcesRoot =
0523         new DefaultMutableTreeNode("Processing Resources"true);
0524     datastoresRoot = new DefaultMutableTreeNode("Datastores"true);
0525     resourcesTreeRoot.add(applicationsRoot);
0526     resourcesTreeRoot.add(languageResourcesRoot);
0527     resourcesTreeRoot.add(processingResourcesRoot);
0528     resourcesTreeRoot.add(datastoresRoot);
0529 
0530     resourcesTreeModel = new ResourcesTreeModel(resourcesTreeRoot, true);
0531   }
0532 
0533   protected void initGuiComponents() {
0534     this.getContentPane().setLayout(new BorderLayout());
0535 
0536     Integer width =
0537         Gate.getUserConfig().getInt(GateConstants.MAIN_FRAME_WIDTH, 1024);
0538     Integer height =
0539         Gate.getUserConfig().getInt(GateConstants.MAIN_FRAME_HEIGHT, 768);
0540     Rectangle maxDimensions =
0541         GraphicsEnvironment.getLocalGraphicsEnvironment()
0542             .getMaximumWindowBounds();
0543     this.setSize(new Dimension(Math.min(width, maxDimensions.width), Math.min(
0544         height, maxDimensions.height)));
0545     if (Gate.getUserConfig().getBoolean(GateConstants.MAIN_FRAME_MAXIMIZED))
0546       setExtendedState(JFrame.MAXIMIZED_BOTH);
0547     
0548     setIconImages(Arrays.asList(new Image[]{new GATEVersionIcon(6464).getImage(),
0549         new GATEVersionIcon(4848).getImage()new GATEVersionIcon(3232).getImage(),
0550         new GATEIcon(2222).getImage()new GATEIcon(1616).getImage()}));
0551     
0552     resourcesTree = new ResourcesTree();
0553     resourcesTree.setModel(resourcesTreeModel);
0554     resourcesTree.setRowHeight(0);
0555 
0556     resourcesTree.setEditable(true);
0557     ResourcesTreeCellRenderer treeCellRenderer =
0558       new ResourcesTreeCellRenderer();
0559     resourcesTree.setCellRenderer(treeCellRenderer);
0560     resourcesTree.setCellEditor(new ResourcesTreeCellEditor(resourcesTree,
0561       treeCellRenderer));
0562     resourcesTree.setInvokesStopCellEditing(true);
0563     resourcesTree.setRowHeight(0);
0564     // expand all nodes
0565     resourcesTree.expandRow(0);
0566     resourcesTree.expandRow(1);
0567     resourcesTree.expandRow(2);
0568     resourcesTree.expandRow(3);
0569     resourcesTree.expandRow(4);
0570     resourcesTree.getSelectionModel().setSelectionMode(
0571       TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
0572     resourcesTree.setEnabled(true);
0573     ToolTipManager.sharedInstance().registerComponent(resourcesTree);
0574     resourcesTreeScroll = new JScrollPane(resourcesTree);
0575 
0576     resourcesTree.setDragEnabled(true);
0577     resourcesTree.setTransferHandler(new TransferHandler() {
0578       // drag and drop that export a list of the selected documents
0579       @Override
0580       public int getSourceActions(JComponent c) {
0581         return COPY;
0582       }
0583       @Override
0584       protected Transferable createTransferable(JComponent c) {
0585         TreePath[] paths = resourcesTree.getSelectionPaths();
0586         if(paths == null) { return new StringSelection("")}
0587         Handle handle;
0588         List<String> documentsNames = new ArrayList<String>();
0589         for(TreePath path : paths) {
0590           if(path != null) {
0591             Object value = path.getLastPathComponent();
0592             value = ((DefaultMutableTreeNode)value).getUserObject();
0593             if(value instanceof Handle) {
0594               handle = (Handle)value;
0595               if(handle.getTarget() instanceof Document) {
0596                 documentsNames.add(((Document)handle.getTarget()).getName());
0597               }
0598             }
0599           }
0600         }
0601         return new StringSelection("ResourcesTree"
0602           + Arrays.toString(documentsNames.toArray()));
0603       }
0604       @Override
0605       protected void exportDone(JComponent c, Transferable data, int action) {
0606       }
0607       @Override
0608       public boolean canImport(JComponent c, DataFlavor[] flavors) {
0609         return false;
0610       }
0611       @Override
0612       public boolean importData(JComponent c, Transferable t) {
0613         return false;
0614       }
0615     });
0616 
0617     lowerScroll = new JScrollPane();
0618     JPanel lowerPane = new JPanel();
0619     lowerPane.setLayout(new OverlayLayout(lowerPane));
0620 
0621     JPanel animationPane = new JPanel();
0622     animationPane.setOpaque(false);
0623     animationPane.setLayout(new BoxLayout(animationPane, BoxLayout.X_AXIS));
0624 
0625     JPanel vBox = new JPanel();
0626     vBox.setLayout(new BoxLayout(vBox, BoxLayout.Y_AXIS));
0627     vBox.setOpaque(false);
0628 
0629     JPanel hBox = new JPanel();
0630     hBox.setLayout(new BoxLayout(hBox, BoxLayout.X_AXIS));
0631     hBox.setOpaque(false);
0632 
0633     vBox.add(Box.createVerticalGlue());
0634     vBox.add(animationPane);
0635 
0636     hBox.add(vBox);
0637     hBox.add(Box.createHorizontalGlue());
0638 
0639     lowerPane.add(hBox);
0640     lowerPane.add(lowerScroll);
0641 
0642     animator = new CartoonMinder(animationPane);
0643     Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
0644       animator, "MainFrame animation");
0645     thread.setDaemon(true);
0646     thread.setPriority(Thread.MIN_PRIORITY);
0647     thread.start();
0648 
0649     leftSplit =
0650       new JSplitPane(JSplitPane.VERTICAL_SPLIT, resourcesTreeScroll, lowerPane);
0651     leftSplit.setResizeWeight(0.7);
0652     leftSplit.setContinuousLayout(true);
0653     leftSplit.setOneTouchExpandable(true);
0654 
0655     // Create a new logArea and redirect the Out and Err output to it.
0656     logArea = new LogArea();
0657     
0658     // Out has been redirected to the logArea
0659 
0660     Out.prln("GATE " + Main.version + " build " + Main.build + " started at "
0661       new Date().toString());
0662     Out.prln("and using Java " + System.getProperty("java.version"" " +
0663       System.getProperty("java.vendor"" on " +
0664       System.getProperty("os.name"" " +
0665       System.getProperty("os.arch"" " +
0666       System.getProperty("os.version"".");
0667     mainTabbedPane = new XJTabbedPane(JTabbedPane.TOP);
0668     mainTabbedPane.insertTab("Messages", null, logArea.getComponentToDisplay()"GATE log"0);
0669 
0670     logHighlighter = new TabHighlighter(mainTabbedPane, logArea.getComponentToDisplay(), Color.red);
0671 
0672     mainSplit =
0673       new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftSplit, mainTabbedPane);
0674     mainSplit.setDividerLocation(leftSplit.getPreferredSize().width + 10);
0675     this.getContentPane().add(mainSplit, BorderLayout.CENTER);
0676     mainSplit.setContinuousLayout(true);
0677     mainSplit.setOneTouchExpandable(true);
0678 
0679     // status and progress bars
0680     statusBar = new JLabel("Welcome to GATE!");
0681     statusBar.setBorder(BorderFactory.createEmptyBorder(0500));
0682 
0683     UIManager.put("ProgressBar.cellSpacing"0);
0684     progressBar = new JProgressBar(JProgressBar.HORIZONTAL);
0685     progressBar.setBorder(BorderFactory.createEmptyBorder());
0686     progressBar.setForeground(new Color(15075150));
0687     progressBar.setStringPainted(false);
0688 
0689     globalProgressBar = new JProgressBar(JProgressBar.HORIZONTAL);
0690     globalProgressBar.setBorder(BorderFactory.createEmptyBorder());
0691     globalProgressBar.setForeground(new Color(15075150));
0692     globalProgressBar.setStringPainted(true);
0693 
0694     JPanel southBox = new JPanel(new GridBagLayout());
0695     GridBagConstraints gbc = new GridBagConstraints();
0696     gbc.fill = GridBagConstraints.BOTH;
0697     gbc.anchor = GridBagConstraints.WEST;
0698     gbc.weightx = 1;
0699     southBox.add(statusBar, gbc);
0700     gbc.insets = new Insets(0303);
0701     gbc.anchor = GridBagConstraints.EAST;
0702     gbc.weightx = 0;
0703     southBox.add(progressBar, gbc);
0704     southBox.add(globalProgressBar, gbc);
0705 
0706     this.getContentPane().add(southBox, BorderLayout.SOUTH);
0707     progressBar.setVisible(false);
0708     globalProgressBar.setVisible(false);
0709 
0710     // extra stuff
0711     newResourceDialog =
0712       new NewResourceDialog(this, "Resource parameters"true);
0713 
0714     // build the Help->About dialog
0715     JPanel splashBox = new JPanel();
0716     splashBox.setBackground(Color.WHITE);
0717 
0718     splashBox.setLayout(new GridBagLayout());
0719     GridBagConstraints constraints = new GridBagConstraints();
0720     constraints.weightx = 1;
0721     constraints.insets = new Insets(2222);
0722     constraints.gridy = 0;
0723     constraints.fill = GridBagConstraints.BOTH;
0724 
0725     JLabel gifLbl = new JLabel(getIcon("splash"));
0726     splashBox.add(gifLbl, constraints);
0727 
0728     constraints.gridy = 2;
0729     constraints.gridwidth = 2;
0730     constraints.fill = GridBagConstraints.HORIZONTAL;
0731     String splashHtml;
0732     try {
0733       splashHtml = Files.getGateResourceAsString("splash.html");
0734     }
0735     catch(IOException e) {
0736       splashHtml = "GATE";
0737       log.error("Couldn't get splash.html resource.", e);
0738     }
0739     JLabel htmlLbl = new JLabel(splashHtml);
0740     htmlLbl.setHorizontalAlignment(SwingConstants.CENTER);
0741     splashBox.add(htmlLbl, constraints);
0742 
0743     constraints.gridy = 3;
0744     htmlLbl =
0745       new JLabel("<HTML><FONT color=\"blue\">Version <B>" + Main.version
0746         "</B></FONT>" ", <FONT color=\"red\">build <B>" + Main.build
0747         "</B></FONT>" "<P><B>JVM version</B>: "
0748         + System.getProperty("java.version"" from "
0749         + System.getProperty("java.vendor""</HTML>");
0750     constraints.fill = GridBagConstraints.HORIZONTAL;
0751     splashBox.add(htmlLbl, constraints);
0752 
0753     constraints.gridy = 4;
0754     constraints.gridwidth = 2;
0755     constraints.fill = GridBagConstraints.NONE;
0756     final JButton okButton = new JButton("OK");
0757     okButton.addActionListener(new ActionListener() {
0758       @Override
0759       public void actionPerformed(ActionEvent e) {
0760         splash.setVisible(false);
0761       }
0762     });
0763     okButton.setBackground(Color.white);
0764     splashBox.add(okButton, constraints);
0765     splash = new Splash(this, splashBox);
0766     // make Enter and Escape keys closing the splash window
0767     splash.getRootPane().setDefaultButton(okButton);
0768     InputMap inputMap = ((JComponent)splash.getContentPane())
0769       .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
0770     ActionMap actionMap = ((JComponent)splash.getContentPane()).getActionMap();
0771     inputMap.put(KeyStroke.getKeyStroke("ENTER")"Apply");
0772     actionMap.put("Apply"new AbstractAction() {
0773       @Override
0774       public void actionPerformed(ActionEvent e) {
0775         okButton.doClick();
0776       }
0777     });
0778     inputMap.put(KeyStroke.getKeyStroke("ESCAPE")"Cancel");
0779     actionMap.put("Cancel"new AbstractAction() {
0780       @Override
0781       public void actionPerformed(ActionEvent e) {
0782         okButton.doClick();
0783       }
0784     });
0785 
0786     // MENUS
0787     menuBar = new JMenuBar();
0788 
0789     JMenu fileMenu = new XJMenu("File", null, this);
0790     fileMenu.setMnemonic(KeyEvent.VK_F);
0791 
0792     LiveMenu newAPPMenu = new LiveMenu(LiveMenu.APP);
0793     newAPPMenu.setText("New Application");
0794     newAPPMenu.setIcon(getIcon("applications"));
0795     fileMenu.add(newAPPMenu);
0796 
0797     LiveMenu newLRMenu = new LiveMenu(LiveMenu.LR);
0798     newLRMenu.setText("New Language Resource");
0799     newLRMenu.setIcon(getIcon("lrs"));
0800     fileMenu.add(newLRMenu);
0801 
0802     LiveMenu newPRMenu = new LiveMenu(LiveMenu.PR);
0803     newPRMenu.setText("New Processing Resource");
0804     newPRMenu.setIcon(getIcon("prs"));
0805     fileMenu.add(newPRMenu);
0806 
0807     final JMenu dsMenu = new XJMenu("Datastores",
0808       "Repositories for large data"this);
0809     dsMenu.setIcon(getIcon("datastores"));
0810     dsMenu.add(new XJMenuItem(new NewDSAction()this));
0811     dsMenu.add(new XJMenuItem(new OpenDSAction()this));
0812     fileMenu.add(dsMenu);
0813 
0814     fileMenu.addSeparator();
0815     fileMenu.add(new ReadyMadeMenu());
0816     fileMenu.add(new XJMenuItem(new LoadResourceFromFileAction()this));
0817 
0818     RecentAppsMenu recentAppsMenu = new RecentAppsMenu();
0819     fileMenu.add(recentAppsMenu);
0820 
0821     /*final JMenu loadANNIEMenu = new XJMenu("Load ANNIE System",
0822       "Application that adds morphosyntaxic and semantic annotations", this);
0823     loadANNIEMenu.setIcon(getIcon("annie-application"));
0824     loadANNIEMenu.add(new XJMenuItem(new LoadANNIEWithDefaultsAction(), this));
0825     loadANNIEMenu
0826       .add(new XJMenuItem(new LoadANNIEWithoutDefaultsAction(), this));
0827     fileMenu.add(loadANNIEMenu);
0828 
0829     // LingPipe action
0830     fileMenu.add(new XJMenuItem(new LoadApplicationAction(
0831             "Load LingPipe System", "LingPipe", "resources/lingpipe.gapp"),
0832             this));
0833 
0834     // OpenNLP action
0835     fileMenu.add(new XJMenuItem(new LoadApplicationAction(
0836             "Load OpenNLP System", "OpenNLP", "resources/opennlp.gapp"), this));
0837 */
0838     fileMenu.add(new XJMenuItem(new ManagePluginsAction()this));
0839 
0840     if(!Gate.runningOnMac()) {
0841       fileMenu.addSeparator();
0842       fileMenu.add(new XJMenuItem(new ExitGateAction()this));
0843     }
0844 
0845     menuBar.add(fileMenu);
0846 
0847     JMenu optionsMenu = new XJMenu("Options", null, this);
0848     optionsMenu.setMnemonic(KeyEvent.VK_O);
0849 
0850     boolean optionsMenuHasEntries = false;
0851 
0852     optionsDialog = new OptionsDialog(MainFrame.this);
0853     if(!Gate.runningOnMac()) {
0854       optionsMenu.add(new XJMenuItem(new AbstractAction("Configuration") {
0855         private static final long serialVersionUID = 1L;
0856         {
0857           putValue(SHORT_DESCRIPTION, "Edit GATE options");
0858         }
0859 
0860         @Override
0861         public void actionPerformed(ActionEvent evt) {
0862           optionsDialog.showDialog();
0863           optionsDialog.dispose();
0864         }
0865       }this));
0866       optionsMenuHasEntries = true;
0867     }
0868 
0869     if(optionsMenuHasEntries) {
0870       menuBar.add(optionsMenu);
0871     }
0872 
0873     ToolsMenu toolsMenu = new ToolsMenu("Tools", null, this);
0874     toolsMenu.setMnemonic(KeyEvent.VK_T);
0875     toolsMenu.add(new XJMenuItem(new NewAnnotDiffAction()this));
0876 
0877     try {
0878       // Check if log4j is present on the classpath, in order to avoid failures
0879       // in cases when running the GATE GUI in the same JVM with a system which
0880       // uses SLF4J and the log4j bridge.
0881       // The log4j-over-slf4j bridge does not include org.apache.log4j.Appender, so
0882       // if the class is not present we assume the lack of a log4j jar in the classpath
0883       // and do not populate the menu.
0884       Class.forName("org.apache.log4j.Appender")
0885   
0886     
0887       final JMenuItem reportClearMenuItem = new XJMenuItem(
0888         new AbstractAction("Clear Profiling History") {
0889         putValue(SHORT_DESCRIPTION,
0890           "Clear profiling history otherwise the report is cumulative.")}
0891         @Override
0892         public void actionPerformed(ActionEvent evt) {
0893           // create a new log file
0894           File logFile = new File(System.getProperty("java.io.tmpdir"),
0895             "gate-benchmark-log.txt");
0896           logFile.deleteOnExit();
0897           if (logFile.exists() && !logFile.delete()) {
0898             log.info("Error when deleting the file:\n" +
0899               logFile.getAbsolutePath());
0900           }
0901         }
0902       }this);
0903       JMenu reportMenu = new XJMenu("Profiling Reports",
0904         "Generates profiling reports from processing resources"this);
0905       reportMenu.setIcon(getIcon("gazetteer"));
0906       reportMenu.add(new XJMenuItem(
0907         new AbstractAction("Start Profiling Applications") {
0908         putValue(SHORT_DESCRIPTION,
0909           "Toggles the profiling of processing resources")}
0910   
0911         // stores the value held by the benchmarking switch before we started
0912         // this profiling run.
0913         boolean benchmarkWasEnabled;
0914   
0915         @Override
0916         public void actionPerformed(ActionEvent evt) {
0917           if (getValue(NAME).equals("Start Profiling Applications")) {
0918             reportClearMenuItem.setEnabled(false);
0919             // store old value of benchmark switch
0920             benchmarkWasEnabled = Benchmark.isBenchmarkingEnabled();
0921             Benchmark.setBenchmarkingEnabled(true);
0922             Layout layout = new PatternLayout("%m%n");
0923             File logFile = new File(System.getProperty("java.io.tmpdir"),
0924               "gate-benchmark-log.txt");
0925             logFile.deleteOnExit();
0926             Appender appender;
0927             try {
0928               appender =
0929                 new FileAppender(layout, logFile.getAbsolutePath()true);
0930             catch (IOException e) {
0931               e.printStackTrace();
0932               return;
0933             }
0934             appender.setName("gate-benchmark");
0935             Benchmark.logger.addAppender(appender);
0936             putValue(NAME, "Stop Profiling Applications");
0937           else {
0938             // reset old value of benchmark switch - i.e. if benchmarking was
0939             // disabled before the user selected "start profiling" then we
0940             // disable it again now, but if it was already enabled before they
0941             // started profiling then we assume it was turned on explicitly and
0942             // leave it alone.
0943             Benchmark.setBenchmarkingEnabled(benchmarkWasEnabled);
0944             Benchmark.logger.removeAppender("gate-benchmark");
0945             putValue(NAME, "Start Profiling Applications");
0946             reportClearMenuItem.setEnabled(true);
0947           }
0948         }
0949       }this));
0950       reportMenu.add(reportClearMenuItem);
0951       reportMenu.add(new XJMenuItem(new AbstractAction("Help on this tool") {
0952         @Override
0953         public void actionPerformed(ActionEvent e) {
0954           showHelpFrame("chap:profiling""Profiling Processing Resources");
0955         }
0956       }this));
0957       reportMenu.addSeparator();
0958   
0959       final JCheckBoxMenuItem reportZeroTimesCheckBox = new JCheckBoxMenuItem();
0960       reportZeroTimesCheckBox.setAction(
0961         new AbstractAction("Report Zero Time Entries") {
0962         @Override
0963         public void actionPerformed(ActionEvent evt) {
0964           Gate.getUserConfig().put(MainFrame.class.getName()+".reportzerotime",
0965             reportZeroTimesCheckBox.isSelected());
0966         }
0967       });
0968       reportZeroTimesCheckBox.setSelected(Gate.getUserConfig().getBoolean(
0969           MainFrame.class.getName()+".reportzerotimes"));
0970       ButtonGroup group = new ButtonGroup();
0971       final JRadioButtonMenuItem reportSortExecution = new JRadioButtonMenuItem();
0972       reportSortExecution.setAction(new AbstractAction("Sort by Execution") {
0973         @Override
0974         public void actionPerformed(ActionEvent evt) {
0975           Gate.getUserConfig().put(
0976             MainFrame.class.getName()+".reportsorttime"false);
0977         }
0978       });
0979       reportSortExecution.setSelected(!Gate.getUserConfig().getBoolean(
0980         MainFrame.class.getName()+".reportsorttime"));
0981       group.add(reportSortExecution);
0982       final JRadioButtonMenuItem reportSortTime = new JRadioButtonMenuItem();
0983       reportSortTime.setAction(new AbstractAction("Sort by Time") {
0984         @Override
0985         public void actionPerformed(ActionEvent evt) {
0986           Gate.getUserConfig().put(
0987             MainFrame.class.getName()+".reportsorttime"true);
0988         }
0989       });
0990       reportSortTime.setSelected(Gate.getUserConfig().getBoolean(
0991         MainFrame.class.getName()+".reportsorttime"));
0992       group.add(reportSortTime);
0993       reportMenu.add(new XJMenuItem(
0994         new AbstractAction("Report on Processing Resources") {
0995         putValue(SHORT_DESCRIPTION,
0996           "Report time taken by each processing resource")}
0997         @Override
0998         public void actionPerformed(ActionEvent evt) {
0999           PRTimeReporter report = new PRTimeReporter();
1000           report.setBenchmarkFile(new File(System.getProperty("java.io.tmpdir"),
1001             "gate-benchmark-log.txt"));
1002           report.setSuppressZeroTimeEntries(!reportZeroTimesCheckBox.isSelected());
1003           report.setSortOrder(reportSortTime.isSelected() ?
1004             PRTimeReporter.SORT_TIME_TAKEN : PRTimeReporter.SORT_EXEC_ORDER);
1005           try {
1006             report.executeReport();
1007           catch (BenchmarkReportException e) {
1008             e.printStackTrace();
1009             return;
1010           }
1011           showHelpFrame("file://" + report.getReportFile(),
1012             "processing times report");
1013         }
1014       }this));
1015       reportMenu.add(reportZeroTimesCheckBox);
1016       reportMenu.add(reportSortTime);
1017       reportMenu.add(reportSortExecution);
1018       reportMenu.addSeparator();
1019   
1020       reportMenu.add(new XJMenuItem(
1021         new AbstractAction("Report on Documents Processed") {
1022           putValue(SHORT_DESCRIPTION, "Report most time consuming documents")}
1023           @Override
1024           public void actionPerformed(ActionEvent evt) {
1025             DocTimeReporter report = new DocTimeReporter();
1026             report.setBenchmarkFile(new File(System.getProperty("java.io.tmpdir"),
1027               "gate-benchmark-log.txt"));
1028             String maxDocs = Gate.getUserConfig().getString(
1029               MainFrame.class.getName()+".reportmaxdocs");
1030             if (maxDocs != null) {
1031               report.setMaxDocumentInReport((maxDocs.equals("All")) ?
1032                 DocTimeReporter.ALL_DOCS : Integer.valueOf(maxDocs));
1033             }
1034             String prRegex = Gate.getUserConfig().getString(
1035               MainFrame.class.getName()+".reportprregex");
1036             if (prRegex != null) {
1037               report.setPRMatchingRegex((prRegex.equals("")) ?
1038                 DocTimeReporter.MATCH_ALL_PR_REGEX : prRegex);
1039             }
1040             try {
1041               report.executeReport();
1042             catch (BenchmarkReportException e) {
1043               e.printStackTrace();
1044               return;
1045             }
1046             showHelpFrame("file://" + report.getReportFile(),
1047               "documents time report");
1048           }
1049         }this));
1050       String maxDocs = Gate.getUserConfig().getString(
1051         MainFrame.class.getName()+".reportmaxdocs");
1052       if (maxDocs == null) { maxDocs = "10"}
1053       reportMenu.add(new XJMenuItem(
1054         new AbstractAction("Set Max Documents (" + maxDocs + ")") {
1055           @Override
1056           public void actionPerformed(ActionEvent evt) {
1057             Object response = JOptionPane.showInputDialog(instance,
1058                 "Set the maximum of documents to report""Report options",
1059                 JOptionPane.QUESTION_MESSAGE, null,
1060                 new Object[]{"All""10""20""30""40""50""100"}"10");
1061             if (response != null) {
1062               Gate.getUserConfig().put(
1063                 MainFrame.class.getName()+".reportmaxdocs",response);
1064               putValue(NAME, "Set Max Documents (" + response + ")");
1065             }
1066           }
1067         }this));
1068       String prRegex = Gate.getUserConfig().getString(
1069         MainFrame.class.getName()+".reportprregex");
1070       if (prRegex == null || prRegex.equals("")) { prRegex = "All"}
1071       reportMenu.add(new XJMenuItem(
1072         new AbstractAction("Set PR Matching Regex (" + prRegex + ")") {
1073           @Override
1074           public void actionPerformed(ActionEvent evt) {
1075             Object response = JOptionPane.showInputDialog(instance,
1076               "Set the processing resource regex filter\n" +
1077               "Leave empty to not filter""Report options",
1078                 JOptionPane.QUESTION_MESSAGE);
1079             if (response != null) {
1080               Gate.getUserConfig().put(
1081                 MainFrame.class.getName()+".reportprregex",response);
1082               if (response.equals("")) { response = "All"}
1083               putValue(NAME, "Set PR Matching Regex (" + response + ")");
1084             }
1085           }
1086         }this));
1087       toolsMenu.add(reportMenu);
1088     catch (ClassNotFoundException e) {
1089       log.warn("log4j.jar not found on the classpath, disabling profiling reports.");
1090     }
1091 
1092     toolsMenu.add(new XJMenuItem(new NewBootStrapAction()this));
1093     final JMenu corpusEvalMenu = new XJMenu("Corpus Benchmark",
1094       "Compares processed and human-annotated annotations"this);
1095     corpusEvalMenu.setIcon(getIcon("corpus-benchmark"));
1096     toolsMenu.add(corpusEvalMenu);
1097     corpusEvalMenu.add(new XJMenuItem(new NewCorpusEvalAction()this));
1098     corpusEvalMenu.addSeparator();
1099     corpusEvalMenu.add(new XJMenuItem(
1100       new GenerateStoredCorpusEvalAction()this));
1101     corpusEvalMenu.addSeparator();
1102     corpusEvalMenu.add(new XJMenuItem(
1103       new StoredMarkedCorpusEvalAction()this));
1104     corpusEvalMenu.add(new XJMenuItem(new CleanMarkedCorpusEvalAction()this));
1105     corpusEvalMenu.addSeparator();
1106     verboseModeItem =
1107       new JCheckBoxMenuItem(new VerboseModeCorpusEvalToolAction());
1108     corpusEvalMenu.add(verboseModeItem);
1109 
1110     toolsMenu.staticItemsAdded();    
1111     menuBar.add(toolsMenu);
1112     
1113     JMenu helpMenu = new XJMenu("Help", null, MainFrame.this);
1114     helpMenu.setMnemonic(KeyEvent.VK_H);
1115     helpMenu.add(new XJMenuItem(new HelpUserGuideAction()this));
1116     helpMenu.add(new XJMenuItem(new HelpUserGuideInContextAction()this));
1117     helpMenu.add(new XJMenuItem(new AbstractAction("Keyboard Shortcuts") {
1118       @Override
1119       public void actionPerformed(ActionEvent e) {
1120         showHelpFrame("sec:developer:keyboard""shortcuts");
1121       }
1122     }this));
1123     helpMenu.addSeparator();
1124     helpMenu.add(new XJMenuItem(new AbstractAction("Using GATE Developer") {
1125       this.putValue(Action.SHORT_DESCRIPTION, "To read first")}
1126       @Override
1127       public void actionPerformed(ActionEvent e) {
1128         showHelpFrame("chap:developer""Using GATE Developer");
1129       }
1130     }this));
1131     helpMenu.add(new XJMenuItem(new AbstractAction("Demo Movies") {
1132       this.putValue(Action.SHORT_DESCRIPTION, "Movie tutorials")}
1133       @Override
1134       public void actionPerformed(ActionEvent e) {
1135         showHelpFrame("http://gate.ac.uk/demos/developer-videos/""movies");
1136       }
1137     }this));
1138     helpMenu.add(new XJMenuItem(new HelpMailingListAction()this));
1139     helpMenu.addSeparator();
1140     JCheckBoxMenuItem toggleToolTipsCheckBoxMenuItem =
1141       new JCheckBoxMenuItem(new ToggleToolTipsAction());
1142     javax.swing.ToolTipManager toolTipManager =
1143       ToolTipManager.sharedInstance();
1144     if (Gate.getUserConfig().getBoolean(
1145         MainFrame.class.getName()+".hidetooltips")) {
1146       toolTipManager.setEnabled(false);
1147       toggleToolTipsCheckBoxMenuItem.setSelected(false);
1148     else {
1149       toolTipManager.setEnabled(true);
1150       toggleToolTipsCheckBoxMenuItem.setSelected(true);
1151     }
1152     helpMenu.add(toggleToolTipsCheckBoxMenuItem);
1153     helpMenu.add(new XJMenuItem(new AbstractAction("What's New") {
1154       this.putValue(Action.SHORT_DESCRIPTION,
1155           "List new features and important changes")}
1156       @Override
1157       public void actionPerformed(ActionEvent e) {
1158         showHelpFrame("chap:changes""changes");
1159       }
1160     }this));
1161     if(!Gate.runningOnMac()) {
1162       helpMenu.add(new XJMenuItem(new HelpAboutAction()this));
1163     }
1164     menuBar.add(helpMenu);
1165 
1166     this.setJMenuBar(menuBar);
1167 
1168     // popups
1169     lrsPopup = new XJPopupMenu();
1170     LiveMenu lrsMenu = new LiveMenu(LiveMenu.LR);
1171     lrsMenu.setText("New");
1172     lrsPopup.add(lrsMenu);
1173     guiRoots.add(lrsPopup);
1174     guiRoots.add(lrsMenu);
1175 
1176     prsPopup = new XJPopupMenu();
1177     LiveMenu prsMenu = new LiveMenu(LiveMenu.PR);
1178     prsMenu.setText("New");
1179     prsPopup.add(prsMenu);
1180     guiRoots.add(prsPopup);
1181     guiRoots.add(prsMenu);
1182 
1183     dssPopup = new XJPopupMenu();
1184     dssPopup.add(new NewDSAction());
1185     dssPopup.add(new OpenDSAction());
1186     guiRoots.add(dssPopup);
1187 
1188     // TOOLBAR
1189     toolbar = new JToolBar(JToolBar.HORIZONTAL);
1190     toolbar.setFloatable(false);
1191     JButton button = new JButton(new LoadResourceFromFileAction());
1192     button.setToolTipText(button.getText());
1193     button.setText("");
1194     toolbar.add(button);
1195     toolbar.addSeparator();
1196 
1197     JPopupMenu annieMenu = new JPopupMenu();
1198     annieMenu.add(new XJMenuItem(new LoadApplicationAction("with defaults",
1199         "annie-application"new File(new File(Gate.getPluginsHome(),
1200             ANNIEConstants.PLUGIN_DIR), ANNIEConstants.DEFAULT_FILE)),
1201         MainFrame.this));
1202     annieMenu.add(new LoadANNIEWithoutDefaultsAction());
1203     JMenuButton menuButton = new JMenuButton(annieMenu);
1204     menuButton.setIcon(getIcon("annie-application"));
1205     menuButton.setToolTipText("Load ANNIE System");
1206     toolbar.add(menuButton);
1207     toolbar.addSeparator();
1208 
1209     LiveMenu tbNewLRMenu = new LiveMenu(LiveMenu.LR);
1210     menuButton = new JMenuButton(tbNewLRMenu);
1211     menuButton.setToolTipText("New Language Resource");
1212     menuButton.setIcon(getIcon("lrs"));
1213     toolbar.add(menuButton);
1214 
1215     LiveMenu tbNewPRMenu = new LiveMenu(LiveMenu.PR);
1216     menuButton = new JMenuButton(tbNewPRMenu);
1217     menuButton.setToolTipText("New Processing Resource");
1218     menuButton.setIcon(getIcon("prs"));
1219     toolbar.add(menuButton);
1220 
1221     LiveMenu tbNewAppMenu = new LiveMenu(LiveMenu.APP);
1222     menuButton = new JMenuButton(tbNewAppMenu);
1223     menuButton.setToolTipText("New Application");
1224     menuButton.setIcon(getIcon("applications"));
1225     toolbar.add(menuButton);
1226     toolbar.addSeparator();
1227 
1228     JPopupMenu tbDsMenu = new JPopupMenu();
1229     tbDsMenu.add(new NewDSAction());
1230     tbDsMenu.add(new OpenDSAction());
1231     menuButton = new JMenuButton(tbDsMenu);
1232     menuButton.setToolTipText("Datastores");
1233     menuButton.setIcon(getIcon("datastores"));
1234     toolbar.add(menuButton);
1235 
1236     toolbar.addSeparator();
1237     button = new JButton(new ManagePluginsAction());
1238     button.setToolTipText(button.getText());
1239     button.setText("");
1240     toolbar.add(button);
1241     toolbar.addSeparator();
1242     button = new JButton(new NewAnnotDiffAction());
1243     button.setToolTipText(button.getText());
1244     button.setText("");
1245     toolbar.add(button);
1246     toolbar.add(Box.createHorizontalGlue());
1247 
1248     this.getContentPane().add(toolbar, BorderLayout.NORTH);
1249   }
1250 
1251   protected void initListeners() {
1252     Gate.getCreoleRegister().addCreoleListener(this);
1253     Gate.getCreoleRegister().addPluginListener(this);
1254    
1255     resourcesTree.addKeyListener(new KeyAdapter() {
1256       @Override
1257       public void keyPressed(KeyEvent e) {
1258         if(e.getKeyCode() == KeyEvent.VK_ENTER) {
1259           // shows in the central tabbed pane, the selected resources
1260           // in the resource tree when the Enter key is pressed
1261           (new ShowSelectedResourcesAction()).actionPerformed(null);
1262         else if(e.getKeyCode() == KeyEvent.VK_DELETE) {
1263           // close selected resources from GATE
1264           (new CloseSelectedResourcesAction()).actionPerformed(null);
1265         else if(e.getKeyCode() == KeyEvent.VK_DELETE
1266                && e.getModifiers() == InputEvent.SHIFT_DOWN_MASK) {
1267           // close recursively selected resources from GATE
1268           (new CloseRecursivelySelectedResourcesAction()).actionPerformed(null);
1269         }
1270       }
1271     });
1272 
1273     resourcesTree.addMouseListener(new MouseAdapter() {
1274       @Override
1275       public void mousePressed(MouseEvent e) {
1276         TreePath path =
1277           resourcesTree.getClosestPathForLocation(e.getX(), e.getY());
1278         if(e.isPopupTrigger()
1279         && !resourcesTree.isPathSelected(path)) {
1280           // if right click outside the selection then reset selection
1281           resourcesTree.getSelectionModel().setSelectionPath(path);
1282         }
1283         processMouseEvent(e);
1284       }
1285       @Override
1286       public void mouseReleased(MouseEvent e) {
1287           processMouseEvent(e);
1288       }
1289       @Override
1290       public void mouseClicked(MouseEvent e) {
1291         processMouseEvent(e);
1292       }
1293       protected void processMouseEvent(MouseEvent e){
1294         // where inside the tree?
1295         int x = e.getX();
1296         int y = e.getY();
1297         TreePath path = resourcesTree.getClosestPathForLocation(x, y);
1298         JPopupMenu popup = null;
1299         Handle handle = null;
1300         if(path != null) {
1301           Object value = path.getLastPathComponent();
1302           if(value == resourcesTreeRoot) {
1303             // no default item for this menu
1304           }
1305           else if(value == applicationsRoot) {
1306             appsPopup = new XJPopupMenu();
1307             LiveMenu appsMenu = new LiveMenu(LiveMenu.APP);
1308             appsMenu.setText("Create New Application");
1309             appsMenu.setIcon(MainFrame.getIcon("applications"));
1310             appsPopup.add(appsMenu);
1311             appsPopup.add(new ReadyMadeMenu());            
1312             appsPopup.add(new XJMenuItem(new LoadResourceFromFileAction(),
1313               MainFrame.this));
1314             
1315             RecentAppsMenu recentApps = new RecentAppsMenu();
1316             if (recentApps.getMenuComponentCount() 0appsPopup.add(recentApps);
1317             
1318             popup = appsPopup;
1319           }
1320           else if(value == languageResourcesRoot) {
1321             popup = lrsPopup;
1322           }
1323           else if(value == processingResourcesRoot) {
1324             popup = prsPopup;
1325           }
1326           else if(value == datastoresRoot) {
1327             popup = dssPopup;
1328           }
1329           else {
1330             value = ((DefaultMutableTreeNode)value).getUserObject();
1331             if(value instanceof Handle) {
1332               handle = (Handle)value;
1333               fileChooser.setResource(handle.getTarget().getClass().getName());
1334               if(e.isPopupTrigger()) { popup = handle.getPopup()}
1335             }
1336           }
1337         }
1338         // popup menu
1339         if(e.isPopupTrigger()) {
1340           if(resourcesTree.getSelectionCount() 1) {
1341             // multiple selection in tree
1342             popup = new XJPopupMenu();
1343 
1344             // add a close all action
1345             popup.add(new XJMenuItem(new CloseSelectedResourcesAction(),
1346                     MainFrame.this));
1347 
1348             // add a close recursively all action
1349             TreePath[] selectedPaths = resourcesTree.getSelectionPaths();
1350             for(TreePath selectedPath : selectedPaths) {
1351               Object userObject = ((DefaultMutableTreeNode)
1352                 selectedPath.getLastPathComponent()).getUserObject();
1353               if(userObject instanceof NameBearerHandle
1354                 && ((NameBearerHandle)userObject).getTarget()
1355                   instanceof Controller) {
1356                 // there is at least one application
1357                 popup.add(new XJMenuItem(new
1358                   CloseRecursivelySelectedResourcesAction(), MainFrame.this));
1359                 break;
1360               }
1361             }
1362 
1363             // add a show all action
1364             selectedPaths = resourcesTree.getSelectionPaths();
1365             for(TreePath selectedPath : selectedPaths) {
1366               Object userObject = ((DefaultMutableTreeNode)
1367                 selectedPath.getLastPathComponent()).getUserObject();
1368               if (userObject instanceof Handle
1369               && !((Handle)userObject).viewsBuilt()
1370                 || (mainTabbedPane.indexOfComponent(
1371                   ((Handle)userObject).getLargeView()) == -1)) ) {
1372                 // there is at least one resource not shown
1373                 popup.add(new XJMenuItem(new ShowSelectedResourcesAction(),
1374                   MainFrame.this));
1375                 break;
1376               }
1377             }
1378 
1379             // add a hide all action
1380             selectedPaths = resourcesTree.getSelectionPaths();
1381             for(TreePath selectedPath : selectedPaths) {
1382               Object userObject = ((DefaultMutableTreeNode)
1383                 selectedPath.getLastPathComponent()).getUserObject();
1384               if (userObject instanceof Handle
1385               && ((Handle)userObject).viewsBuilt()
1386               && ((Handle)userObject).getLargeView() != null
1387               && (mainTabbedPane.indexOfComponent(
1388                 ((Handle)userObject).getLargeView()) != -1)) {
1389                 // there is at least one resource shown
1390                 popup.add(new XJMenuItem(new CloseViewsForSelectedResourcesAction(),
1391                   MainFrame.this));
1392                 break;
1393               }
1394             }
1395 
1396             popup.show(resourcesTree, e.getX(), e.getY());
1397           }
1398           else if(popup != null) {
1399             if(handle != null) {
1400               // these menu items are added after
1401               // gate.gui.NameBearerHandle#buildStaticPopupItems
1402 
1403               // add a close action
1404               if(handle instanceof NameBearerHandle) {
1405                 popup.insert(new XJMenuItem(((NameBearerHandle)handle)
1406                         .getCloseAction(), MainFrame.this)0);
1407               }
1408 
1409               // if application then add a close recursively action
1410               if(handle instanceof NameBearerHandle
1411               && handle.getTarget() instanceof Controller) {
1412                 popup.insert(new XJMenuItem(((NameBearerHandle)handle)
1413                   .getCloseRecursivelyAction(), MainFrame.this)1);
1414               }
1415 
1416               // add a show/hide action
1417               if (handle.viewsBuilt() &&
1418                   handle.getLargeView() != null
1419                   && (mainTabbedPane.indexOfComponent(
1420                           handle.getLargeView()) != -1)) {
1421                popup.insert(new XJMenuItem(new CloseViewAction(handle),
1422                  MainFrame.this)2);
1423               else {
1424                 popup.insert(new XJMenuItem(new ShowResourceAction(handle),
1425                   MainFrame.this)2);
1426               }
1427 
1428               // add a rename action
1429               popup.insert(new XJMenuItem(new RenameResourceAction(path),
1430                 MainFrame.this)3);
1431 
1432               // add a help action
1433               if(handle instanceof NameBearerHandle) {
1434                 popup.insert(new XJMenuItem(new HelpOnItemTreeAction(
1435                   (NameBearerHandle)handle), MainFrame.this)4);
1436               }
1437             }
1438 
1439             popup.show(resourcesTree, e.getX(), e.getY());
1440           }
1441         }
1442         else if(e.getID() == MouseEvent.MOUSE_CLICKED
1443              && e.getClickCount() == 2
1444              && handle != null) {
1445             // double click - show the resource
1446             select(handle);
1447         }
1448       }
1449     });
1450 
1451     resourcesTree.addTreeSelectionListener(new TreeSelectionListener() {
1452       @Override
1453       public void valueChanged(TreeSelectionEvent e) {
1454         if (!Gate.getUserConfig().getBoolean(
1455           MainFrame.class.getName()+".treeselectview")) {
1456           return;
1457         }
1458         // synchronise the selected tabbed pane with
1459         // the resource tree selection
1460         if (resourcesTree.getSelectionPaths() != null
1461          && resourcesTree.getSelectionPaths().length == 1) {
1462           Object value = e.getPath().getLastPathComponent();
1463           Object object = ((DefaultMutableTreeNode)value).getUserObject();
1464           if (object instanceof Handle
1465               && ((Handle)object).viewsBuilt()
1466               && (mainTabbedPane.indexOfComponent(
1467                       ((Handle)object).getLargeView()) != -1)) {
1468             select((Handle)object);
1469           }
1470         }
1471       }
1472     });
1473 
1474     // define keystrokes action bindings at the level of the main window
1475     InputMap inputMap = ((JComponent)this.getContentPane()).
1476       getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1477     inputMap.put(KeyStroke.getKeyStroke("control F4")"Close resource");
1478     inputMap.put(KeyStroke.getKeyStroke("shift F4")"Close recursively");
1479     inputMap.put(KeyStroke.getKeyStroke("control H")"Hide");
1480     inputMap.put(KeyStroke.getKeyStroke("control shift H")"Hide all");
1481     inputMap.put(KeyStroke.getKeyStroke("control S")"Save As XML");
1482 
1483     // add the support of the context menu key in tables and trees
1484     // TODO: remove when Swing will take care of the context menu key
1485     if (inputMap.get(KeyStroke.getKeyStroke("CONTEXT_MENU")) == null) {
1486       inputMap.put(KeyStroke.getKeyStroke("CONTEXT_MENU")"Show context menu");
1487     }
1488     ActionMap actionMap =
1489       ((JComponent)instance.getContentPane()).getActionMap();
1490     actionMap.put("Show context menu"new AbstractAction() {
1491       @Override
1492       public void actionPerformed(ActionEvent e) {
1493         KeyboardFocusManager focusManager =
1494           KeyboardFocusManager.getCurrentKeyboardFocusManager();
1495         // get the current focused component
1496         Component focusedComponent = focusManager.getFocusOwner();
1497         if (focusedComponent != null) {
1498           Point menuLocation = null;
1499           Rectangle selectionRectangle = null;
1500           if (focusedComponent instanceof JTable
1501           && ((JTable)focusedComponent).getSelectedRowCount() 0) {
1502             // selection in a JTable
1503             JTable table = (JTable)focusedComponent;
1504             selectionRectangle = table.getCellRect(
1505               table.getSelectionModel().getLeadSelectionIndex(),
1506               table.convertColumnIndexToView(table.getSelectedColumn()),
1507               false);
1508           else if (focusedComponent instanceof JTree
1509           && ((JTree)focusedComponent).getSelectionCount() 0) {
1510             // selection in a JTree
1511             JTree tree = (JTree)focusedComponent;
1512             selectionRectangle = tree.getRowBounds(
1513               tree.getSelectionModel().getLeadSelectionRow());
1514           else {
1515             // for other component set the menu location at the top left corner
1516             menuLocation = new Point(focusedComponent.getX()-1,
1517                                      focusedComponent.getY()-1);
1518           }
1519           if (menuLocation == null) {
1520             // menu location at the bottom left of the JTable or JTree
1521             menuLocation = new Point(
1522               new Double(selectionRectangle.getMinX()+1).intValue(),
1523               new Double(selectionRectangle.getMaxY()-1).intValue());
1524           }
1525 
1526           // generate a right/button 3/popup menu mouse click
1527           focusedComponent.dispatchEvent(
1528             new MouseEvent(focusedComponent, MouseEvent.MOUSE_PRESSED,
1529               e.getWhen(), MouseEvent.BUTTON3_DOWN_MASK,
1530               menuLocation.x, menuLocation.y,
1531               1, true, MouseEvent.BUTTON3));
1532         }
1533       }
1534     });
1535 
1536     mainTabbedPane.getModel().addChangeListener(new ChangeListener() {
1537       @Override
1538       public void stateChanged(ChangeEvent e) {
1539         // find the handle in the resources tree for the main view
1540         JComponent largeView =
1541           (JComponent)mainTabbedPane.getSelectedComponent();
1542         Enumeration<?> nodesEnum = resourcesTreeRoot.preorderEnumeration();
1543         boolean done = false;
1544         DefaultMutableTreeNode node = resourcesTreeRoot;
1545         while(!done && nodesEnum.hasMoreElements()) {
1546           node = (DefaultMutableTreeNode)nodesEnum.nextElement();
1547           done =
1548             node.getUserObject() instanceof Handle
1549               && ((Handle)node.getUserObject()).viewsBuilt()
1550               && ((Handle)node.getUserObject()).getLargeView() == largeView;
1551         }
1552         ActionMap actionMap =
1553           ((JComponent)instance.getContentPane()).getActionMap();
1554         if(done) {
1555           Handle handle = (Handle)node.getUserObject();
1556           if (Gate.getUserConfig().getBoolean(
1557             MainFrame.class.getName()+".viewselecttree")) {
1558             // synchronise the selection in the tabbed pane with
1559             // the one in the resources tree
1560             TreePath nodePath = new TreePath(node.getPath());
1561             resourcesTree.setSelectionPath(nodePath);
1562             resourcesTree.scrollPathToVisible(nodePath);
1563           }
1564           lowerScroll.getViewport().setView(handle.getSmallView());
1565 
1566           // redefine MainFrame actionMaps for the selected tab
1567           JComponent resource =
1568             (JComponent)mainTabbedPane.getSelectedComponent();
1569           actionMap.put("Close resource",
1570             resource.getActionMap().get("Close resource"));
1571           actionMap.put("Close recursively",
1572             resource.getActionMap().get("Close recursively"));
1573           actionMap.put("Hide"new CloseViewAction(handle));
1574           actionMap.put("Hide all"new HideAllAction());
1575           actionMap.put("Save As XML",
1576             resource.getActionMap().get("Save As XML"));
1577         }
1578         else {
1579           // the selected item is not a resource (maybe the log area?)
1580           lowerScroll.getViewport().setView(null);
1581           // disabled actions on the selected tabbed pane
1582           actionMap.put("Close resource"null);
1583           actionMap.put("Close recursively"null);
1584           actionMap.put("Hide"null);
1585           actionMap.put("Hide all"null);
1586           actionMap.put("Save As XML"null);
1587         }
1588       }
1589     });
1590 
1591     mainTabbedPane.addMouseListener(new MouseAdapter() {
1592       @Override
1593       public void mousePressed(MouseEvent e) {
1594         processMouseEvent(e);
1595       }
1596       @Override
1597       public void mouseReleased(MouseEvent e) {
1598         processMouseEvent(e);
1599       }
1600       protected void processMouseEvent(MouseEvent e){
1601         if(e.isPopupTrigger()) {
1602           int index = mainTabbedPane.getIndexAt(e.getPoint());
1603           if(index != -1) {
1604             JComponent view = (JComponent)mainTabbedPane.getComponentAt(index);
1605             Enumeration<?> nodesEnum = resourcesTreeRoot.preorderEnumeration();
1606             boolean done = false;
1607             DefaultMutableTreeNode node = resourcesTreeRoot;
1608             while(!done && nodesEnum.hasMoreElements()) {
1609               node = (DefaultMutableTreeNode)nodesEnum.nextElement();
1610               done = node.getUserObject() instanceof Handle
1611                   && ((Handle)node.getUserObject()).viewsBuilt()
1612                   && ((Handle)node.getUserObject()).getLargeView() == view;
1613             }
1614             if(done) {
1615               Handle handle = (Handle)node.getUserObject();
1616               JPopupMenu popup = handle.getPopup();
1617 
1618               // add a hide action
1619               CloseViewAction cva = new CloseViewAction(handle);
1620               XJMenuItem menuItem = new XJMenuItem(cva, MainFrame.this);
1621               popup.insert(menuItem, 0);
1622 
1623               // add a hide all action
1624               if (mainTabbedPane.getTabCount() 2) {
1625                 HideAllAction haa = new HideAllAction();
1626                 menuItem = new XJMenuItem(haa, MainFrame.this);
1627                 popup.insert(menuItem, 1);
1628               }
1629 
1630               popup.show(mainTabbedPane, e.getX(), e.getY());
1631             }
1632           }
1633         }
1634       }
1635     });
1636 
1637     addComponentListener(new ComponentAdapter() {
1638       @Override
1639       public void componentShown(ComponentEvent e) {
1640         leftSplit.setDividerLocation(0.7);
1641       }
1642       @Override
1643       public void componentResized(ComponentEvent e) {
1644         // resize proportionally the status bar elements
1645         int width = MainFrame.this.getWidth();
1646         statusBar.setPreferredSize(new Dimension(width*65/100,
1647           statusBar.getPreferredSize().height));
1648         progressBar.setPreferredSize(new Dimension(width*20/100,
1649           progressBar.getPreferredSize().height));
1650         progressBar.setMinimumSize(new Dimension(800));
1651         globalProgressBar.setPreferredSize(new Dimension(width*10/100,
1652           globalProgressBar.getPreferredSize().height));
1653         globalProgressBar.setMinimumSize(new Dimension(800));
1654       }
1655     });
1656 
1657     // blink the messages tab when new information is displayed
1658     logArea.getDocument().addDocumentListener(
1659       new javax.swing.event.DocumentListener() {
1660         @Override
1661         public void insertUpdate(javax.swing.event.DocumentEvent e) {
1662           changeOccured();
1663         }
1664 
1665         @Override
1666         public void removeUpdate(javax.swing.event.DocumentEvent e) {
1667           changeOccured();
1668         }
1669 
1670         @Override
1671         public void changedUpdate(javax.swing.event.DocumentEvent e) {
1672         }
1673 
1674         protected void changeOccured() {
1675           logHighlighter.highlight();
1676         }
1677       });
1678 
1679     logArea.addPropertyChangeListener("document"new PropertyChangeListener() {
1680       @Override
1681       public void propertyChange(PropertyChangeEvent evt) {
1682         // add the document listener
1683         logArea.getDocument().addDocumentListener(
1684           new javax.swing.event.DocumentListener() {
1685             @Override
1686             public void insertUpdate(javax.swing.event.DocumentEvent e) {
1687               changeOccured();
1688             }
1689 
1690             @Override
1691             public void removeUpdate(javax.swing.event.DocumentEvent e) {
1692               changeOccured();
1693             }
1694 
1695             @Override
1696             public void changedUpdate(javax.swing.event.DocumentEvent e) {
1697               changeOccured();
1698             }
1699 
1700             protected void changeOccured() {
1701               logHighlighter.highlight();
1702             }
1703           });
1704       }
1705     });
1706 
1707     Gate.getListeners().put("gate.event.StatusListener", MainFrame.this);
1708     Gate.getListeners().put("gate.event.ProgressListener", MainFrame.this);
1709     if(Gate.runningOnMac()) {
1710       // mac-specific initialisation
1711       initMacListeners();
1712     }
1713   }// protected void initListeners()
1714 
1715   /**
1716    * Set up the handlers to support the Macintosh Application menu. This
1717    * makes the About, Quit and Preferences menu items map to their
1718    * equivalents in GATE. If an exception occurs during this process we
1719    * print a warning.
1720    */
1721   protected void initMacListeners() {
1722     // What this method effectively does is:
1723     //
1724     // com.apple.eawt.Application app = Application.getApplication();
1725     // app.addApplicationListener(new ApplicationAdapter() {
1726     // public void handleAbout(ApplicationEvent e) {
1727     // e.setHandled(true);
1728     // new HelpAboutAction().actionPerformed(null);
1729     // }
1730     // public void handleQuit(ApplicationEvent e) {
1731     // e.setHandled(false);
1732     // new ExitGateAction().actionPerformed(null);
1733     // }
1734     // public void handlePreferences(ApplicationEvent e) {
1735     // e.setHandled(true);
1736     // optionsDialog.showDialog();
1737     // optionsDialog.dispose();
1738     // }
1739     // });
1740     //
1741     // app.setEnabledPreferencesMenu(true);
1742     //
1743     // except that it does it all by reflection so as not to
1744     // compile-time
1745     // depend on Apple classes.
1746     try {
1747       // load the Apple classes
1748       final Class<?> eawtApplicationClass =
1749         Gate.getClassLoader().loadClass("com.apple.eawt.Application");
1750       final Class<?> eawtApplicationListenerInterface =
1751         Gate.getClassLoader().loadClass("com.apple.eawt.ApplicationListener");
1752       final Class<?> eawtApplicationEventClass =
1753         Gate.getClassLoader().loadClass("com.apple.eawt.ApplicationEvent");
1754 
1755       // method used in the InvocationHandler
1756       final Method appEventSetHandledMethod =
1757         eawtApplicationEventClass.getMethod("setHandled"boolean.class);
1758 
1759       // Invocation handler used to process Apple application events
1760       InvocationHandler handler = new InvocationHandler() {
1761         private Action aboutAction = new HelpAboutAction();
1762 
1763         private Action exitAction = new ExitGateAction();
1764 
1765         @Override
1766         public Object invoke(Object proxy, Method method, Object[] args)
1767           throws Throwable {
1768           Object appEvent = args[0];
1769           if("handleAbout".equals(method.getName())) {
1770             appEventSetHandledMethod.invoke(appEvent, Boolean.TRUE);
1771             aboutAction.actionPerformed(null);
1772           }
1773           else if("handleQuit".equals(method.getName())) {
1774             appEventSetHandledMethod.invoke(appEvent, Boolean.FALSE);
1775             exitAction.actionPerformed(null);
1776           }
1777           else if("handlePreferences".equals(method.getName())) {
1778             appEventSetHandledMethod.invoke(appEvent, Boolean.TRUE);
1779             optionsDialog.showDialog();
1780             optionsDialog.dispose();
1781           }
1782 
1783           return null;
1784         }
1785       };
1786 
1787       // Create an ApplicationListener proxy instance
1788       Object applicationListenerObject =
1789         Proxy.newProxyInstance(Gate.getClassLoader(),
1790           new Class<?>[]{eawtApplicationListenerInterface}, handler);
1791 
1792       // get hold of the Application object
1793       Method getApplicationMethod =
1794         eawtApplicationClass.getMethod("getApplication");
1795       Object applicationObject = getApplicationMethod.invoke(null);
1796 
1797       // enable the preferences menu item
1798       Method setEnabledPreferencesMenuMethod =
1799         eawtApplicationClass.getMethod("setEnabledPreferencesMenu",
1800           boolean.class);
1801       setEnabledPreferencesMenuMethod.invoke(applicationObject, Boolean.TRUE);
1802 
1803       // Register our proxy instance as an ApplicationListener
1804       Method addApplicationListenerMethod =
1805         eawtApplicationClass.getMethod("addApplicationListener",
1806           eawtApplicationListenerInterface);
1807       addApplicationListenerMethod.invoke(applicationObject,
1808         applicationListenerObject);
1809     }
1810     catch(Throwable error) {
1811       // oh well, we tried
1812       String message =
1813         "There was a problem setting up the Mac "
1814         "application\nmenu.  Your options/session will not be saved if "
1815         "you exit\nwith \u2318Q, use the close button at the top-left"
1816         "corner\nof this window instead.";
1817         log.error(message, error);
1818     }
1819   }
1820 
1821   @Override
1822   public void progressChanged(int i) {
1823     // progressBar.setStringPainted(true);
1824     int oldValue = progressBar.getValue();
1825     // if((!stopAction.isEnabled()) &&
1826     // (Gate.getExecutable() != null)){
1827     // stopAction.setEnabled(true);
1828     // SwingUtilities.invokeLater(new Runnable(){
1829     // public void run(){
1830     // southBox.add(stopBtn, 0);
1831     // }
1832     // });
1833     // }
1834     if(!animator.isActive()) animator.activate();
1835     if(oldValue != i) {
1836       SwingUtilities.invokeLater(new ProgressBarUpdater(i));
1837     }
1838   }
1839 
1840   /**
1841    * Called when the process is finished.
1842    *
1843    */
1844   @Override
1845   public void processFinished() {
1846     // progressBar.setStringPainted(false);
1847     // if(stopAction.isEnabled()){
1848     // stopAction.setEnabled(false);
1849     // SwingUtilities.invokeLater(new Runnable(){
1850     // public void run(){
1851     // southBox.remove(stopBtn);
1852     // }
1853     // });
1854     // }
1855     SwingUtilities.invokeLater(new ProgressBarUpdater(0));
1856     SwingUtilities.invokeLater(new Runnable() { @Override
1857     public void run() {
1858       globalProgressBar.setVisible(false);
1859     }});
1860     animator.deactivate();
1861   }
1862   
1863   /**
1864    * Regular expression pattern for the "Start running" message.
1865    */
1866   private static final Pattern START_RUNNING_PATTERN =
1867     Pattern.compile("Start running .* on (\\d+) documents?");
1868 
1869   @Override
1870   public void statusChanged(String text) {
1871     SwingUtilities.invokeLater(new StatusBarUpdater(text));
1872     if (text != null) {
1873       Matcher m = START_RUNNING_PATTERN.matcher(text);
1874       if (m.matches()) {
1875         // get the corpus size from the status text
1876         final int corpusSize = Integer.valueOf(m.group(1));
1877         SwingUtilities.invokeLater(new Runnable() { @Override
1878         public void run() {
1879           // initialise the progress bar
1880           globalProgressBar.setMaximum(corpusSize);
1881           globalProgressBar.setValue(0);
1882           globalProgressBar.setString("0/" + corpusSize);
1883           globalProgressBar.setVisible(true);
1884         }});
1885       else if (text.startsWith("Finished running ")) {
1886         SwingUtilities.invokeLater(new Runnable() { @Override
1887         public void run() {
1888           // update the progress bar with one document processed
1889           globalProgressBar.setValue(globalProgressBar.getValue() 1);
1890           globalProgressBar.setString(globalProgressBar.getValue() "/"
1891             + globalProgressBar.getMaximum());
1892         }});
1893       }
1894     }
1895   }
1896 
1897   @Override
1898   public void resourceLoaded(CreoleEvent e) {
1899     final Resource res = e.getResource();
1900     if(Gate.getHiddenAttribute(res.getFeatures())
1901       || res instanceof VisualResourcereturn;
1902     SwingUtilities.invokeLater(new Runnable() {
1903       @Override
1904       public void run() {
1905         
1906         NameBearerHandle handle = null;
1907         
1908         if(res instanceof Controller) {
1909           handle = new NameBearerHandle(res, MainFrame.this);
1910           DefaultMutableTreeNode node = new DefaultMutableTreeNode(handle, false);
1911           resourcesTreeModel.insertNodeInto(node, applicationsRoot, 0);
1912           
1913         else if(res instanceof ProcessingResource) {
1914           handle = new NameBearerHandle(res, MainFrame.this);
1915           DefaultMutableTreeNode node = new DefaultMutableTreeNode(handle, false);
1916           resourcesTreeModel.insertNodeInto(node, processingResourcesRoot, 0);
1917         }
1918         else if(res instanceof LanguageResource) {
1919           handle = new NameBearerHandle(res, MainFrame.this);
1920           DefaultMutableTreeNode node = new DefaultMutableTreeNode(handle, false);
1921           resourcesTreeModel.insertNodeInto(node, languageResourcesRoot, 0);
1922         }
1923 
1924         if (handle != nullhandle.addProgressListener(MainFrame.this);
1925         if (handle != nullhandle.addStatusListener(MainFrame.this);
1926       }
1927     });
1928 
1929     // JPopupMenu popup = handle.getPopup();
1930     //
1931     // // Create a CloseViewAction and a menu item based on it
1932     // CloseViewAction cva = new CloseViewAction(handle);
1933     // XJMenuItem menuItem = new XJMenuItem(cva, this);
1934     // // Add an accelerator ATL+F4 for this action
1935     // menuItem.setAccelerator(KeyStroke.getKeyStroke(
1936     // KeyEvent.VK_H, ActionEvent.CTRL_MASK));
1937     // popup.insert(menuItem, 1);
1938     // popup.insert(new JPopupMenu.Separator(), 2);
1939     //
1940     // popup.insert(new XJMenuItem(
1941     // new RenameResourceAction(
1942     // new TreePath(resourcesTreeModel.getPathToRoot(node))),
1943     // MainFrame.this) , 3);
1944     //
1945     // // Put the action command in the component's action map
1946     // if (handle.getLargeView() != null)
1947     // handle.getLargeView().getActionMap().put("Hide current
1948     // view",cva);
1949     //
1950   }// resourceLoaded();
1951 
1952   @Override
1953   public void resourceUnloaded(CreoleEvent e) {
1954     final Resource res = e.getResource();
1955     if(Gate.getHiddenAttribute(res.getFeatures())) return;
1956     Runnable runner = new Runnable() {
1957       @Override
1958       public void run() {
1959         DefaultMutableTreeNode node;
1960         DefaultMutableTreeNode parent = null;
1961         if(res instanceof Controller) {
1962           parent = applicationsRoot;
1963         }else if(res instanceof ProcessingResource) {
1964           parent = processingResourcesRoot;
1965         }
1966         else if(res instanceof LanguageResource) {
1967           parent = languageResourcesRoot;
1968         }
1969         if(parent != null) {
1970           Enumeration<?> children = parent.children();
1971           while(children.hasMoreElements()) {
1972             node = (DefaultMutableTreeNode)children.nextElement();
1973             if(((NameBearerHandle)node.getUserObject()).getTarget() == res) {
1974               resourcesTreeModel.removeNodeFromParent(node);
1975               Handle handle = (Handle)node.getUserObject();
1976               if(handle.viewsBuilt()) {
1977                 if(mainTabbedPane.indexOfComponent(handle.getLargeView()) != -1)
1978                   mainTabbedPane.remove(handle.getLargeView());
1979                 if(lowerScroll.getViewport().getView() == handle.getSmallView())
1980                   lowerScroll.getViewport().setView(null);
1981               }
1982               handle.cleanup();
1983               return;
1984             }
1985           }
1986         }
1987       }
1988     };
1989     SwingUtilities.invokeLater(runner);
1990   }
1991 
1992   /** Called when a {@link gate.DataStore} has been opened */
1993   @Override
1994   public void datastoreOpened(CreoleEvent e) {
1995     final DataStore ds = e.getDatastore();
1996     if(ds.getName() == null || ds.getName().length() == 0){
1997       String name = ds.getStorageUrl();
1998       StringBuilder nameBuilder = new StringBuilder();
1999       //quick and dirty FSA
2000       int state = 0;
2001       for(int i = name.length() -1; i >= && state != ; i--){
2002         char currentChar = name.charAt(i);
2003         switch (state) {
2004           case 0:
2005             //consuming slashes at the end
2006             if(currentChar == '/'){
2007               //consume
2008             }else{
2009               //we got the first non-slash char
2010               state = 1;
2011               nameBuilder.insert(0, currentChar);
2012             }
2013             break;
2014           case 1:
2015             //eating up name chars
2016             if(currentChar == '/'){
2017               //we're done!
2018               state = 2;
2019             }else{
2020               //we got a non-slash char
2021               nameBuilder.insert(0, currentChar);
2022             }
2023             break;
2024           default:
2025             throw new LuckyException("A phanthom state of things!");
2026         }
2027       }
2028       if(nameBuilder.length() 0name = nameBuilder.toString();
2029       ds.setName(name);
2030     }
2031 
2032     SwingUtilities.invokeLater(new Runnable() {
2033       
2034       @Override
2035       public void run() {
2036         NameBearerHandle handle = new NameBearerHandle(ds, MainFrame.this);
2037         DefaultMutableTreeNode node = new DefaultMutableTreeNode(handle, false);
2038         resourcesTreeModel.insertNodeInto(node, datastoresRoot, 0);
2039         handle.addProgressListener(MainFrame.this);
2040         handle.addStatusListener(MainFrame.this);        
2041       }
2042     });    
2043 
2044     // JPopupMenu popup = handle.getPopup();
2045     // popup.addSeparator();
2046     // // Create a CloseViewAction and a menu item based on it
2047     // CloseViewAction cva = new CloseViewAction(handle);
2048     // XJMenuItem menuItem = new XJMenuItem(cva, this);
2049     // // Add an accelerator ATL+F4 for this action
2050     // menuItem.setAccelerator(KeyStroke.getKeyStroke(
2051     // KeyEvent.VK_H, ActionEvent.CTRL_MASK));
2052     // popup.add(menuItem);
2053     // // Put the action command in the component's action map
2054     // if (handle.getLargeView() != null)
2055     // handle.getLargeView().getActionMap().put("Hide current
2056     // view",cva);
2057   }// datastoreOpened();
2058 
2059   /** Called when a {@link gate.DataStore} has been created */
2060   @Override
2061   public void datastoreCreated(CreoleEvent e) {
2062     datastoreOpened(e);
2063   }
2064 
2065   /** Called when a {@link gate.DataStore} has been closed */
2066   @Override
2067   public void datastoreClosed(final CreoleEvent e) {
2068     SwingUtilities.invokeLater(new Runnable() {
2069       
2070       @Override
2071       public void run() {
2072         DataStore ds = e.getDatastore();
2073         DefaultMutableTreeNode node;
2074         DefaultMutableTreeNode parent = datastoresRoot;
2075         if(parent != null) {
2076           Enumeration<?> children = parent.children();
2077           while(children.hasMoreElements()) {
2078             node = (DefaultMutableTreeNode)children.nextElement();
2079             if(((NameBearerHandle)node.getUserObject()).getTarget() == ds) {
2080               resourcesTreeModel.removeNodeFromParent(node);
2081               NameBearerHandle handle = (NameBearerHandle)node.getUserObject();
2082 
2083               if(handle.viewsBuilt()) {
2084                 if(mainTabbedPane.indexOfComponent(handle.getLargeView()) != -1) {
2085                   mainTabbedPane.remove(handle.getLargeView());
2086                 }
2087                 if(lowerScroll.getViewport().getView() == handle.getSmallView()) {
2088                   lowerScroll.getViewport().setView(null);
2089                 }
2090               }
2091               return;
2092             }
2093           }
2094         }
2095       }
2096     });
2097     
2098   }
2099 
2100   @Override
2101   public void resourceRenamed(final Resource resource, final String oldName, final String newName) {
2102     SwingUtilities.invokeLater(new Runnable() {
2103       
2104       @Override
2105       public void run() {
2106         //first find the handle for the renamed resource
2107         Handle handle = findHandleForResource(resource);
2108         if(handle != null && handle.viewsBuilt()){
2109           //next see if there is a tab for this resource and rename it
2110           for(int i = 0; i < mainTabbedPane.getTabCount(); i++) {
2111             if(mainTabbedPane.getTitleAt(i).equals(oldName&&
2112                mainTabbedPane.getComponentAt(i== handle.getLargeView()) {
2113               mainTabbedPane.setTitleAt(i, newName);
2114               return;
2115             }
2116           }
2117         }        
2118       }
2119     });
2120   }
2121   
2122   @Override
2123   public void pluginLoaded(URL url) {
2124     // currently we don't care about this event
2125   }
2126 
2127   @Override
2128   public void pluginUnloaded(URL url) {
2129     try {
2130       String classloaderID = (new URL(url, "creole.xml")).toExternalForm();
2131 
2132       Iterator<String> it = iconByName.keySet().iterator();
2133       while(it.hasNext()) {
2134         String name = it.next();
2135         Icon icon = iconByName.get(name);
2136 
2137         ClassLoader cl = icon.getClass().getClassLoader();
2138 
2139         if(cl instanceof GateClassLoader) {
2140           if(((GateClassLoader)cl).getID().equals(classloaderID)) {
2141             it.remove();
2142           }
2143         }
2144       }
2145     catch(MalformedURLException e) {
2146       // this should be impossible!
2147 
2148       e.printStackTrace();
2149     }
2150   }
2151 
2152   /**
2153    * Overridden so we can exit when window is closed
2154    */
2155   @Override
2156   protected void processWindowEvent(WindowEvent e) {
2157     if(e.getID() == WindowEvent.WINDOW_CLOSING) {
2158       new ExitGateAction().actionPerformed(null);
2159     }
2160     super.processWindowEvent(e);
2161   }// processWindowEvent(WindowEvent e)
2162 
2163   public static java.util.Collection<Component> getGuiRoots() {
2164     return guiRoots;
2165   }
2166 
2167   /**
2168    * This method will lock all input to the gui by means of a modal
2169    * dialog. If Gate is not currently running in GUI mode this call will
2170    * be ignored. A call to this method while the GUI is locked will
2171    * cause the GUI to be unlocked and then locked again with the new
2172    * message. If a message is provided it will show in the dialog.
2173    *
2174    @param message the message to be displayed while the GUI is locked
2175    */
2176   public synchronized static void lockGUI(final String message) {
2177     // check whether GUI is up
2178     if(getGuiRoots() == null || getGuiRoots().isEmpty()) return;
2179     // if the GUI is locked unlock it so we can show the new message
2180     unlockGUI();
2181 
2182     // this call needs to return so we'll show the dialog from a
2183     // different thread
2184     // the Swing thread sounds good for that
2185     SwingUtilities.invokeLater(new Runnable() {
2186       @Override
2187       public void run() {
2188      // build the dialog contents
2189         Object[] options = new Object[]{new JButton(new StopAction())};
2190         JOptionPane pane =
2191           new JOptionPane(message, JOptionPane.WARNING_MESSAGE,
2192             JOptionPane.DEFAULT_OPTION, null, options, null);
2193 
2194         // build the dialog
2195         Component parentComp = ((List<Component>)getGuiRoots()).get(0);
2196         JDialog dialog;
2197         Window parentWindow;
2198         if(parentComp instanceof Window)
2199           parentWindow = (Window)parentComp;
2200         else parentWindow = SwingUtilities.getWindowAncestor(parentComp);
2201         if(parentWindow instanceof Frame) {
2202           dialog = new JDialog((Frame)parentWindow, "Please wait"true) {
2203             private static final long serialVersionUID = 1L;
2204             @Override
2205             protected void processWindowEvent(WindowEvent e) {
2206               if(e.getID() == WindowEvent.WINDOW_CLOSING) {
2207                 getToolkit().beep();
2208               }
2209             }
2210           };
2211         }
2212         else if(parentWindow instanceof Dialog) {
2213           dialog = new JDialog((Dialog)parentWindow, "Please wait"true) {
2214             private static final long serialVersionUID = 1L;
2215             @Override
2216             protected void processWindowEvent(WindowEvent e) {
2217               if(e.getID() == WindowEvent.WINDOW_CLOSING) {
2218                 getToolkit().beep();
2219               }
2220             }
2221           };
2222         }
2223         else {
2224           dialog = new JDialog(JOptionPane.getRootFrame()"Please wait"true) {
2225             private static final long serialVersionUID = 1L;
2226             @Override
2227             protected void processWindowEvent(WindowEvent e) {
2228               if(e.getID() == WindowEvent.WINDOW_CLOSING) {
2229                 getToolkit().beep();
2230               }
2231             }
2232           };
2233         }
2234         dialog.getContentPane().setLayout(new BorderLayout());
2235         dialog.getContentPane().add(pane, BorderLayout.CENTER);
2236         dialog.pack();
2237         dialog.setLocationRelativeTo(parentComp);
2238         dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
2239         guiLock = dialog;
2240 
2241         guiLock.setVisible(true);
2242       }
2243     });
2244 
2245     // this call should not return until the dialog is up to ensure
2246     // proper
2247     // sequentiality for lock - unlock calls
2248     /*while(guiLock == null || !guiLock.isShowing()) {
2249       try {
2250         Thread.sleep(100);
2251       }
2252       catch(InterruptedException ie) {
2253         log.debug("Interrupted sleep when the GUI is locked.", ie);
2254       }
2255     }*/
2256     
2257   }
2258 
2259   public synchronized static void unlockGUI() {
2260     
2261     Thread t = new Thread() {
2262       public void run() {
2263      // check whether GUI is up
2264         if(getGuiRoots() == null || getGuiRoots().isEmpty()) return;
2265 
2266         if(guiLock != null) {
2267           guiLock.setVisible(false);
2268           // completely dispose the dialog (causes it to disappear even if
2269           // displayed on a non-visible virtual display on Linux)
2270           // fix for bug 1369096
2271           // (http://sourceforge.net/tracker/index.php?func=detail&aid=1369096&group_id=143829&atid=756796)
2272           guiLock.dispose();
2273         }
2274         guiLock = null;
2275       }
2276     };
2277     
2278     /*if (SwingUtilities.isEventDispatchThread()) {
2279       t.start();
2280     }
2281     else {*/
2282       SwingUtilities.invokeLater(t);
2283     //}    
2284   }
2285 
2286   /** Flag to protect Frame title to be changed */
2287   private boolean titleChangable = false;
2288 
2289   public void setTitleChangable(boolean isChangable) {
2290     titleChangable = isChangable;
2291   // setTitleChangable(boolean isChangable)
2292 
2293   /** Override to avoid Protege to change Frame title */
2294   @Override
2295   public synchronized void setTitle(String title) {
2296     if(titleChangable) {
2297       super.setTitle(title);
2298     // if
2299   // setTitle(String title)
2300 
2301   /**
2302    * Method is used in NewDSAction
2303    @return the new datastore or null if an error occurs
2304    */
2305   protected DataStore createSerialDataStore() {
2306     DataStore ds = null;
2307 
2308     // get the URL (a file in this case)
2309     fileChooser.setDialogTitle("Please create a new empty directory");
2310     fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2311     fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
2312     fileChooser.setResource("gate.persist.SerialDataStore");
2313     if(fileChooser.showOpenDialog(MainFrame.this)
2314       == JFileChooser.APPROVE_OPTION) {
2315       try {
2316         URL dsURL = fileChooser.getSelectedFile().toURI().toURL();
2317         ds =
2318           Factory.createDataStore("gate.persist.SerialDataStore", dsURL
2319             .toExternalForm());
2320       }
2321       catch(MalformedURLException mue) {
2322         JOptionPane.showMessageDialog(MainFrame.this,
2323           "Invalid location for the datastore\n " + mue.toString()"GATE",
2324           JOptionPane.ERROR_MESSAGE);
2325       }
2326       catch(PersistenceException pe) {
2327         JOptionPane.showMessageDialog(MainFrame.this,
2328           "Datastore creation error!\n " + pe.toString()"GATE",
2329           JOptionPane.ERROR_MESSAGE);
2330       // catch
2331     // if
2332 
2333     return ds;
2334   // createSerialDataStore()
2335 
2336   /**
2337    * Method is used in OpenDSAction
2338    @return the opened datastore or null if an error occurs
2339    */
2340   protected DataStore openSerialDataStore() {
2341     DataStore ds = null;
2342 
2343     // get the URL (a file in this case)
2344     fileChooser.setDialogTitle("Select the datastore directory");
2345     fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2346     fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
2347     fileChooser.setResource("gate.persist.SerialDataStore");
2348     if(fileChooser.showOpenDialog(MainFrame.this)
2349       == JFileChooser.APPROVE_OPTION) {
2350       try {
2351         URL dsURL = fileChooser.getSelectedFile().toURI().toURL();
2352         ds =
2353           Factory.openDataStore("gate.persist.SerialDataStore", dsURL
2354             .toExternalForm());
2355       }
2356       catch(MalformedURLException mue) {
2357         JOptionPane.showMessageDialog(MainFrame.this,
2358           "Invalid location for the datastore\n " + mue.toString()"GATE",
2359           JOptionPane.ERROR_MESSAGE);
2360       }
2361       catch(PersistenceException pe) {
2362         JOptionPane.showMessageDialog(MainFrame.this,
2363           "Datastore opening error!\n " + pe.toString()"GATE",
2364           JOptionPane.ERROR_MESSAGE);
2365       // catch
2366     // if
2367 
2368     return ds;
2369   // openSerialDataStore()
2370 
2371   /**
2372    * Method is used in ....OpenDSAction
2373    @return the opened datastore or null if an error occurs
2374    */
2375   protected DataStore openDocServiceDataStore() {
2376     DataStore ds = null;
2377     try {
2378       String DSLocation =
2379         JOptionPane.showInputDialog(MainFrame.this,
2380           "Enter document service URL",
2381           "http://localhost:8080/docservice/services/docservice");
2382       // System.out.println("DEBUG: MainFrame.openDocServiceDataStore()
2383       // DSLocation='" + DSLocation + "'");
2384       ds =
2385         Factory.openDataStore("gleam.docservice.gate.DocServiceDataStore",
2386           DSLocation);
2387     }
2388     catch(Exception error) {
2389       String message = "Error when opening the Datastore.";
2390       log.error(message, error);
2391     }
2392     return ds;
2393   // openWSDataStore()
2394 
2395   /*
2396    * synchronized void showWaitDialog() { Point location =
2397    * getLocationOnScreen(); location.translate(10, getHeight() -
2398    * waitDialog.getHeight() - southBox.getHeight() - 10);
2399    * waitDialog.setLocation(location); waitDialog.showDialog(new
2400    * Component[]{}); }
2401    *
2402    * synchronized void hideWaitDialog() { waitDialog.goAway(); }
2403    */
2404 
2405   /*
2406    * class NewProjectAction extends AbstractAction { public
2407    * NewProjectAction(){ super("New Project", new
2408    * ImageIcon(MainFrame.class.getResource(
2409    * "/gate/resources/img/newProject")));
2410    * putValue(SHORT_DESCRIPTION,"Create a new project"); } public void
2411    * actionPerformed(ActionEvent e){ fileChooser.setDialogTitle("Select
2412    * new project file");
2413    * fileChooser.setFileSelectionMode(fileChooser.FILES_ONLY);
2414    * if(fileChooser.showOpenDialog(parentFrame) ==
2415    * fileChooser.APPROVE_OPTION){ ProjectData pData = new
2416    * ProjectData(fileChooser.getSelectedFile(), parentFrame);
2417    * addProject(pData); } } }
2418    */
2419 
2420   /** This class represent an action which brings up the Annot Diff tool */
2421   class NewAnnotDiffAction extends AbstractAction {
2422     private static final long serialVersionUID = 1L;
2423     public NewAnnotDiffAction() {
2424       super("Annotation Diff", getIcon("annotation-diff"));
2425       putValue(SHORT_DESCRIPTION,
2426         "Compare annotations and features in one or two documents");
2427     }
2428     @Override
2429     public void actionPerformed(ActionEvent e) {
2430       // find the handle in the resource tree for the displayed view
2431       Enumeration<?> nodesEnum = resourcesTreeRoot.preorderEnumeration();
2432       DefaultMutableTreeNode node;
2433       Handle handle = null;
2434       while(nodesEnum.hasMoreElements()) {
2435         node = (DefaultMutableTreeNode)nodesEnum.nextElement();
2436         if ((node.getUserObject() instanceof Handle)
2437          && ((Handle)node.getUserObject()).viewsBuilt()
2438          && (mainTabbedPane.getSelectedComponent().equals(
2439             ((Handle)node.getUserObject()).getLargeView()))) {
2440           handle = (Handle)node.getUserObject();
2441           break;
2442         }
2443       }
2444       String documentName = null;
2445       if(handle != null
2446       && handle.getTarget() instanceof Document) {
2447         documentName = ((Document)handle.getTarget()).getName();
2448       }
2449       AnnotationDiffGUI frame;
2450       if (documentName != null) {
2451         // use the document displayed in the view to compute the differences
2452         frame = new AnnotationDiffGUI("Annotation Diff Tool",
2453           documentName, documentName, null, null, null, null);
2454       else {
2455         frame = new AnnotationDiffGUI("Annotation Diff Tool");
2456       }
2457       frame.pack();
2458       frame.setLocationRelativeTo(MainFrame.this);
2459       frame.setVisible(true);
2460     }
2461   }
2462 
2463   /**
2464    * This class represent an action which brings up the corpus
2465    * evaluation tool
2466    */
2467   class NewCorpusEvalAction extends AbstractAction {
2468     private static final long serialVersionUID = 1L;
2469     public NewCorpusEvalAction() {
2470       super("Default Mode");
2471       putValue(SHORT_DESCRIPTION, "Compares stored processed set with current" +
2472         " processed set and human-annotated set");
2473       putValue(SMALL_ICON, getIcon("corpus-benchmark"));
2474     }// newCorpusEvalAction
2475 
2476     @Override
2477     public void actionPerformed(ActionEvent e) {
2478       Runnable runnable = new Runnable() {
2479         @Override
2480         public void run() {
2481           fileChooser.setDialogTitle("Please select a directory which contains "
2482             "the documents to be evaluated");
2483           fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2484           fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
2485           fileChooser.setResource(CorpusBenchmarkTool.class.getName());
2486           int state = fileChooser.showOpenDialog(MainFrame.this);
2487           File startDir = fileChooser.getSelectedFile();
2488           if(state == JFileChooser.CANCEL_OPTION || startDir == nullreturn;
2489 
2490           fileChooser.setDialogTitle(
2491             "Please select the application that you want to run");
2492           fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
2493           fileChooser.setResource(
2494             CorpusBenchmarkTool.class.getName() ".application");
2495           state = fileChooser.showOpenDialog(MainFrame.this);
2496           File testApp = fileChooser.getSelectedFile();
2497           if(state == JFileChooser.CANCEL_OPTION || testApp == nullreturn;
2498 
2499           // first create the tool and set its parameters
2500           CorpusBenchmarkTool theTool = new CorpusBenchmarkTool();
2501           theTool.setStartDirectory(startDir);
2502           theTool.setApplicationFile(testApp);
2503           theTool.setVerboseMode(verboseModeItem.isSelected());
2504 
2505           Out.prln("Please wait while GATE tools are initialised.");
2506           // initialise the tool
2507           theTool.init();
2508           // and execute it
2509           theTool.execute();
2510           theTool.printStatistics();
2511 
2512           Out.prln("<BR>Overall average precision: "
2513             + theTool.getPrecisionAverage());
2514           Out.prln("<BR>Overall average recall: " + theTool.getRecallAverage());
2515           Out.prln("<BR>Overall average fMeasure : "
2516             + theTool.getFMeasureAverage());
2517           Out.prln("<BR>Finished!");
2518           theTool.unloadPRs();
2519         }
2520       };
2521       Thread thread =
2522         new Thread(Thread.currentThread().getThreadGroup(), runnable,
2523           "NewCorpusEvalAction");
2524       thread.setPriority(Thread.MIN_PRIORITY);
2525       thread.start();
2526     }// actionPerformed();
2527   }// class NewCorpusEvalAction
2528 
2529   /**
2530    * This class represent an action which brings up the corpus
2531    * evaluation tool
2532    */
2533   class StoredMarkedCorpusEvalAction extends AbstractAction {
2534     private static final long serialVersionUID = 1L;
2535     public StoredMarkedCorpusEvalAction() {
2536       super("Human Marked Against Stored Processing Results");
2537       putValue(SHORT_DESCRIPTION,
2538         "Compares stored processed set with human-annotated set");
2539       putValue(SMALL_ICON, getIcon("corpus-benchmark"));
2540     }// newCorpusEvalAction
2541 
2542     @Override
2543     public void actionPerformed(ActionEvent e) {
2544       Runnable runnable = new Runnable() {
2545         @Override
2546         public void run() {
2547           fileChooser.setDialogTitle("Please select a directory which contains "
2548             "the documents to be evaluated");
2549           fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2550           fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
2551           fileChooser.setResource(CorpusBenchmarkTool.class.getName());
2552           int state = fileChooser.showOpenDialog(MainFrame.this);
2553           File startDir = fileChooser.getSelectedFile();
2554           if(state == JFileChooser.CANCEL_OPTION || startDir == nullreturn;
2555 
2556           // first create the tool and set its parameters
2557           CorpusBenchmarkTool theTool = new CorpusBenchmarkTool();
2558           theTool.setStartDirectory(startDir);
2559           theTool.setMarkedStored(true);
2560           theTool.setVerboseMode(verboseModeItem.isSelected());
2561           // theTool.setMarkedDS(
2562           // MainFrame.this.datastoreModeCorpusEvalToolAction.isDatastoreMode());
2563 
2564           Out
2565             .prln("Evaluating human-marked documents against pre-stored results.");
2566           // initialise the tool
2567           theTool.init();
2568           // and execute it
2569           theTool.execute();
2570           theTool.printStatistics();
2571 
2572           Out.prln("<BR>Overall average precision: "
2573             + theTool.getPrecisionAverage());
2574           Out.prln("<BR>Overall average recall: " + theTool.getRecallAverage());
2575           Out.prln("<BR>Overall average fMeasure : "
2576             + theTool.getFMeasureAverage());
2577           Out.prln("<BR>Finished!");
2578           theTool.unloadPRs();
2579         }
2580       };
2581       Thread thread =
2582         new Thread(Thread.currentThread().getThreadGroup(), runnable,
2583           "StoredMarkedCorpusEvalAction");
2584       thread.setPriority(Thread.MIN_PRIORITY);
2585       thread.start();
2586     }// actionPerformed();
2587   }// class StoredMarkedCorpusEvalActionpusEvalAction
2588 
2589   /**
2590    * This class represent an action which brings up the corpus
2591    * evaluation tool
2592    */
2593   class CleanMarkedCorpusEvalAction extends AbstractAction {
2594     private static final long serialVersionUID = 1L;
2595     public CleanMarkedCorpusEvalAction() {
2596       super("Human Marked Against Current Processing Results");
2597       putValue(SHORT_DESCRIPTION,
2598         "Compares current processed set with human-annotated set");
2599       putValue(SMALL_ICON, getIcon("corpus-benchmark"));
2600     }// newCorpusEvalAction
2601 
2602     @Override
2603     public void actionPerformed(ActionEvent e) {
2604       Runnable runnable = new Runnable() {
2605         @Override
2606         public void run() {
2607           fileChooser.setDialogTitle("Please select a directory which contains "
2608             "the documents to be evaluated");
2609           fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2610           fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
2611           fileChooser.setResource(CorpusBenchmarkTool.class.getName());
2612           int state = fileChooser.showOpenDialog(MainFrame.this);
2613           File startDir = fileChooser.getSelectedFile();
2614           if(state == JFileChooser.CANCEL_OPTION || startDir == nullreturn;
2615 
2616           fileChooser.setDialogTitle(
2617             "Please select the application that you want to run");
2618           fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
2619           fileChooser.setResource(
2620             CorpusBenchmarkTool.class.getName() ".application");
2621           state = fileChooser.showOpenDialog(MainFrame.this);
2622           File testApp = fileChooser.getSelectedFile();
2623           if(state == JFileChooser.CANCEL_OPTION || testApp == nullreturn;
2624 
2625           // first create the tool and set its parameters
2626           CorpusBenchmarkTool theTool = new CorpusBenchmarkTool();
2627           theTool.setStartDirectory(startDir);
2628           theTool.setApplicationFile(testApp);
2629           theTool.setMarkedClean(true);
2630           theTool.setVerboseMode(verboseModeItem.isSelected());
2631 
2632           Out.prln("Evaluating human-marked documents against current processing results.");
2633           // initialise the tool
2634           theTool.init();
2635           // and execute it
2636           theTool.execute();
2637           theTool.printStatistics();
2638 
2639           Out.prln("Overall average precision: "
2640             + theTool.getPrecisionAverage());
2641           Out.prln("Overall average recall: " + theTool.getRecallAverage());
2642           Out
2643             .prln("Overall average fMeasure : " + theTool.getFMeasureAverage());
2644           Out.prln("Finished!");
2645           theTool.unloadPRs();
2646         }
2647       };
2648       Thread thread =
2649         new Thread(Thread.currentThread().getThreadGroup(), runnable,
2650           "CleanMarkedCorpusEvalAction");
2651       thread.setPriority(Thread.MIN_PRIORITY);
2652       thread.start();
2653     }// actionPerformed();
2654   }// class CleanMarkedCorpusEvalActionpusEvalAction
2655 
2656   /**
2657    * This class represent an action which brings up the corpus
2658    * evaluation tool
2659    */
2660   class GenerateStoredCorpusEvalAction extends AbstractAction {
2661     private static final long serialVersionUID = 1L;
2662     public GenerateStoredCorpusEvalAction() {
2663       super("Store Corpus for Future Evaluation");
2664       putValue(SHORT_DESCRIPTION, "Store corpus for future evaluation");
2665       putValue(SMALL_ICON, getIcon("corpus-benchmark"));
2666     }// newCorpusEvalAction
2667 
2668     @Override
2669     public void actionPerformed(ActionEvent e) {
2670       Runnable runnable = new Runnable() {
2671         @Override
2672         public void run() {
2673           fileChooser.setDialogTitle("Please select a directory which contains "
2674             "the documents to be evaluated");
2675           fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
2676           fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
2677           fileChooser.setResource(CorpusBenchmarkTool.class.getName());
2678           int state = fileChooser.showOpenDialog(MainFrame.this);
2679           File startDir = fileChooser.getSelectedFile();
2680           if(state == JFileChooser.CANCEL_OPTION || startDir == nullreturn;
2681 
2682           fileChooser.setDialogTitle(
2683             "Please select the application that you want to run");
2684           fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
2685           fileChooser.setResource(
2686             CorpusBenchmarkTool.class.getName() ".application");
2687           state = fileChooser.showOpenDialog(MainFrame.this);
2688           File testApp = fileChooser.getSelectedFile();
2689           if(state == JFileChooser.CANCEL_OPTION || testApp == nullreturn;
2690 
2691           // first create the tool and set its parameters
2692           CorpusBenchmarkTool theTool = new CorpusBenchmarkTool();
2693           theTool.setStartDirectory(startDir);
2694           theTool.setApplicationFile(testApp);
2695           theTool.setGenerateMode(true);
2696 
2697           Out.prln("Processing and storing documents for future evaluation.");
2698           // initialise the tool
2699           theTool.init();
2700           // and execute it
2701           theTool.execute();
2702           theTool.unloadPRs();
2703           Out.prln("Finished!");
2704         }
2705       };
2706       Thread thread =
2707         new Thread(Thread.currentThread().getThreadGroup(), runnable,
2708           "GenerateStoredCorpusEvalAction");
2709       thread.setPriority(Thread.MIN_PRIORITY);
2710       thread.start();
2711     }// actionPerformed();
2712   }// class GenerateStoredCorpusEvalAction
2713 
2714   /**
2715    * This class represent an action which brings up the corpus
2716    * evaluation tool
2717    */
2718   class VerboseModeCorpusEvalToolAction extends AbstractAction {
2719     private static final long serialVersionUID = 1L;
2720     public VerboseModeCorpusEvalToolAction() {
2721       super("Verbose Mode");
2722     }// VerboseModeCorpusEvalToolAction
2723 
2724     public boolean isVerboseMode() {
2725       return verboseMode;
2726     }
2727 
2728     @Override
2729     public void actionPerformed(ActionEvent e) {
2730       if(!(e.getSource() instanceof JCheckBoxMenuItem)) return;
2731       verboseMode = ((JCheckBoxMenuItem)e.getSource()).getState();
2732     }// actionPerformed();
2733 
2734     protected boolean verboseMode = false;
2735   }// class f
2736 
2737   /**
2738    * Loads ANNIE without default parameters.
2739    */
2740   class LoadANNIEWithoutDefaultsAction extends AbstractAction implements
2741                                                              ANNIEConstants {
2742     private static final long serialVersionUID = 1L;
2743 
2744     public LoadANNIEWithoutDefaultsAction() {
2745       super("without Defaults");
2746       putValue(SHORT_DESCRIPTION, "Load ANNIE without default parameters");
2747       putValue(SMALL_ICON, getIcon("annie-application"));
2748     }
2749 
2750     @Override
2751     public void actionPerformed(ActionEvent e) {
2752       Runnable runnable = new Runnable() {
2753         @Override
2754         public void run() {
2755           lockGUI("ANNIE is being loaded...");
2756           final ConditionalSerialAnalyserController controller;
2757           try {
2758             // load ANNIE as an application from a gapp file
2759             controller = (ConditionalSerialAnalyserController)
2760               PersistenceManager.loadObjectFromFile(new File(new File(
2761                 Gate.getPluginsHome(), ANNIEConstants.PLUGIN_DIR),
2762                   ANNIEConstants.DEFAULT_FILE));
2763 
2764             statusChanged("ANNIE loaded!");
2765             unlockGUI();
2766           }
2767           catch(Exception error) {
2768             unlockGUI();
2769             String message =
2770               "There was an error when loading the ANNIE application.";
2771             log.error(message, error);
2772             return;
2773           }
2774 
2775           SwingUtilities.invokeLater(new Runnable() {
2776             @Override
2777             public void run() {
2778               List<ProcessingResource> prs =
2779                 new ArrayList<ProcessingResource>(controller.getPRs());
2780               for(ProcessingResource pr : prs) {
2781                 try {
2782                   SwingUtilities.invokeLater(new Runnable() {
2783                     @Override
2784                     public void run() {
2785                       // select last processing resource in resources tree
2786                       int selectedRow = resourcesTree.getRowForPath(
2787                         new TreePath(processingResourcesRoot.getPath()));
2788                       selectedRow += processingResourcesRoot.getChildCount();
2789                       resourcesTree.setSelectionRow(selectedRow);
2790                       resourcesTree.scrollRowToVisible(selectedRow);
2791                     }
2792                   });
2793                   // get the parameters for each ANNIE PR
2794                   ResourceData resData = Gate.getCreoleRegister()
2795                     .get(pr.getClass().getName());
2796                   if (resData == null) {
2797                     throw new ResourceInstantiationException(
2798                       pr.getName() " was not possible to load.");
2799                   }
2800                   fileChooser.setResource(resData.getClassName());
2801                   if(newResourceDialog.show(resData, "Parameters for the new "
2802                     + resData.getName())) {
2803                     // add the PR with user parameters
2804                     controller.add((ProcessingResource)
2805                       Factory.createResource(pr.getClass().getName(),
2806                       newResourceDialog.getSelectedParameters()));
2807                   }
2808                   // remove the PR with default parameters
2809                   Factory.deleteResource(pr);
2810                 }
2811                 catch(ResourceInstantiationException error) {
2812                   String message = "There was an error when creating"
2813                     " the resource: " + pr.getName() ".";
2814                   log.error(message, error);
2815                 }
2816               // for(Object loadedPR : loadedPRs)
2817             }
2818           });
2819         }
2820       };
2821       Thread thread = new Thread(runnable, "LoadANNIEWithoutDefaultsAction");
2822       thread.setPriority(Thread.MIN_PRIORITY);
2823       thread.start();
2824     }
2825   }// class LoadANNIEWithoutDefaultsAction
2826 
2827   /**
2828    * Loads the application.
2829    */
2830   class LoadApplicationAction extends AbstractAction {
2831     private static final long serialVersionUID = 1L;
2832 
2833     private String name, icon;
2834     
2835     private URL pipelineURL;
2836 
2837     public LoadApplicationAction(String name, URL pipelineURL) {
2838       this(name,"application",pipelineURL);
2839     }
2840     
2841     public LoadApplicationAction(String name, File pipelineFile) {
2842       this(name,"application",pipelineFile);
2843     }
2844     
2845     public LoadApplicationAction(String name, String icon, File pipelineFile) {
2846       super(name,MainFrame.getIcon(icon));
2847       if (getValue(Action.SMALL_ICON== nullputValue(Action.SMALL_ICON, MainFrame.getIcon("application"));
2848       this.name = name;
2849       this.icon = icon;
2850       try {
2851         this.pipelineURL = pipelineFile.toURI().toURL();
2852       }
2853       catch (MalformedURLException e) {
2854         throw new RuntimeException("When is a file not a URL? I don't know but this stack trace might help!",e);
2855       }
2856     }
2857     
2858     public LoadApplicationAction(String name, String icon, URL pipelineURL) {
2859       super(name,MainFrame.getIcon(icon));
2860       if (getValue(Action.SMALL_ICON== nullputValue(Action.SMALL_ICON, MainFrame.getIcon("application"));
2861       this.name = name;
2862       this.pipelineURL = pipelineURL;
2863       this.icon = icon;
2864     }
2865 
2866     @Override
2867     public void actionPerformed(ActionEvent e) {
2868       if (pipelineURL == null) {
2869         System.err.println("The URL of the application has not been correctly set and cannot be loaded.");
2870         return;
2871       }
2872       
2873       Runnable runnable = new Runnable() {
2874         @Override
2875         public void run() {
2876           lockGUI(name + " is being loaded...");
2877           try {
2878             long startTime = System.currentTimeMillis();
2879 
2880             // load LingPipe as an application from a gapp file
2881             Resource controller =
2882                 (Resource)PersistenceManager.loadObjectFromUrl(pipelineURL);
2883 
2884             if(!icon.equals(controller.getFeatures().get("gate.gui.icon"))) {
2885               
2886               controller.getFeatures().put("gate.gui.icon", icon);
2887 
2888               @SuppressWarnings("unchecked")
2889               Enumeration<TreeNode> items =
2890                   applicationsRoot.depthFirstEnumeration();
2891               while(items.hasMoreElements()) {
2892                 TreeNode n = items.nextElement();
2893                 if(instanceof DefaultMutableTreeNode) {
2894                   Object userObject =
2895                       ((DefaultMutableTreeNode)n).getUserObject();
2896                   if(userObject instanceof NameBearerHandle) {
2897                     if(((NameBearerHandle)userObject).getTarget().equals(
2898                         controller)) {
2899                       ((NameBearerHandle)((DefaultMutableTreeNode)n)
2900                           .getUserObject())
2901                           .setIcon((Icon)LoadApplicationAction.this
2902                               .getValue(Action.SMALL_ICON));
2903                       resourcesTree.invalidate();
2904                       break;
2905                     }
2906                   }
2907                 }
2908               }
2909             }            
2910 
2911             long endTime = System.currentTimeMillis();
2912             statusChanged(name
2913                     " loaded in "
2914                     + NumberFormat.getInstance().format(
2915                             (double)(endTime - startTime1000" seconds");
2916           catch(Exception error) {
2917             String message =
2918                     "There was an error when loading the " + name
2919                             " application.";
2920             log.error(message, error);
2921           finally {
2922             unlockGUI();
2923           }
2924         }
2925       };
2926       Thread thread = new Thread(runnable, "LoadApplicationAction");
2927       thread.setPriority(Thread.MIN_PRIORITY);
2928       thread.start();
2929     }
2930   }// class LoadApplicationAction
2931 
2932   class NewBootStrapAction extends AbstractAction {
2933     private static final long serialVersionUID = 1L;
2934     public NewBootStrapAction() {
2935       super("BootStrap Wizard", getIcon("application"));
2936       putValue(SHORT_DESCRIPTION, "Create a generic resource to be completed");
2937     }// NewBootStrapAction
2938 
2939     @Override
2940     public void actionPerformed(ActionEvent e) {
2941       BootStrapDialog bootStrapDialog = new BootStrapDialog(MainFrame.this);
2942       bootStrapDialog.setVisible(true);
2943     }// actionPerformed();
2944   }// class NewBootStrapAction
2945 
2946   class ManagePluginsAction extends AbstractAction {
2947     private static final long serialVersionUID = 1L;
2948     public ManagePluginsAction() {
2949       super("Manage CREOLE Plugins...");
2950       putValue(SHORT_DESCRIPTION,
2951         "Load, unload, add and remove CREOLE plugins");
2952       putValue(SMALL_ICON, new AvailableIcon(24,24));
2953     }
2954 
2955     @Override
2956     public void actionPerformed(ActionEvent e) {
2957       if(pluginManager == null) {
2958         pluginManager = new PluginUpdateManager(MainFrame.this);
2959       }
2960       pluginManager.setVisible(true);
2961     }
2962   }
2963 
2964   class NewResourceAction extends AbstractAction {
2965     private static final long serialVersionUID = 1L;
2966     /** Used for creation of resource menu item and creation dialog */
2967     ResourceData rData;
2968 
2969     public NewResourceAction(ResourceData rData) {
2970       super(rData.getName());
2971       putValue(SHORT_DESCRIPTION, rData.getComment());
2972       this.rData = rData;
2973       putValue(SMALL_ICON, getIcon(rData.getIcon()));
2974     // NewResourceAction(ResourceData rData)
2975 
2976     @Override
2977     public void actionPerformed(ActionEvent evt) {
2978       Runnable runnable = new Runnable() {
2979         @Override
2980         public void run() {
2981           newResourceDialog.setTitle("Parameters for the new "
2982             + rData.getName());
2983           fileChooser.setResource(rData.getClassName());
2984           newResourceDialog.show(rData);
2985         }
2986       };
2987       SwingUtilities.invokeLater(runnable);
2988     // actionPerformed
2989   // class NewResourceAction extends AbstractAction
2990 
2991   static class StopAction extends AbstractAction {
2992     private static final long serialVersionUID = 1L;
2993     public StopAction() {
2994       super(" Stop! ");
2995       putValue(SHORT_DESCRIPTION, "Stops the current action");
2996     }
2997 
2998     @Override
2999     public boolean isEnabled() {
3000       return Gate.getExecutable() != null;
3001     }
3002 
3003     @Override
3004     public void actionPerformed(ActionEvent e) {
3005       Executable ex = Gate.getExecutable();
3006       if(ex != nullex.interrupt();
3007     }
3008   }
3009 
3010   /**
3011    * Method is used in NewDSAction
3012    @return the new datastore or null if an error occurs
3013    */
3014   protected DataStore createSearchableDataStore() {
3015     try {
3016 
3017       JPanel mainPanel = new JPanel(new GridBagLayout());
3018 
3019       final JTextField dsLocation = new JTextField(""20);
3020       dsLocation.setEditable(false);
3021       
3022       final JTextField indexLocation = new JTextField(""20);
3023       indexLocation.setToolTipText("directory to store the the lucene index");
3024 
3025       JTextField btat = new JTextField("Token"20);
3026       btat.setToolTipText("Examples: Token, AnnotationSetName.Token, "
3027         + Constants.DEFAULT_ANNOTATION_SET_NAME + ".Token");
3028       JCheckBox createTokensAutomatically =
3029         new JCheckBox("Create Tokens Automatically");
3030       createTokensAutomatically.setSelected(true);
3031       JTextField iuat = new JTextField(""20);
3032       iuat.setToolTipText("Examples: Sentence, AnnotationSetName.Sentence, "
3033         + Constants.DEFAULT_ANNOTATION_SET_NAME + ".Sentence");
3034 
3035       final List<String> inputASList = new ArrayList<String>();
3036       inputASList.add("Key");
3037       inputASList.add(Constants.DEFAULT_ANNOTATION_SET_NAME);
3038       
3039       final JTextField inputAS = new JTextField(""20);
3040       inputAS.setText("Key;"+Constants.DEFAULT_ANNOTATION_SET_NAME);
3041       inputAS.setEditable(false);
3042       
3043       JButton editInputAS = new JButton(getIcon("edit-list"));
3044       editInputAS.addActionListener(new ActionListener() {
3045         @Override
3046         public void actionPerformed(ActionEvent ae) {
3047           ListEditorDialog listEditor =
3048             new ListEditorDialog(instance, inputASList, "java.lang.String");
3049           @SuppressWarnings("unchecked")
3050           List<String> result = listEditor.showDialog();
3051           if(result != null) {
3052             inputASList.clear();
3053             inputASList.addAll(result);
3054             if(inputASList.size() 0) {
3055               String text =
3056                 inputASList.get(0== null
3057                   ? Constants.DEFAULT_ANNOTATION_SET_NAME
3058                   : inputASList.get(0);
3059               for(int j = 1; j < inputASList.size(); j++) {
3060                 text +=
3061                   ";"
3062                     (inputASList.get(j== null
3063                       ? Constants.DEFAULT_ANNOTATION_SET_NAME
3064                       : inputASList.get(j));
3065               }
3066               inputAS.setText(text);
3067             }
3068             else {
3069               inputAS.setText("");
3070             }
3071           }
3072         }
3073       });
3074 
3075       JComboBox<String> asie = new JComboBox<String>(new String[]{"include""exclude"});
3076       inputAS.setToolTipText("Leave blank for indexing all annotation sets. \"" 
3077               + Constants.DEFAULT_ANNOTATION_SET_NAME + 
3078               "\" indicates the default annotation set");
3079 
3080       final List<String> fteList = new ArrayList<String>();
3081       fteList.add("SpaceToken");
3082       fteList.add("Split");
3083       final JTextField fte = new JTextField(""20);
3084       fte.setText("SpaceToken;Split");
3085       fte.setEditable(false);
3086       JButton editFTE = new JButton(getIcon("edit-list"));
3087       editFTE.addActionListener(new ActionListener() {
3088         @Override
3089         public void actionPerformed(ActionEvent ae) {
3090           ListEditorDialog listEditor =
3091             new ListEditorDialog(instance, fteList, "java.lang.String");
3092           @SuppressWarnings("unchecked")
3093           List<String> result = listEditor.showDialog();
3094           if(result != null) {
3095             fteList.clear();
3096             fteList.addAll(result);
3097             if(fteList.size() 0) {
3098               String text =
3099                 fteList.get(0== null
3100                   ? Constants.DEFAULT_ANNOTATION_SET_NAME
3101                   : fteList.get(0);
3102               for(int j = 1; j < fteList.size(); j++) {
3103                 text +=
3104                   ";"
3105                     (fteList.get(j== null
3106                       ? Constants.DEFAULT_ANNOTATION_SET_NAME
3107                       : fteList.get(j));
3108               }
3109               fte.setText(text);
3110             }
3111             else {
3112               fte.setText("");
3113             }
3114           }
3115         }
3116       });
3117 
3118       JComboBox<String> ftie = new JComboBox<String>(new String[]{"include""exclude"});
3119       ftie.setSelectedIndex(1);
3120       fte.setToolTipText("Leave blank for inclusion of all features");
3121 
3122       JButton indexBrowse = new JButton(getIcon("open-file"));
3123       indexBrowse.addActionListener(new ActionListener() {
3124         @Override
3125         public void actionPerformed(ActionEvent ae) {
3126           // first we need to ask for a new empty directory
3127           fileChooser.setDialogTitle(
3128             "Please create a new empty directory for datastore");
3129           fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
3130           fileChooser.setResource("gate.DataStore.index");
3131           if(fileChooser.showOpenDialog(MainFrame.this)
3132             == JFileChooser.APPROVE_OPTION) {
3133             try {
3134               indexLocation.setText(fileChooser.getSelectedFile().toURI()
3135                 .toURL().toExternalForm());
3136             }
3137             catch(Exception e) {
3138               indexLocation.setText("");
3139             }
3140           }
3141         }
3142       });
3143 
3144       GridBagConstraints constraints = new GridBagConstraints();
3145       constraints.gridx = GridBagConstraints.RELATIVE;
3146       constraints.gridy = 0;
3147       constraints.gridwidth = 3;
3148       constraints.anchor = GridBagConstraints.WEST;
3149       constraints.fill = GridBagConstraints.NONE;
3150       constraints.insets = new Insets(0005);
3151       mainPanel.add(new JLabel("Datastore URL:"), constraints);
3152 
3153       constraints = new GridBagConstraints();
3154       constraints.gridx = GridBagConstraints.RELATIVE;
3155       constraints.gridy = 0;
3156       constraints.gridwidth = 6;
3157       constraints.fill = GridBagConstraints.HORIZONTAL;
3158       constraints.insets = new Insets(00010);
3159       mainPanel.add(dsLocation, constraints);
3160 
3161       // second row
3162       constraints = new GridBagConstraints();
3163       constraints.gridx = GridBagConstraints.RELATIVE;
3164       constraints.gridy = 1;
3165       constraints.gridwidth = 3;
3166       constraints.anchor = GridBagConstraints.WEST;
3167       constraints.fill = GridBagConstraints.NONE;
3168       constraints.insets = new Insets(0005);
3169       mainPanel.add(new JLabel("Index Location:"), constraints);
3170 
3171       constraints = new GridBagConstraints();
3172       constraints.gridx = GridBagConstraints.RELATIVE;
3173       constraints.gridy = 1;
3174       constraints.gridwidth = 5;
3175       constraints.fill = GridBagConstraints.HORIZONTAL;
3176       constraints.insets = new Insets(00010);
3177       mainPanel.add(indexLocation, constraints);
3178 
3179       constraints = new GridBagConstraints();
3180       constraints.gridx = GridBagConstraints.RELATIVE;
3181       constraints.gridy = 1;
3182       constraints.gridwidth = 1;
3183       constraints.anchor = GridBagConstraints.NORTHWEST;
3184       mainPanel.add(indexBrowse, constraints);
3185       indexBrowse.setBorderPainted(false);
3186       indexBrowse.setContentAreaFilled(false);
3187 
3188       // third row row
3189       constraints = new GridBagConstraints();
3190       constraints.gridx = GridBagConstraints.RELATIVE;
3191       constraints.gridy = 2;
3192       constraints.gridwidth = 2;
3193       constraints.anchor = GridBagConstraints.WEST;
3194       constraints.fill = GridBagConstraints.NONE;
3195       constraints.insets = new Insets(0005);
3196       mainPanel.add(new JLabel("Annotation Sets:"), constraints);
3197 
3198       constraints = new GridBagConstraints();
3199       constraints.gridx = GridBagConstraints.RELATIVE;
3200       constraints.gridy = 2;
3201       constraints.gridwidth = 1;
3202       constraints.fill = GridBagConstraints.HORIZONTAL;
3203       constraints.insets = new Insets(00010);
3204       mainPanel.add(asie, constraints);
3205 
3206       constraints = new GridBagConstraints();
3207       constraints.gridx = GridBagConstraints.RELATIVE;
3208       constraints.gridy = 2;
3209       constraints.gridwidth = 5;
3210       constraints.fill = GridBagConstraints.HORIZONTAL;
3211       constraints.insets = new Insets(00010);
3212       mainPanel.add(inputAS, constraints);
3213 
3214       constraints = new GridBagConstraints();
3215       constraints.gridx = GridBagConstraints.RELATIVE;
3216       constraints.gridy = 2;
3217       constraints.gridwidth = 1;
3218       constraints.anchor = GridBagConstraints.NORTHWEST;
3219       mainPanel.add(editInputAS, constraints);
3220       editInputAS.setBorderPainted(false);
3221       editInputAS.setContentAreaFilled(false);
3222 
3223       // fourth row row
3224       constraints = new GridBagConstraints();
3225       constraints.gridx = GridBagConstraints.RELATIVE;
3226       constraints.gridy = 3;
3227       constraints.gridwidth = 3;
3228       constraints.anchor = GridBagConstraints.WEST;
3229       constraints.fill = GridBagConstraints.NONE;
3230       constraints.insets = new Insets(0005);
3231       mainPanel.add(new JLabel("Base Token Type:"), constraints);
3232 
3233       constraints = new GridBagConstraints();
3234       constraints.gridx = GridBagConstraints.RELATIVE;
3235       constraints.gridy = 3;
3236       constraints.gridwidth = 5;
3237       constraints.anchor = GridBagConstraints.NORTHWEST;
3238       mainPanel.add(btat, constraints);
3239 
3240       // fifth row
3241       constraints = new GridBagConstraints();
3242       constraints.gridx = 4;
3243       constraints.gridy = 4;
3244       constraints.gridwidth = 5;
3245       constraints.anchor = GridBagConstraints.WEST;
3246       constraints.fill = GridBagConstraints.NONE;
3247       constraints.insets = new Insets(0005);
3248       mainPanel.add(createTokensAutomatically, constraints);
3249 
3250       // sixth row
3251       constraints = new GridBagConstraints();
3252       constraints.gridx = GridBagConstraints.RELATIVE;
3253       constraints.gridy = 5;
3254       constraints.gridwidth = 3;
3255       constraints.anchor = GridBagConstraints.WEST;
3256       constraints.fill = GridBagConstraints.NONE;
3257       constraints.insets = new Insets(0005);
3258       mainPanel.add(new JLabel("Index Unit Type:"), constraints);
3259 
3260       constraints = new GridBagConstraints();
3261       constraints.gridx = GridBagConstraints.RELATIVE;
3262       constraints.gridy = 5;
3263       constraints.gridwidth = 5;
3264       constraints.anchor = GridBagConstraints.NORTHWEST;
3265       mainPanel.add(iuat, constraints);
3266 
3267       // seventh row
3268       constraints = new GridBagConstraints();
3269       constraints.gridx = GridBagConstraints.RELATIVE;
3270       constraints.gridy = 6;
3271       constraints.gridwidth = 2;
3272       constraints.anchor = GridBagConstraints.WEST;
3273       constraints.fill = GridBagConstraints.NONE;
3274       constraints.insets = new Insets(0005);
3275       mainPanel.add(new JLabel("Features:"), constraints);
3276 
3277       constraints = new GridBagConstraints();
3278       constraints.gridx = GridBagConstraints.RELATIVE;
3279       constraints.gridy = 6;
3280       constraints.gridwidth = 1;
3281       constraints.fill = GridBagConstraints.HORIZONTAL;
3282       constraints.insets = new Insets(00010);
3283       mainPanel.add(ftie, constraints);
3284 
3285       constraints = new GridBagConstraints();
3286       constraints.gridx = GridBagConstraints.RELATIVE;
3287       constraints.gridy = 6;
3288       constraints.gridwidth = 5;
3289       constraints.fill = GridBagConstraints.HORIZONTAL;
3290       constraints.insets = new Insets(00010);
3291       mainPanel.add(fte, constraints);
3292 
3293       constraints = new GridBagConstraints();
3294       constraints.gridx = GridBagConstraints.RELATIVE;
3295       constraints.gridy = 6;
3296       constraints.gridwidth = 1;
3297       constraints.anchor = GridBagConstraints.NORTHWEST;
3298       mainPanel.add(editFTE, constraints);
3299       editFTE.setBorderPainted(false);
3300       editFTE.setContentAreaFilled(false);
3301 
3302       // get the URL (a folder in this case)
3303       fileChooser.setDialogTitle("Please create a new empty directory");
3304       fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
3305       fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
3306       fileChooser.setResource("gate.persist.LuceneDataStoreImpl");
3307       int response = fileChooser.showOpenDialog(MainFrame.this);
3308       if(response == JFileChooser.APPROVE_OPTION) {
3309         try {
3310           File dsFolder = fileChooser.getSelectedFile();
3311           dsLocation.setText(dsFolder.toURI().toURL().toExternalForm());
3312           File indexFolder = 
3313             new File(dsFolder.getParentFile(), dsFolder.getName()+"-index");
3314           indexLocation.setText(indexFolder.toURI().toURL().toExternalForm());
3315         }
3316         catch(MalformedURLException mue) {
3317           JOptionPane.showMessageDialog(MainFrame.this,
3318             "Invalid location\n " + mue.toString()"GATE",
3319             JOptionPane.ERROR_MESSAGE);
3320         }
3321       else {
3322         return null;
3323       }
3324       
3325       
3326       boolean validEntry = false;
3327       while(!validEntry) {
3328         int returnValue =
3329           JOptionPane.showOptionDialog(MainFrame.this, mainPanel,
3330             "SearchableDataStore", JOptionPane.PLAIN_MESSAGE,
3331             JOptionPane.OK_CANCEL_OPTION, getIcon("empty"),
3332             new String[]{"OK""Cancel"}"OK");
3333         
3334         if(returnValue == JOptionPane.OK_OPTION) {
3335           
3336           // sanity check parameters
3337           
3338           if(dsLocation.getText().equals(indexLocation.getText())) {
3339             JOptionPane.showMessageDialog(MainFrame.this,
3340                     "Datastore and index cannot be stored in the same directory",
3341                     "Error", JOptionPane.ERROR_MESSAGE);
3342           }
3343           else {
3344             // check if index folder can be created
3345             try {
3346               File indexDir = 
3347                 new File(new URL(indexLocation.getText()).getFile());
3348               if(indexDir.exists() && indexDir.isFile()) {
3349                 JOptionPane.showMessageDialog(MainFrame.this,
3350                         indexDir.getAbsolutePath() 
3351                         " is a file on your disk. Index directory must be an" +
3352                         " empty folder.",
3353                         "Error", JOptionPane.ERROR_MESSAGE);
3354                 continue;
3355               else if(indexDir.isDirectory() && indexDir.list().length > 0) {
3356                 JOptionPane.showMessageDialog(instance,
3357                         "Index directory " + indexDir.getAbsolutePath() 
3358                         " must be an empty folder. ",
3359                         "Error", JOptionPane.ERROR_MESSAGE);
3360                 continue;
3361               else {
3362                 if(!indexDir.exists()) {
3363                   if(!indexDir.mkdirs()) {
3364                     JOptionPane.showMessageDialog(MainFrame.this,
3365                             "Cannot create index directory " 
3366                             indexDir.getAbsolutePath() "an empty folder. ",
3367                             "Error", JOptionPane.ERROR_MESSAGE);
3368                     continue;
3369                   }
3370                 }
3371               }
3372             catch(MalformedURLException mue) {
3373               JOptionPane.showMessageDialog(MainFrame.this,
3374                       "Invalid index location "+indexLocation.getText(),
3375                       "Error", JOptionPane.ERROR_MESSAGE);
3376               continue;
3377             catch(SecurityException se) {
3378               JOptionPane.showMessageDialog(MainFrame.this,
3379                       "Could not create a directory "+indexLocation.getText() 
3380                       " because "+se.getMessage(),
3381                       "Error", JOptionPane.ERROR_MESSAGE);
3382               continue;
3383             }
3384             
3385             // if here.. an empty index directory exists
3386             // break the loop by setting validEntry to true 
3387             validEntry = true;            
3388             DataStore ds =
3389               Factory.createDataStore("gate.persist.LuceneDataStoreImpl",
3390                 dsLocation.getText());
3391     
3392             // we need to set Indexer
3393             Class<?>[] consParam = new Class<?>[1];
3394             consParam[0= URL.class;
3395             Constructor<?> constructor =
3396               Class.forName("gate.creole.annic.lucene.LuceneIndexer", true,
3397                 Gate.getClassLoader()).getConstructor(consParam);
3398             Object indexer =
3399               constructor.newInstance(new URL(indexLocation.getText()));
3400     
3401             Map<String, Object> parameters = new HashMap<String, Object>();
3402             parameters.put(Constants.INDEX_LOCATION_URL, new URL(indexLocation
3403               .getText()));
3404             parameters.put(Constants.BASE_TOKEN_ANNOTATION_TYPE, btat.getText());
3405             parameters.put(Constants.INDEX_UNIT_ANNOTATION_TYPE, iuat.getText());
3406             parameters.put(Constants.CREATE_TOKENS_AUTOMATICALLY,
3407               createTokensAutomatically.isSelected());
3408     
3409             if(inputAS.getText().trim().length() 0) {
3410               ArrayList<String> inputASList1 = new ArrayList<String>();
3411               String[] inputASArray = inputAS.getText().trim().split(";");
3412               if(inputASArray != null && inputASArray.length > 0) {
3413                 inputASList1.addAll(Arrays.asList(inputASArray));
3414               }
3415               if(asie.getSelectedIndex() == 0) {
3416                 // user has provided values for inclusion
3417                 parameters.put(Constants.ANNOTATION_SETS_NAMES_TO_INCLUDE,
3418                   inputASList1);
3419                 parameters.put(Constants.ANNOTATION_SETS_NAMES_TO_EXCLUDE,
3420                   new ArrayList<String>());
3421               }
3422               else {
3423                 // user has provided values for exclusion
3424                 parameters.put(Constants.ANNOTATION_SETS_NAMES_TO_EXCLUDE,
3425                   inputASList1);
3426                 parameters.put(Constants.ANNOTATION_SETS_NAMES_TO_INCLUDE,
3427                   new ArrayList<String>());
3428               }
3429             }
3430             else {
3431               parameters.put(Constants.ANNOTATION_SETS_NAMES_TO_EXCLUDE,
3432                 new ArrayList<String>());
3433               parameters.put(Constants.ANNOTATION_SETS_NAMES_TO_INCLUDE,
3434                 new ArrayList<String>());
3435             }
3436     
3437             if(fte.getText().trim().length() 0) {
3438               ArrayList<String> fteList1 = new ArrayList<String>();
3439               String[] inputASArray = fte.getText().trim().split(";");
3440               if(inputASArray != null && inputASArray.length > 0) {
3441                 fteList1.addAll(Arrays.asList(inputASArray));
3442               }
3443               if(ftie.getSelectedIndex() == 0) {
3444                 // user has provided values for inclusion
3445                 parameters.put(Constants.FEATURES_TO_INCLUDE, fteList1);
3446                 parameters.put(Constants.FEATURES_TO_EXCLUDE,
3447                   new ArrayList<String>());
3448               }
3449               else {
3450                 // user has provided values for exclusion
3451                 parameters.put(Constants.FEATURES_TO_EXCLUDE, fteList1);
3452                 parameters.put(Constants.FEATURES_TO_INCLUDE,
3453                   new ArrayList<String>());
3454               }
3455             }
3456             else {
3457               parameters
3458                 .put(Constants.FEATURES_TO_EXCLUDE, new ArrayList<String>());
3459               parameters
3460                 .put(Constants.FEATURES_TO_INCLUDE, new ArrayList<String>());
3461             }
3462     
3463             Class<?>[] params = new Class<?>[2];
3464             params[0=
3465               Class.forName("gate.creole.annic.Indexer", true, Gate
3466                 .getClassLoader());
3467             params[1= Map.class;
3468             Method indexerMethod = ds.getClass().getMethod("setIndexer", params);
3469             indexerMethod.invoke(ds, indexer, parameters);
3470     
3471             // Class[] searchConsParams = new Class[0];
3472             Constructor<?> searcherConst =
3473               Class.forName("gate.creole.annic.lucene.LuceneSearcher", true,
3474                 Gate.getClassLoader()).getConstructor();
3475             Object searcher = searcherConst.newInstance();
3476             Class<?>[] searchParams = new Class<?>[1];
3477             searchParams[0=
3478               Class.forName("gate.creole.annic.Searcher", true, Gate
3479                 .getClassLoader());
3480             Method searcherMethod =
3481               ds.getClass().getMethod("setSearcher", searchParams);
3482             searcherMethod.invoke(ds, searcher);
3483             return ds;
3484           }
3485         }
3486         else {
3487           validEntry = true;
3488         }
3489       }
3490       return null;
3491     }
3492     catch(Exception e) {
3493       throw new GateRuntimeException(e);
3494     }
3495   // createSearchableDataStore()
3496 
3497   /**
3498    * Method is used in OpenDSAction
3499    @return the opened datastore or null if an error occurs
3500    */
3501   protected DataStore openSearchableDataStore() {
3502     DataStore ds = null;
3503 
3504     // get the URL (a file in this case)
3505     fileChooser.setDialogTitle("Select the datastore directory");
3506     fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
3507     fileChooser.setResource("gate.DataStore.data");
3508     if(fileChooser.showOpenDialog(MainFrame.this)
3509       == JFileChooser.APPROVE_OPTION) {
3510       try {
3511         URL dsURL = fileChooser.getSelectedFile().toURI().toURL();
3512         ds =
3513           Factory.openDataStore("gate.persist.LuceneDataStoreImpl", dsURL
3514             .toExternalForm());
3515       }
3516       catch(MalformedURLException mue) {
3517         JOptionPane.showMessageDialog(MainFrame.this,
3518           "Invalid location for the datastore\n " + mue.toString()"GATE",
3519           JOptionPane.ERROR_MESSAGE);
3520       }
3521       catch(PersistenceException pe) {
3522         JOptionPane.showMessageDialog(MainFrame.this,
3523           "Datastore opening error!\n " + pe.toString()"GATE",
3524           JOptionPane.ERROR_MESSAGE);
3525       // catch
3526     // if
3527 
3528     return ds;
3529   // openSerialDataStore()
3530 
3531   class NewDSAction extends AbstractAction {
3532     private static final long serialVersionUID = 1L;
3533     public NewDSAction() {
3534       super("Create Datastore");
3535       putValue(SHORT_DESCRIPTION, "Create a new datastore");
3536       putValue(SMALL_ICON, getIcon("datastore"));
3537     }
3538 
3539     @Override
3540     public void actionPerformed(ActionEvent e) {
3541       Map<String,String> dsTypes = DataStoreRegister.getDataStoreClassNames();
3542       HashMap<String,String> dsTypeByName = new HashMap<String,String>();
3543       for(Map.Entry<String, String> entry : dsTypes.entrySet()) {
3544         dsTypeByName.put(entry.getValue(), entry.getKey());
3545       }
3546 
3547       if(!dsTypeByName.isEmpty()) {
3548         JLabel label = new JLabel("Select a type of Datastore:");
3549         final JList<String> list = new JList<String>(dsTypeByName.keySet().toArray(new String[dsTypeByName.keySet().size()]));
3550         String initialSelection = Gate.getUserConfig().getString(
3551           MainFrame.class.getName()+".datastoretype");
3552         if (dsTypeByName.containsKey(initialSelection)) {
3553           list.setSelectedValue(initialSelection, true);
3554         else {
3555           list.setSelectedIndex(0);
3556         }
3557         list.setVisibleRowCount(Math.min(10, list.getModel().getSize()));
3558         list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
3559         final JOptionPane optionPane = new JOptionPane(
3560           new Object[]{label, new JScrollPane(list)},
3561           JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION,
3562           getIcon("datastore")new String[]{"OK""Cancel""Help"}"OK");
3563         final JDialog dialog = new JDialog(
3564           MainFrame.this, "Create a datastore"true);
3565         dialog.setContentPane(optionPane);
3566         list.addMouseListener(new MouseAdapter() {
3567           @Override
3568           public void mouseClicked(MouseEvent e) {
3569             if (e.getClickCount() == 2) {
3570               optionPane.setValue("OK");
3571               dialog.setVisible(false);
3572             }
3573           }
3574         });
3575         optionPane.addPropertyChangeListener(new PropertyChangeListener() {
3576           @Override
3577           public void propertyChange(PropertyChangeEvent e) {
3578             Object value = optionPane.getValue();
3579             if (value == null || value.equals(JOptionPane.UNINITIALIZED_VALUE)) {
3580               return;
3581             }
3582             if (dialog.isVisible()
3583             && e.getSource() == optionPane
3584             && e.getPropertyName().equals(JOptionPane.VALUE_PROPERTY)) {
3585               if (optionPane.getValue().equals("Help")) {
3586                 // don't close the dialog
3587                 optionPane.setValue(JOptionPane.UNINITIALIZED_VALUE);
3588                 showHelpFrame("sec:datastores""gate.persist.SerialDataStore");
3589               else {
3590                 dialog.setVisible(false);
3591               }
3592             }
3593           }
3594         });
3595         dialog.pack();
3596         dialog.setLocationRelativeTo(MainFrame.this);
3597         dialog.setVisible(true);
3598         Object answer = optionPane.getValue();
3599         if(answer == null) { return}
3600         String className = dsTypeByName.get(list.getSelectedValue());
3601         if(answer.equals("OK"&& !list.isSelectionEmpty()) {
3602           Gate.getUserConfig().put(MainFrame.class.getName()+".datastoretype",
3603             list.getSelectedValue());
3604           if(className.equals("gate.persist.SerialDataStore")) {
3605             createSerialDataStore();
3606           }
3607           else if(className.equals("gate.persist.LuceneDataStoreImpl")) {
3608             createSearchableDataStore();
3609           }
3610           else {
3611             throw new UnsupportedOperationException("Unimplemented option!\n"
3612               "Use a serial datastore");
3613           }
3614         }
3615       }
3616       else {
3617         // no ds types
3618         JOptionPane.showMessageDialog(MainFrame.this,
3619           "Could not find any registered types " "of datastores...\n"
3620             "Check your GATE installation!""GATE",
3621           JOptionPane.ERROR_MESSAGE);
3622 
3623       }
3624     }
3625   }// class NewDSAction extends AbstractAction
3626 
3627   class LoadResourceFromFileAction extends AbstractAction {
3628     private static final long serialVersionUID = 1L;
3629     public LoadResourceFromFileAction() {
3630       super("Restore Application from File...");
3631       putValue(SHORT_DESCRIPTION,
3632         "Restores a previously saved application from a file");
3633       putValue(SMALL_ICON, getIcon("open-application"));
3634     }
3635 
3636     @Override
3637     public void actionPerformed(ActionEvent e) {
3638       ExtensionFileFilter filter = new ExtensionFileFilter(
3639         "GATE Application files (.gapp, .xgapp)"".gapp"".xgapp");
3640       fileChooser.addChoosableFileFilter(filter);
3641       fileChooser.setFileFilter(filter);
3642       fileChooser.setDialogTitle("Select a file for this resource");
3643       fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
3644       fileChooser.setResource("lastapplication");
3645 
3646       if (fileChooser.showOpenDialog(MainFrame.this)
3647         == JFileChooser.APPROVE_OPTION) {
3648         final File file = fileChooser.getSelectedFile();
3649         Runnable runnable = new Runnable() { @Override
3650         public void run() {
3651         try {
3652           Object resource = PersistenceManager.loadObjectFromFile(file);
3653           if(resource instanceof Resource) {
3654             Map<String, String> locations = fileChooser.getLocations();
3655             Resource res = (Resourceresource;
3656             // save also the location of the application with its name
3657             locations.put("application."+res.getName(),file.getAbsolutePath());
3658             locations.put("application.zip."+res.getName(),
3659               file.getAbsolutePath().replaceFirst("\\.[^.]{3,5}$"".zip"));
3660             // add this application to the list of recent applications
3661             String list = locations.get("applications");
3662             if (list == null) { list = ""}
3663             list = list.replaceFirst("\\Q"+res.getName()+"\\E(;|$)""");
3664             list = res.getName() ";" + list;
3665             locations.put("applications", list);
3666             fileChooser.setLocations(locations);
3667           }
3668         }
3669         catch(MalformedURLException e) {
3670           log.error("Error when saving the resource URL.", e);
3671         }
3672         catch (final Exception error) {
3673           SwingUtilities.invokeLater(new Runnable() {
3674             @Override
3675             public void run() {
3676               String message = error.getMessage();
3677               log.error(message, error);
3678             }
3679           });
3680         }
3681         finally {
3682           processFinished();
3683         }
3684         }};
3685         Thread thread = new Thread(runnable, "LoadResourceFromFileAction");
3686         thread.setPriority(Thread.MIN_PRIORITY);
3687         thread.start();
3688       }
3689     }
3690   }
3691 
3692   /**
3693    * Closes the view associated to a resource. Does not remove the
3694    * resource from the system, only its view.
3695    */
3696   class CloseViewAction extends AbstractAction {
3697     private static final long serialVersionUID = 1L;
3698     public CloseViewAction(Handle handle) {
3699       super("Hide");
3700       putValue(SHORT_DESCRIPTION, "Hide this resource view");
3701       putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("control H"));
3702       this.handle = handle;
3703     }
3704 
3705     @Override
3706     public void actionPerformed(ActionEvent e) {
3707       SwingUtilities.invokeLater(new Runnable() { @Override
3708       public void run() {
3709         mainTabbedPane.remove(handle.getLargeView());
3710         mainTabbedPane.setSelectedIndex(mainTabbedPane.getTabCount() 1);
3711         // remove all GUI resources used by this handle
3712         handle.removeViews();
3713       }});
3714     }
3715 
3716     Handle handle;
3717   }
3718 
3719   class CloseViewsForSelectedResourcesAction extends AbstractAction {
3720     private static final long serialVersionUID = 1L;
3721     public CloseViewsForSelectedResourcesAction() {
3722       super("Hide all");
3723       putValue(SHORT_DESCRIPTION, "Hide the selected resources");
3724     }
3725 
3726     @Override
3727     public void