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