1   /*
2    *  Copyright (c) 1998-2001, The University of Sheffield.
3    *
4    *  This file is part of GATE (see http://gate.ac.uk/), and is free
5    *  software, licenced under the GNU Library General Public License,
6    *  Version 2, June 1991 (in the distribution as file licence.html,
7    *  and also available at http://gate.ac.uk/gate/licence.html).
8    *
9    *  Angel Kirilov 26/03/2002
10   *
11   *  $Id: ShellSlacFrame.java,v 1.29 2002/06/26 15:12:49 nasso Exp $
12   *
13   */
14  
15  package gate.gui;
16  
17  import java.awt.Component;
18  import java.awt.Container;
19  import java.awt.AWTEvent;
20  import java.awt.AWTException;
21  import java.awt.Font;
22  import java.awt.Window;
23  import java.awt.Dialog;
24  import java.awt.Frame;
25  import java.awt.Color;
26  import java.awt.Toolkit;
27  import java.awt.Dimension;
28  import java.awt.BorderLayout;
29  import java.awt.Point;
30  import java.awt.event.*;
31  import java.awt.font.TextAttribute;
32  import java.awt.GraphicsEnvironment;
33  
34  import java.text.*;
35  
36  import javax.swing.*;
37  import javax.swing.tree.*;
38  import javax.swing.event.*;
39  import javax.swing.plaf.FontUIResource;
40  
41  import java.beans.*;
42  
43  import java.util.*;
44  import java.io.*;
45  import java.net.*;
46  
47  import gate.*;
48  
49  import gate.creole.*;
50  import gate.event.*;
51  import gate.persist.*;
52  import gate.util.*;
53  import gate.swing.*;
54  import gate.security.*;
55  import junit.framework.*;
56  //import guk.im.*;
57  
58  
59  /**
60   * The main Shell SLAC Gate GUI frame.
61   */
62  public class ShellSlacFrame extends MainFrame {
63  
64    /** Debug flag */
65    private static final boolean DEBUG = false;
66  
67    /** Shell GUI application */
68    private CorpusController application = null;
69  
70    /** Shell GUI corpus */
71    private Corpus corpus = null;
72    private Corpus oneDocCorpus = null;
73  
74    /** Shell GUI documents DataStore */
75    private DataStore dataStore = null;
76  
77    /** Keep this action for enable/disable the menu item */
78    private Action saveAction = null;
79    /** Keep this action for enable/disable the menu item */
80    private Action runOneAction = null;
81    private Action runAction = null;
82  
83    /** Default corpus resource name */
84    public static final String DEFAULT_SLUG_CORPUS_NAME = "SLUG Corpus";
85    public static final String ONE_DOC_SLUG_CORPUS_NAME = "SLUG One Doc Corpus";
86  
87    /** New frame */
88    public ShellSlacFrame() {
89      super(true);
90  //    guiRoots.clear();
91  //    guiRoots.add(this);
92  
93      initShellSlacLocalData();
94      initShellSlacGuiComponents();
95    } // ShellSlacFrame
96  
97    protected void initShellSlacLocalData(){
98      createCorpus();
99  //    createDefaultApplication();
100     String applicationURL =
101       System.getProperty(GateConstants.APPLICATION_JAVA_PROPERTY_NAME);
102     if(applicationURL != null) {
103       createDefaultApplication(applicationURL);
104     }
105     else {
106       // create default ANNIE
107       createDefaultApplication();
108     } // if
109 
110     dataStore = null;
111   } // initLocalData
112 
113   protected void initShellSlacGuiComponents() {
114     super.setJMenuBar(createMenuBar());
115   } // initShellSlacGuiComponents()
116 
117   /** Create the new Shell SLAC menu */
118   private JMenuBar createMenuBar() {
119     //MENUS
120     JMenuBar retMenuBar = new JMenuBar();
121 
122     JMenu fileMenu = new JMenu("File");
123     Action action;
124 
125     ResourceData rDataDocument = getDocumentResourceData();
126     if(rDataDocument != null) {
127       action = new NewResourceAction(rDataDocument);
128       action.putValue(action.NAME, "New Document");
129       action.putValue(action.SHORT_DESCRIPTION,"Create a new document");
130 
131       fileMenu.add(new XJMenuItem(action, this));
132 
133     } // if
134     
135     // Open All... action - open multiple files from directory
136     corpusFiller = new CorpusFillerComponent();
137     action = new PopulateCorpusAction();
138     action.putValue(action.NAME, "New Documents...");
139     action.putValue(action.SHORT_DESCRIPTION,"Create multiple documents");
140     fileMenu.add(new XJMenuItem(action, this));
141 
142     fileMenu.add(new XJMenuItem(new CloseSelectedDocumentAction(), this));
143     fileMenu.add(new XJMenuItem(new CloseAllDocumentAction(), this));
144 
145     fileMenu.addSeparator();
146 
147     action = new ImportDocumentAction();
148     fileMenu.add(new XJMenuItem(action, this));
149 
150     JMenu exportMenu = new JMenu("Export");
151     action = new ExportDocumentAction();
152     exportMenu.add(new XJMenuItem(action, this));
153     action = new ExportDocumentInlineAction();
154     exportMenu.add(new XJMenuItem(action, this));
155     fileMenu.add(exportMenu);
156     
157     JMenu exportAllMenu = new JMenu("Export All");
158     action = new ExportAllDocumentAction();
159     exportAllMenu.add(new XJMenuItem(action, this));
160     action = new ExportAllDocumentInlineAction();
161     exportAllMenu.add(new XJMenuItem(action, this));
162     fileMenu.add(exportAllMenu);
163 
164 /*
165     action = new StoreAllDocumentAction();
166     action.setEnabled(false);
167     saveAction = action;
168     fileMenu.add(new XJMenuItem(action, this));
169     action = new StoreAllDocumentAsAction();
170     fileMenu.add(new XJMenuItem(action, this));
171     action = new LoadAllDocumentAction();
172     fileMenu.add(new XJMenuItem(action, this));
173 
174     action = new LoadResourceFromFileAction();
175     action.putValue(action.NAME, "Load application");
176     fileMenu.add(new XJMenuItem(action, this));
177 
178     action = new RestoreDefaultApplicationAction();
179     fileMenu.add(new XJMenuItem(action, this));
180 
181     action = new TestStoreAction();
182     fileMenu.add(new XJMenuItem(action, this));
183 */
184 
185     fileMenu.addSeparator();
186 
187 //    action = new ExitGateAction();
188     // define exit action without save of session
189     action = new AbstractAction () {
190       public void actionPerformed(ActionEvent e) {
191         setVisible(false);
192         dispose();
193         System.exit(0);
194       }
195     };
196     action.putValue(action.NAME, "Exit");
197     fileMenu.add(new XJMenuItem(action, this));
198     retMenuBar.add(fileMenu);
199 
200     JMenu analyseMenu = new JMenu("Analyse");
201 
202     action = new RunApplicationOneDocumentAction();
203     if(application == null) {
204       action.setEnabled(false);
205     } // if
206     runOneAction = action;
207     analyseMenu.add(new XJMenuItem(action, this));
208     retMenuBar.add(analyseMenu);
209 
210     action = new RunApplicationAction();
211     if(application == null) {
212       action.setEnabled(false);
213     } // if
214     runAction = action;
215     analyseMenu.add(new XJMenuItem(action, this));
216     retMenuBar.add(analyseMenu);
217 
218     JMenu toolsMenu = new JMenu("Tools");
219     createToolsMenuItems(toolsMenu);
220     retMenuBar.add(toolsMenu);
221 
222     JMenu helpMenu = new JMenu("Help");
223     helpMenu.add(new HelpAboutSlugAction());
224     retMenuBar.add(helpMenu);
225 
226     return retMenuBar;
227   } // createMenuBar()
228 
229   /** Should check for registered Creole components and populate menu.
230    *  <BR> In first version is hardcoded. */
231   private void createToolsMenuItems(JMenu toolsMenu) {
232     toolsMenu.add(new NewAnnotDiffAction());
233     toolsMenu.add(
234       new AbstractAction("Unicode editor", getIcon("unicode.gif")){
235       public void actionPerformed(ActionEvent evt){
236         new guk.Editor();
237       }
238     });
239 
240     /*add the ontology editor to the tools menu ontotext.bp */
241     toolsMenu.add(newOntologyEditorAction);
242 
243     if (System.getProperty("gate.slug.gazetteer") != null)
244       toolsMenu.add(newGazetteerEditorAction);
245 
246   } // createToolsMenuItems()
247 
248   /** Find ResourceData for "Create Document" menu item. */
249   private ResourceData getDocumentResourceData() {
250     ResourceData result = null;
251 
252     CreoleRegister reg = Gate.getCreoleRegister();
253     List lrTypes = reg.getPublicLrTypes();
254 
255     if(lrTypes != null && !lrTypes.isEmpty()){
256       Iterator lrIter = lrTypes.iterator();
257       while(lrIter.hasNext()){
258         ResourceData rData = (ResourceData)reg.get(lrIter.next());
259         if("gate.corpora.DocumentImpl".equalsIgnoreCase(rData.getClassName())) {
260           result = rData;
261           break;
262         } // if
263       } // while
264     } // if
265 
266     return result;
267   } // getDocumentResourceData()
268 
269   /** Here default ANNIE is created. Could be changed. */
270   private void createDefaultApplication() {
271     // Loads ANNIE with defaults
272     Runnable loadAction = new ANNIERunnable(ShellSlacFrame.this);
273 
274     Thread thread = new Thread(loadAction, "");
275     thread.setPriority(Thread.MIN_PRIORITY);
276     thread.start();
277   } // createDefaultApplication
278 
279   /** Load serialized application from file. */
280   private void createDefaultApplication(String url) {
281     ApplicationLoadRun run = new ApplicationLoadRun(url, this);
282     Thread thread = new Thread(run, "");
283     thread.setPriority(Thread.MIN_PRIORITY);
284     thread.start();
285   } // createDefaultApplication
286 
287   /** Create corpus for application */
288   private void createCorpus() {
289     try {
290       Factory.newCorpus(DEFAULT_SLUG_CORPUS_NAME);
291       Factory.newCorpus(ONE_DOC_SLUG_CORPUS_NAME);
292     } catch (ResourceInstantiationException ex) {
293       ex.printStackTrace();
294       throw new GateRuntimeException("Error in creating build in corpus.");
295     } // catch
296   } // createCorpus()
297 
298   /** Override base class method */
299   public void resourceLoaded(CreoleEvent e) {
300     super.resourceLoaded(e);
301 
302     Resource res = e.getResource();
303 
304     if(res instanceof CorpusController) {
305       if(application != null) {
306         // remove old application
307         Factory.deleteResource(application);
308       } // if
309       application = (CorpusController) res;
310 
311       runOneAction.setEnabled(true);
312       runAction.setEnabled(true);
313       if(corpus != null)
314         application.setCorpus(corpus);
315     } // if
316 
317     if(res instanceof Corpus) {
318       Corpus resCorpus = (Corpus) res;
319 
320       if(DEFAULT_SLUG_CORPUS_NAME.equals(resCorpus.getName())) {
321         corpus = resCorpus;
322         if(application != null)
323           application.setCorpus(corpus);
324       } // if
325 
326       if(ONE_DOC_SLUG_CORPUS_NAME.equals(resCorpus.getName())) {
327         oneDocCorpus = resCorpus;
328       } // if
329     } // if
330 
331     if(res instanceof Document) {
332       Document doc = (Document) res;
333       corpus.add(doc);
334       showDocument(doc);
335     } // if
336   }// resourceLoaded();
337 
338   /** Find in resource tree and show the document */
339   protected void showDocument(Document doc) {
340     // should find NameBearerHandle for document and call
341     Handle handle = null;
342     Enumeration nodesEnum = resourcesTreeRoot.preorderEnumeration();
343     boolean done = false;
344     DefaultMutableTreeNode node = resourcesTreeRoot;
345     Object obj;
346 
347     while(!done && nodesEnum.hasMoreElements()){
348       node = (DefaultMutableTreeNode)nodesEnum.nextElement();
349       obj = node.getUserObject();
350       if(obj instanceof Handle) {
351         handle = (Handle)obj;
352         obj = handle.getTarget();
353         done = obj instanceof Document
354           && doc == (Document)obj;
355       } // if
356     } // while
357 
358     if(done){
359       select(handle);
360     } // if
361   } // showDocument(Document doc)
362 
363   /** Called when a {@link gate.DataStore} has been opened.
364    *  Save corpus on datastore open. */
365   public void datastoreOpened(CreoleEvent e){
366     super.datastoreOpened(e);
367     if(corpus == null) return;
368 
369     DataStore ds = e.getDatastore();
370     try {
371       if(dataStore != null) {
372         // close old datastore if any
373         dataStore.close();
374       } // if
375       // put documents in datastore
376       saveAction.setEnabled(false);
377 
378       LanguageResource persCorpus = ds.adopt(corpus, null);
379       ds.sync(persCorpus);
380       // change corpus with the new persistent corpus
381       Factory.deleteResource((LanguageResource)corpus);
382       corpus = (Corpus) persCorpus;
383       if(application != null) application.setCorpus(corpus);
384 
385       dataStore = ds;
386       saveAction.setEnabled(true);
387     } catch (PersistenceException pex) {
388       pex.printStackTrace();
389     } catch (gate.security.SecurityException sex) {
390       sex.printStackTrace();
391     } // catch
392   } // datastoreOpened(CreoleEvent e)
393 
394   /** Return handle to selected tab resource */
395   private Handle getSelectedResource() {
396     JComponent largeView = (JComponent)
397                                 mainTabbedPane.getSelectedComponent();
398 
399     Handle result = null;
400     Enumeration nodesEnum = resourcesTreeRoot.preorderEnumeration();
401     boolean done = false;
402     DefaultMutableTreeNode node = resourcesTreeRoot;
403     while(!done && nodesEnum.hasMoreElements()){
404       node = (DefaultMutableTreeNode)nodesEnum.nextElement();
405       done = node.getUserObject() instanceof Handle &&
406              ((Handle)node.getUserObject()).getLargeView()
407               == largeView;
408     }
409     if(done)
410       result = (Handle)node.getUserObject();
411 
412     return result;
413   } // getSelectedResource()
414 
415   /** Export All store of documents from SLUG corpus */
416   private void saveDocuments(File targetDir) {
417     if(corpus == null || corpus.size() == 0) return;
418 
419     Document doc;
420     String target = targetDir.getPath();
421     URL fileURL;
422     String fileName = null;
423     int index;
424 
425     MainFrame.lockGUI("Export all documents...");
426 
427     target = target+File.separatorChar;
428     for(int i=0; i<corpus.size(); ++i) {
429       doc = (Document) corpus.get(i);
430       fileURL = doc.getSourceUrl();
431       if(fileURL != null)
432         fileName = fileURL.toString();
433         index = fileName.lastIndexOf('/');
434         if(index != -1) {
435           fileName = fileName.substring(index+1, fileName.length());
436         }
437       else
438         fileName = "content_txt";
439 
440       // create full file name
441       fileName = target + fileName+".xml";
442       try{
443 
444         // Prepare to write into the xmlFile using UTF-8 encoding
445         OutputStreamWriter writer = new OutputStreamWriter(
446                         new FileOutputStream(new File(fileName)),"UTF-8");
447 
448         // Write (test the toXml() method)
449         // This Action is added only when a gate.Document is created.
450         // So, is for sure that the resource is a gate.Document
451         writer.write(doc.toXml());
452         writer.flush();
453         writer.close();
454       } catch (Exception ex){
455         ex.printStackTrace(Out.getPrintWriter());
456       } finally{
457         MainFrame.unlockGUI();
458       } // finally
459     } // for
460 
461     MainFrame.unlockGUI();
462   } // saveDocuments(File targetDir)
463 
464 //------------------------------------------------------------------------------
465 //  Inner classes section
466 
467   /** Run the current application SLAC */
468   class RunApplicationAction extends AbstractAction {
469     public RunApplicationAction() {
470       super("Analyse All", getIcon("menu_controller.gif"));
471       putValue(SHORT_DESCRIPTION, "Run the application to process documents");
472     } // RunApplicationAction()
473 
474     public void actionPerformed(ActionEvent e) {
475       if (application != null && corpus != null && corpus.size() > 0) {
476         application.setCorpus(corpus);
477         SerialControllerEditor editor = new SerialControllerEditor();
478         editor.setTarget(application);
479         editor.runAction.actionPerformed(null);
480       } // if
481     } // actionPerformed(ActionEvent e)
482   } // class RunApplicationAction extends AbstractAction
483 
484   /** Run the current application SLAC on current document */
485   class RunApplicationOneDocumentAction extends AbstractAction {
486     public RunApplicationOneDocumentAction() {
487       super("Analyse", getIcon("menu_controller.gif"));
488       putValue(SHORT_DESCRIPTION,
489           "Run the application to process current document");
490     } // RunApplicationOneDocumentAction()
491 
492     public void actionPerformed(ActionEvent e) {
493       if (application != null) {
494         Handle handle = getSelectedResource();
495         if(handle == null) return;
496         Object target = handle.getTarget();
497         if(target == null) return;
498 
499         if(target instanceof Document) {
500           Document doc = (Document) target;
501           oneDocCorpus.clear();
502           oneDocCorpus.add(doc);
503 
504           application.setCorpus(oneDocCorpus);
505 
506           SerialControllerEditor editor = new SerialControllerEditor();
507           editor.setTarget(application);
508           editor.runAction.actionPerformed(null);
509         } // if - Document
510       } // if
511     } // actionPerformed(ActionEvent e)
512   } // class RunApplicationOneDocumentAction extends AbstractAction
513 
514   class RestoreDefaultApplicationAction extends AbstractAction {
515     public RestoreDefaultApplicationAction() {
516       super("Create ANNIE application");
517       putValue(SHORT_DESCRIPTION, "Create default ANNIE application");
518     } // RestoreDefaultApplicationAction()
519 
520     public void actionPerformed(ActionEvent e) {
521       createDefaultApplication();
522     } // actionPerformed(ActionEvent e)
523   } // class RestoreDefaultApplicationAction extends AbstractAction
524 
525   class CloseSelectedDocumentAction extends AbstractAction {
526     public CloseSelectedDocumentAction() {
527       super("Close Document");
528       putValue(SHORT_DESCRIPTION, "Closes the selected document");
529     } // CloseSelectedDocumentAction()
530 
531     public void actionPerformed(ActionEvent e) {
532       JComponent resource = (JComponent)
533                                   mainTabbedPane.getSelectedComponent();
534       if (resource != null){
535         Action act = resource.getActionMap().get("Close resource");
536         if (act != null)
537           act.actionPerformed(null);
538       }// End if
539     } // actionPerformed(ActionEvent e)
540   } // class CloseSelectedDocumentAction extends AbstractAction
541 
542   class CloseAllDocumentAction extends AbstractAction {
543     public CloseAllDocumentAction() {
544       super("Close All");
545       putValue(SHORT_DESCRIPTION, "Closes all documents");
546     } // CloseAllDocumentAction()
547 
548     public void actionPerformed(ActionEvent e) {
549       JComponent resource;
550       for(int i=mainTabbedPane.getTabCount()-1; i>0; --i) {
551 
552         resource = (JComponent) mainTabbedPane.getComponentAt(i);
553         if (resource != null){
554           Action act = resource.getActionMap().get("Close resource");
555           if (act != null)
556             act.actionPerformed(null);
557         }// End if
558       } // for
559     } // actionPerformed(ActionEvent e)
560   } // class CloseAllDocumentAction extends AbstractAction
561 
562   class StoreAllDocumentAsAction extends AbstractAction {
563     public StoreAllDocumentAsAction() {
564       super("Store all Documents As...");
565       putValue(SHORT_DESCRIPTION,
566         "Store all opened in the application documents in new directory");
567     } // StoreAllDocumentAsAction()
568 
569     public void actionPerformed(ActionEvent e) {
570       createSerialDataStore();
571     } // actionPerformed(ActionEvent e)
572   } // class StoreAllDocumentAction extends AbstractAction
573 
574   class StoreAllDocumentAction extends AbstractAction {
575     public StoreAllDocumentAction() {
576       super("Store all Documents");
577       putValue(SHORT_DESCRIPTION,"Store all opened in the application documents");
578     } // StoreAllDocumentAction()
579 
580     public void actionPerformed(ActionEvent e) {
581       if(dataStore != null) {
582         try {
583           dataStore.sync(corpus);
584         } catch (PersistenceException pex) {
585           pex.printStackTrace();
586         } catch (gate.security.SecurityException sex) {
587           sex.printStackTrace();
588         } // catch
589       } // if
590     } // actionPerformed(ActionEvent e)
591   } // class StoreAllDocumentAction extends AbstractAction
592 
593   class LoadAllDocumentAction extends AbstractAction {
594     public LoadAllDocumentAction() {
595       super("Load all Documents");
596       putValue(SHORT_DESCRIPTION,"Load documents from storage");
597     } // StoreAllDocumentAction()
598 
599     public void actionPerformed(ActionEvent e) {
600       if(dataStore != null) {
601         // on close all resources will be closed too
602         try {
603           dataStore.close();
604         } catch (PersistenceException pex) {
605           pex.printStackTrace();
606         } // catch
607         dataStore = null;
608       } // if
609 
610       // should open a datastore
611       dataStore = openSerialDataStore();
612 
613       if(dataStore != null) {
614         // load from datastore
615         List corporaIDList = null;
616         List docIDList = null;
617         String docID = "";
618         FeatureMap features;
619         Document doc;
620 
621         try {
622           corporaIDList = dataStore.getLrIds("gate.corpora.CorpusImpl");
623           docIDList = dataStore.getLrIds("gate.corpora.DocumentImpl");
624         } catch (PersistenceException pex) {
625           pex.printStackTrace();
626         } // catch
627 
628         features = Factory.newFeatureMap();
629         features.put(DataStore.LR_ID_FEATURE_NAME, docID);
630         features.put(DataStore.DATASTORE_FEATURE_NAME, dataStore);
631 
632         for(int i=0; i < docIDList.size(); ++i) {
633           docID = (String) docIDList.get(i);
634           // read the document back
635           features.put(DataStore.LR_ID_FEATURE_NAME, docID);
636           doc = null;
637           try {
638             doc = (Document)
639               Factory.createResource("gate.corpora.DocumentImpl", features);
640           } catch (gate.creole.ResourceInstantiationException rex) {
641             rex.printStackTrace();
642           } // catch
643 
644           if(doc != null) corpus.add(doc);
645         } // for
646       } // if
647 
648     } // actionPerformed(ActionEvent e)
649   } // class LoadAllDocumentAction extends AbstractAction
650 
651   class TestStoreAction extends AbstractAction {
652     public TestStoreAction() {
653       super("Test Store application");
654       putValue(SHORT_DESCRIPTION,"Store the application");
655     } // TestStoreAction()
656 
657     public void actionPerformed(ActionEvent e) {
658       if(application != null) {
659         // load/store test
660         try {
661           File file = new File("D:/temp/tempapplication.tmp");
662           ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
663           long startTime = System.currentTimeMillis();
664           oos.writeObject(application);
665           long endTime = System.currentTimeMillis();
666 
667           System.out.println("Storing completed in " +
668             NumberFormat.getInstance().format(
669             (double)(endTime - startTime) / 1000) + " seconds");
670 
671           ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
672           Object object;
673           startTime = System.currentTimeMillis();
674           object = ois.readObject();
675           endTime = System.currentTimeMillis();
676           application = (CorpusController) object;
677 
678           System.out.println("Loading completed in " +
679             NumberFormat.getInstance().format(
680             (double)(endTime - startTime) / 1000) + " seconds");
681 
682         } catch (Exception ex) {
683           ex.printStackTrace();
684         } // catch
685       } // if
686     } // actionPerformed(ActionEvent e)
687   } // class TestStoreAction extends AbstractAction
688 
689   /** Import document action */
690   class ImportDocumentAction extends AbstractAction {
691     public ImportDocumentAction() {
692       super("Import");
693       putValue(SHORT_DESCRIPTION, "Open a document in XML format");
694     } // ImportDocumentAction()
695 
696     public void actionPerformed(ActionEvent e) {
697       fileChooser.setDialogTitle("Select file to Import from");
698       fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
699 
700       int res = fileChooser.showOpenDialog(ShellSlacFrame.this);
701       if(res == fileChooser.APPROVE_OPTION) {
702         File file = fileChooser.getSelectedFile();
703 
704         String str = "";
705         char chArr[] = new char[1024];
706 
707         try {
708           FileReader reader = new FileReader(file);
709           int readedChars = reader.read(chArr);
710           reader.close();
711           str = new String(chArr, 0, readedChars);
712         } catch (Exception ex) {
713           // do nothing - some error, so we shouldn't read file anyway
714         } // catch
715 
716         boolean isGateXmlDocument = false;
717         // Detect whether or not is a GateXmlDocument
718         if(str.indexOf("<GateDocument") != -1  ||
719            str.indexOf(" GateDocument") != -1)
720           isGateXmlDocument = true;
721 
722         if(isGateXmlDocument) {
723           Runnable run = new ImportRunnable(file);
724           Thread thread = new Thread(run, "");
725           thread.setPriority(Thread.MIN_PRIORITY);
726           thread.start();
727         }
728         else {
729           JOptionPane.showMessageDialog(ShellSlacFrame.this,
730               "The import file '"+file.getAbsolutePath()+"'\n"
731               +"is not a SLUG document.",
732               "Import error",
733               JOptionPane.WARNING_MESSAGE);
734         } // if
735       } // if
736     } // actionPerformed(ActionEvent e)
737   } // class ImportDocumentAction extends AbstractAction
738 
739   /** Object to run ExportAll in a new Thread */
740   private class ImportRunnable implements Runnable {
741     File file;
742     ImportRunnable(File targetFile) {
743       file = targetFile;
744     } // ImportRunnable(File targetDirectory)
745 
746     public void run() {
747       if(file != null) {
748         MainFrame.lockGUI("Import file...");
749         try {
750           Factory.newDocument(file.toURL());
751         } catch (MalformedURLException mex) {
752           mex.printStackTrace();
753         } catch (ResourceInstantiationException rex) {
754           rex.printStackTrace();
755         } finally {
756           MainFrame.unlockGUI();
757         } // finally
758       } // if
759     } // run()
760   } // ImportRunnable
761 
762   /** Export current document action */
763   class ExportDocumentInlineAction extends AbstractAction {
764     public ExportDocumentInlineAction() {
765       super("with inline markup");
766       putValue(SHORT_DESCRIPTION, "Save the selected document in XML format"
767             +" with inline markup");
768     } // ExportDocumentInlineAction()
769 
770     public void actionPerformed(ActionEvent e) {
771       JComponent resource = (JComponent)
772                                   mainTabbedPane.getSelectedComponent();
773       if (resource == null) return;
774       Component c;
775       Document doc = null;
776 
777       for(int i=0; i<resource.getComponentCount(); ++i) {
778         c = resource.getComponent(i);
779         if(c instanceof DocumentEditor) {
780           doc = ((DocumentEditor) c).getDocument();
781         } // if
782       } // for
783 
784       if(doc != null) {
785         JFileChooser fileChooser = MainFrame.getFileChooser();
786         File selectedFile = null;
787 
788         fileChooser.setMultiSelectionEnabled(false);
789         fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
790         fileChooser.setDialogTitle("Select document to save ...");
791         fileChooser.setSelectedFiles(null);
792 
793         int res = fileChooser.showDialog(ShellSlacFrame.this, "Save");
794         if(res == JFileChooser.APPROVE_OPTION){
795           selectedFile = fileChooser.getSelectedFile();
796           fileChooser.setCurrentDirectory(fileChooser.getCurrentDirectory());
797 
798           // store document with annotations Document.toXML()
799           Runnable run = new ExportInline(doc, selectedFile);
800           Thread thread = new Thread(run, "");
801           thread.setPriority(Thread.MIN_PRIORITY);
802           thread.start();
803         } // if
804       }// End if
805     } // actionPerformed(ActionEvent e)
806   } // class ExportDocumentInlineAction extends AbstractAction
807 
808   /** New thread object for export inline */
809   private class ExportInline implements Runnable {
810     File targetFile;
811     Document document;
812 
813     ExportInline(Document doc, File target) {
814       targetFile = target;
815       document = doc;
816     } // ExportAllRunnable(File targetDirectory)
817 
818     protected Set getTypes(String types) {
819       Set set = new HashSet();
820       StringTokenizer tokenizer = new StringTokenizer(types, ";");
821 
822       while(tokenizer.hasMoreTokens()) {
823         set.add(tokenizer.nextToken());
824       } // while
825       
826       return set;
827     }
828     
829     public void run() {
830       if(document == null || targetFile == null) return;
831       MainFrame.lockGUI("Store document with inline markup...");
832       try{
833         AnnotationSet annotationsToDump = null;
834         annotationsToDump = document.getAnnotations();
835         // check for restriction from Java property
836         String enumaratedAnnTypes =
837           System.getProperty(GateConstants.ANNOT_TYPE_TO_EXPORT);
838 
839         if(enumaratedAnnTypes != null) {
840           Set typesSet = getTypes(enumaratedAnnTypes);
841           annotationsToDump = annotationsToDump.get(typesSet);
842         } // if
843         
844         // Prepare to write into the xmlFile using the original encoding
845         String encoding = ((gate.TextualDocument)document).getEncoding();
846         if(encoding == null || encoding.length() == 0)
847           encoding = System.getProperty("file.encoding");
848         if(encoding == null || encoding.length() == 0) encoding = "UTF-8";
849 
850         OutputStreamWriter writer = new OutputStreamWriter(
851                                       new FileOutputStream(targetFile),
852                                       encoding);
853 
854         //determine if the features need to be saved first
855         Boolean featuresSaved =
856             Gate.getUserConfig().getBoolean(
857               GateConstants.SAVE_FEATURES_WHEN_PRESERVING_FORMAT);
858         boolean saveFeatures = true;
859         if (featuresSaved != null)
860           saveFeatures = featuresSaved.booleanValue();
861 
862         // Write with the toXml() method
863         String toXml = document.toXml(annotationsToDump, saveFeatures);
864 
865         // check for plain text feature and add root XML tag <GATE>
866         String mimeType = (String) document.getFeatures().get("MimeType");
867         if("text/plain".equalsIgnoreCase(mimeType)) {
868           toXml = "<GATE>\n"+ toXml + "\n</GATE>";
869         } // if
870         
871         writer.write(toXml);
872         writer.flush();
873         writer.close();
874       } catch (Exception ex){
875         ex.printStackTrace(Out.getPrintWriter());
876       }// End try
877       
878       MainFrame.unlockGUI();
879     } // run()
880   } // ExportInline
881 
882   /** Export current document action */
883   class ExportDocumentAction extends AbstractAction {
884     public ExportDocumentAction() {
885       super("in GATE format");
886       putValue(SHORT_DESCRIPTION, "Save the selected document in XML format");
887     } // ExportDocumentAction()
888 
889     public void actionPerformed(ActionEvent e) {
890       JComponent resource = (JComponent)
891                                   mainTabbedPane.getSelectedComponent();
892       if (resource != null){
893         Action act = resource.getActionMap().get("Save As XML");
894         if (act != null)
895           act.actionPerformed(null);
896       }// End if
897     } // actionPerformed(ActionEvent e)
898   } // class ExportDocumentAction extends AbstractAction
899 
900   /** Export All menu action */
901   class ExportAllDocumentAction extends AbstractAction {
902     public ExportAllDocumentAction() {
903       super("in GATE format");
904       putValue(SHORT_DESCRIPTION, "Save all documents in XML format");
905     } // ExportAllDocumentAction()
906 
907     public void actionPerformed(ActionEvent e) {
908       fileChooser.setDialogTitle("Select Export directory");
909       fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
910 
911       int res = fileChooser.showOpenDialog(ShellSlacFrame.this);
912       if(res == fileChooser.APPROVE_OPTION) {
913         File directory = fileChooser.getSelectedFile();
914         if(directory != null && directory.isDirectory()) {
915           Runnable run = new ExportAllRunnable(directory);
916           Thread thread = new Thread(run, "");
917           thread.setPriority(Thread.MIN_PRIORITY);
918           thread.start();
919         } // if
920       } // if
921     } // actionPerformed(ActionEvent e)
922   } // class ExportAllDocumentAction extends AbstractAction
923 
924   /** Export All Inline menu action */
925   class ExportAllDocumentInlineAction extends AbstractAction {
926     public ExportAllDocumentInlineAction() {
927       super("with inline markup");
928       putValue(SHORT_DESCRIPTION, "Save all documents in XML format"
929             +" with inline markup");
930     } // ExportAllDocumentInlineAction()
931 
932     public void actionPerformed(ActionEvent e) {
933       fileChooser.setDialogTitle("Select Export directory");
934       fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
935 
936       int res = fileChooser.showOpenDialog(ShellSlacFrame.this);
937       if(res == fileChooser.APPROVE_OPTION) {
938         File directory = fileChooser.getSelectedFile();
939         if(directory != null && directory.isDirectory()) {
940           Document currentDoc;
941           String fileName;
942           URL fileURL;
943           Runnable run;
944           Thread thread;
945           
946           for(int i=0; i<corpus.size(); ++i) {
947             currentDoc = (Document) corpus.get(i);
948 
949             fileURL = currentDoc.getSourceUrl();
950             fileName = null;
951             if(fileURL != null){
952               fileName = fileURL.getFile();
953               fileName = Files.getLastPathComponent(fileName);
954             } // if
955             if(fileName == null || fileName.length() == 0){
956               fileName = currentDoc.getName();
957             } // if
958             if(fileName.length() == 0) {
959               fileName = "gate_result"+i;
960             } // if      
961             // create full file name
962             fileName = fileName+".gate";
963             
964             // run export
965             run = new ExportInline(currentDoc, new File(directory, fileName));
966             thread = new Thread(run, "");
967             thread.setPriority(Thread.MIN_PRIORITY);
968             thread.start();
969           } // for
970         } // if
971       } // if
972     } // actionPerformed(ActionEvent e)
973   } // class ExportAllDocumentInlineAction extends AbstractAction
974 
975   /** Object to run ExportAll in a new Thread */
976   private class ExportAllRunnable implements Runnable {
977     File directory;
978     ExportAllRunnable(File targetDirectory) {
979       directory = targetDirectory;
980     } // ExportAllRunnable(File targetDirectory)
981 
982     public void run() {
983       saveDocuments(directory);
984     } // run()
985   } // ExportAllRunnable
986 
987   /** Load application from file */
988   private class ApplicationLoadRun implements Runnable {
989     private String appURL;
990     private MainFrame appFrame;
991     public ApplicationLoadRun(String url, MainFrame frame) {
992       appURL = url;
993       appFrame = frame;
994     }
995 
996     public void run(){
997       File file = new File(appURL);
998       boolean appLoaded = false;
999 
1000      appFrame.lockGUI("Application from '"+appURL+"' is being loaded...");
1001      if( file.exists() ) {
1002        try {
1003          gate.util.persistence.PersistenceManager.loadObjectFromFile(file);
1004          appLoaded = true;
1005        } catch (PersistenceException pex) {
1006          pex.printStackTrace();
1007        } catch (ResourceInstantiationException riex) {
1008          riex.printStackTrace();
1009        } catch (IOException ioex) {
1010          ioex.printStackTrace();
1011        } // catch
1012      } // if
1013      appFrame.unlockGUI();
1014
1015      if(!appLoaded) {
1016        // file do not exist. Show a message
1017        JOptionPane.showMessageDialog(ShellSlacFrame.this,
1018            "The application file '"+appURL+"'\n"
1019            +"from parameter -Dgate.slug.app\n"
1020            +"is missing or corrupted."
1021            +"Create default application.",
1022            "Load application error",
1023            JOptionPane.WARNING_MESSAGE);
1024
1025        createDefaultApplication();
1026      } // if
1027    } // run
1028  } // class ApplicationLoadRun implements Runnable
1029
1030  /** Create default ANNIE */
1031  public class ANNIERunnable implements Runnable {
1032    MainFrame parentFrame;
1033    ANNIERunnable(MainFrame parent) {
1034      parentFrame = parent;
1035    }
1036
1037    public void run(){
1038      AbstractAction action = new LoadANNIEWithDefaultsAction();
1039      action.actionPerformed(new ActionEvent(parentFrame, 1, "Load ANNIE"));
1040    }
1041  } // ANNIERunnable
1042
1043  class AboutPaneDialog extends JDialog {
1044    public AboutPaneDialog(Frame frame, String title, boolean modal) {
1045      super(frame, title, modal);
1046    } // AboutPaneDialog
1047
1048    public boolean setURL(URL url) {
1049      boolean success = false;
1050      // try to show in JEditorPane
1051      try {
1052        Container pane = getContentPane();
1053
1054        JScrollPane scroll = new JScrollPane();
1055        JEditorPane editor = new JEditorPane(url);
1056        editor.setEditable(false);
1057        scroll.getViewport().add(editor);
1058        pane.add(scroll, BorderLayout.CENTER);
1059
1060        JButton ok = new JButton("Close");
1061        ok.addActionListener( new ActionListener() {
1062          public void actionPerformed(ActionEvent e) {
1063            AboutPaneDialog.this.hide();
1064          }
1065        });
1066        pane.add(ok, BorderLayout.SOUTH);
1067        success = true;
1068      } catch (Exception ex) {
1069        if(DEBUG) {
1070          ex.printStackTrace();
1071        }
1072      } // catch
1073      return success;
1074    } // setURL
1075  } // class AboutPaneDialog
1076
1077  /** Dummy Help About dialog */
1078  class HelpAboutSlugAction extends AbstractAction {
1079    public HelpAboutSlugAction() {
1080      super("About");
1081    } // HelpAboutSlugAction()
1082
1083    public void actionPerformed(ActionEvent e) {
1084
1085      // Set about box content from Java properties
1086      String aboutText = "Slug application.";
1087      String aboutURL =
1088        System.getProperty(GateConstants.ABOUT_URL_JAVA_PROPERTY_NAME);
1089
1090      boolean canShowInPane = false;
1091
1092      if(aboutURL != null) {
1093        try {
1094          URL url = new URL(aboutURL);
1095
1096          AboutPaneDialog dlg =
1097            new AboutPaneDialog(ShellSlacFrame.this,
1098                                "Slug application about", true);
1099          canShowInPane = dlg.setURL(url);
1100          if(canShowInPane) {
1101            dlg.setSize(300, 200);
1102            dlg.setLocationRelativeTo(ShellSlacFrame.this);
1103            dlg.show();
1104          } // if
1105          else {
1106            BufferedReader reader = new BufferedReader(
1107              new InputStreamReader(url.openStream()));
1108            String line = "";
1109            StringBuffer content = new StringBuffer();
1110            do {
1111              content.append(line);
1112              line = reader.readLine();
1113            } while (line != null);
1114
1115            if(content.length() != 0) {
1116              aboutText = content.toString();
1117            } // if
1118          } // if
1119
1120        } catch (Exception ex) {
1121          // do nothing on exception
1122          // application just stay with a dummy text in about box
1123          if(DEBUG) {
1124            ex.printStackTrace();
1125          }
1126        } // catch
1127      } // if
1128
1129
1130      if(!canShowInPane) JOptionPane.showMessageDialog(ShellSlacFrame.this,
1131          aboutText,
1132          "Slug application about",
1133          JOptionPane.INFORMATION_MESSAGE);
1134    } // actionPerformed(ActionEvent e)
1135  } // class HelpAboutSlugAction extends AbstractAction
1136
1137  
1138  /**
1139   * Component used to select the options for corpus populating
1140   */
1141  CorpusFillerComponent corpusFiller;
1142
1143  class PopulateCorpusAction extends AbstractAction {
1144    PopulateCorpusAction() {
1145      super("New Documents...");
1146    } // PopulateCorpusAction()
1147
1148    public void actionPerformed(ActionEvent e) {
1149      Runnable runnable = new Runnable(){
1150        public void run(){
1151          if(corpus == null || corpusFiller == null) return;
1152          corpusFiller.setExtensions(new ArrayList());
1153          corpusFiller.setEncoding("");
1154          boolean answer = OkCancelDialog.showDialog(
1155                                  ShellSlacFrame.this,
1156                                  corpusFiller,
1157                                  "Select a directory and allowed extensions");
1158          if(answer){
1159            URL url = null;
1160            try{
1161              url = new URL(corpusFiller.getUrlString());
1162              java.util.List extensions = corpusFiller.getExtensions();
1163              ExtensionFileFilter filter = null;
1164              if(extensions == null || extensions.isEmpty()) filter = null;
1165              else{
1166                filter = new ExtensionFileFilter();
1167                Iterator extIter = corpusFiller.getExtensions().iterator();
1168                while(extIter.hasNext()){
1169                  filter.addExtension((String)extIter.next());
1170                }
1171              }
1172              corpus.populate(url, filter,
1173                                corpusFiller.getEncoding(),
1174                                corpusFiller.isRecurseDirectories());
1175            }catch(MalformedURLException mue){
1176              JOptionPane.showMessageDialog(ShellSlacFrame.this,
1177                                            "Invalid URL!\n " +
1178                                            "See \"Messages\" tab for details!",
1179                                            "Gate", JOptionPane.ERROR_MESSAGE);
1180              mue.printStackTrace(Err.getPrintWriter());
1181            }catch(IOException ioe){
1182              JOptionPane.showMessageDialog(ShellSlacFrame.this,
1183                                            "I/O error!\n " +
1184                                            "See \"Messages\" tab for details!",
1185                                            "Gate", JOptionPane.ERROR_MESSAGE);
1186              ioe.printStackTrace(Err.getPrintWriter());
1187            }catch(ResourceInstantiationException rie){
1188              JOptionPane.showMessageDialog(ShellSlacFrame.this,
1189                                            "Could not create document!\n " +
1190                                            "See \"Messages\" tab for details!",
1191                                            "Gate", JOptionPane.ERROR_MESSAGE);
1192              rie.printStackTrace(Err.getPrintWriter());
1193            }
1194          }
1195        }
1196      };
1197      Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
1198                                 runnable);
1199      thread.setPriority(Thread.MIN_PRIORITY);
1200      thread.start();
1201    } // actionPerformed(ActionEvent e)
1202  } // class PopulateCorpusAction extends AbstractAction
1203  
1204} // class ShellSlacFrame
1205