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    *  Valentin Tablan 23/01/2001
10   *
11   *  $Id: NameBearerHandle.java,v 1.62 2002/07/11 12:55:03 nasso Exp $
12   *
13   */
14  
15  package gate.gui;
16  
17  import javax.swing.*;
18  import java.util.*;
19  import java.net.*;
20  import java.awt.Component;
21  import java.awt.Window;
22  import java.awt.Frame;
23  import java.awt.Dialog;
24  import java.awt.event.*;
25  import java.text.NumberFormat;
26  import java.io.*;
27  import javax.swing.filechooser.FileFilter;
28  
29  import gate.*;
30  import gate.util.*;
31  import gate.swing.*;
32  import gate.creole.*;
33  import gate.creole.ir.*;
34  import gate.persist.*;
35  import gate.event.*;
36  import gate.security.*;
37  import gate.security.SecurityException;
38  
39  /**
40   * Class used to store the GUI information about an open entity (resource,
41   * controller, datastore).
42   * Such information will include icon to be used for tree components,
43   * popup menu for right click events, large and small views, etc.
44   */
45  public class NameBearerHandle implements Handle,
46                                           StatusListener,
47                                           ProgressListener, CreoleListener {
48  
49    public NameBearerHandle(NameBearer target, Window window) {
50      this.target = target;
51      this.window = window;
52      sListenerProxy = new ProxyStatusListener();
53      String iconName = null;
54      if(target instanceof Resource){
55        rData = (ResourceData)Gate.getCreoleRegister().
56                                                get(target.getClass().getName());
57        if(rData != null){
58          iconName = rData.getIcon();
59          if(iconName == null){
60            if(target instanceof LanguageResource) iconName = "lr.gif";
61            else if(target instanceof ProcessingResource) iconName = "pr.gif";
62            else if(target instanceof Controller) iconName = "controller.gif";
63          }
64          tooltipText = "<HTML> <b>" + rData.getComment() + "</b><br>(<i>" +
65                        rData.getClassName() + "</i>)</HTML>";
66        } else {
67          this.icon = MainFrame.getIcon("lr.gif");
68        }
69      }else if(target instanceof DataStore){
70        iconName = ((DataStore)target).getIconName();
71        tooltipText = ((DataStore)target).getComment();
72      }
73  
74      popup = null;
75      title = (String)target.getName();
76      this.icon = MainFrame.getIcon(iconName);
77  
78      Gate.getCreoleRegister().addCreoleListener(this);
79      buildViews();
80      // Add the CTRL +F4 key & action combination to the resource
81      JComponent largeView = this.getLargeView();
82      if (largeView != null){
83        largeView.getActionMap().put("Close resource",
84                          new CloseAction());
85        if (target instanceof gate.TextualDocument){
86          largeView.getActionMap().put("Save As XML", new SaveAsXmlAction());
87        }// End if
88      }// End if
89    }//public DefaultResourceHandle(FeatureBearer res)
90  
91    public Icon getIcon(){
92      return icon;
93    }
94  
95    public void setIcon(Icon icon){
96      this.icon = icon;
97    }
98  
99    public String getTitle(){
100     return title;
101   }
102 
103   public void setTitle(String newTitle){
104     this.title = newTitle;
105   }
106 
107   /**
108    * Returns a GUI component to be used as a small viewer/editor, e.g. below
109    * the main tree in the Gate GUI for the selected resource
110    */
111   public JComponent getSmallView() {
112     return smallView;
113   }
114 
115   /**
116    * Returns the large view for this resource. This view will go into the main
117    * display area.
118    */
119   public JComponent getLargeView() {
120     return largeView;
121   }
122 
123   public JPopupMenu getPopup() {
124     return popup;
125   }
126 
127   public void setPopup(JPopupMenu popup) {
128     this.popup = popup;
129   }
130 
131   public String getTooltipText() {
132     return tooltipText;
133   }
134 
135   public void setTooltipText(String text) {
136     this.tooltipText = text;
137   }
138 
139   public Object getTarget() {
140     return target;
141   }
142 
143   public Action getCloseAction(){
144     return new CloseAction();
145   }
146 
147   /** Fill Protege save, save as and save in format actions */
148   private void fillProtegeActions(JPopupMenu popup) {
149     Action action;
150 
151     popup.addSeparator();
152 
153     action = new edu.stanford.smi.protege.action.SaveProject();
154     action.putValue(action.NAME, "Save Protege");
155     action.putValue(action.SHORT_DESCRIPTION, "Save protege project");
156     // Add Save Protege action
157     popup.add(action);
158 
159     action = new edu.stanford.smi.protege.action.SaveAsProject();
160     action.putValue(action.NAME, "Save Protege As...");
161     action.putValue(action.SHORT_DESCRIPTION, "Save protege project as");
162     // Add Save as... Protege action
163     popup.add(action);
164 
165     action = new edu.stanford.smi.protege.action.ChangeProjectStorageFormat();
166     // Add Save in format... Protege action
167     popup.add(action);
168 
169     popup.addSeparator();
170     action = new edu.stanford.smi.protege.action.BuildProject();
171     // Add Import... Protege action
172     popup.add(action);
173   } // fillProtegeActions(gate.gui.ProtegeWrapper protege)
174 
175   /** Fill HMM Save and Save As... actions */
176   private void fillHMMActions(JPopupMenu popup) {
177     Action action;
178 
179     com.ontotext.gate.hmm.agent.AlternativeHMMAgent hmmPR =
180       (com.ontotext.gate.hmm.agent.AlternativeHMMAgent) target;
181 
182     popup.addSeparator();
183     action = new com.ontotext.gate.hmm.agent.SaveAction(hmmPR);
184     action.putValue(action.SHORT_DESCRIPTION,
185       "Save trained HMM model into PR URL file");
186     // Add Save trained HMM model action
187     popup.add(action);
188 
189     action = new com.ontotext.gate.hmm.agent.SaveAsAction(hmmPR);
190     action.putValue(action.SHORT_DESCRIPTION,
191       "Save trained HMM model into new file");
192     // Add Save As... trained HMM model action
193     popup.add(action);
194   } // fillHMMActions(gate.gui.ProtegeWrapper protege)
195 
196 
197   protected void buildViews() {
198     //build the popup
199     popup = new JPopupMenu();
200     XJMenuItem closeItem = new XJMenuItem(new CloseAction(), sListenerProxy);
201     closeItem.setAccelerator(KeyStroke.getKeyStroke(
202                                 KeyEvent.VK_F4, ActionEvent.CTRL_MASK));
203     popup.add(closeItem);
204 
205     if(target instanceof ProcessingResource){
206       popup.addSeparator();
207       popup.add(new XJMenuItem(new ReloadAction(), sListenerProxy));
208       if(target instanceof gate.ml.DataCollector){
209         popup.add(new DumpArffAction());
210       }
211       if(target instanceof com.ontotext.gate.hmm.agent.AlternativeHMMAgent) {
212         fillHMMActions(popup);
213       } // if
214     }else if(target instanceof LanguageResource) {
215       //Language Resources
216       popup.addSeparator();
217       popup.add(new XJMenuItem(new SaveAction(), sListenerProxy));
218       popup.add(new XJMenuItem(new SaveToAction(), sListenerProxy));
219       if(target instanceof gate.TextualDocument){
220         XJMenuItem saveAsXmlItem =
221                          new XJMenuItem(new SaveAsXmlAction(), sListenerProxy);
222         saveAsXmlItem.setAccelerator(KeyStroke.getKeyStroke(
223                                         KeyEvent.VK_X, ActionEvent.CTRL_MASK));
224 
225         popup.add(saveAsXmlItem);
226         XJMenuItem savePreserveFormatItem =
227                          new XJMenuItem(new DumpPreserveFormatAction(),
228                                         sListenerProxy);
229         popup.add(savePreserveFormatItem);
230       }else if(target instanceof Corpus){
231         popup.addSeparator();
232         corpusFiller = new CorpusFillerComponent();
233         popup.add(new XJMenuItem(new PopulateCorpusAction(), sListenerProxy));
234         popup.addSeparator();
235         popup.add(new XJMenuItem(new SaveCorpusAsXmlAction(false), sListenerProxy));
236         popup.add(new XJMenuItem(new SaveCorpusAsXmlAction(true), sListenerProxy));
237         if (target instanceof IndexedCorpus){
238           popup.addSeparator();
239           popup.add(new XJMenuItem(new CreateIndexAction(), sListenerProxy));
240           popup.add(new XJMenuItem(new OptimizeIndexAction(), sListenerProxy));
241           popup.add(new XJMenuItem(new DeleteIndexAction(), sListenerProxy));
242         }
243       }
244       if (target instanceof gate.creole.ProtegeProjectName){
245         fillProtegeActions(popup);
246       }// End if
247     }else if(target instanceof Controller){
248       //Applications
249       popup.addSeparator();
250       popup.add(new XJMenuItem(new DumpToFileAction(), sListenerProxy));
251     }
252 
253     fireStatusChanged("Building views...");
254 
255     //build the large views
256     List largeViewNames = Gate.getCreoleRegister().
257                           getLargeVRsForResource(target.getClass().getName());
258     if(largeViewNames != null && !largeViewNames.isEmpty()){
259       largeView = new JTabbedPane(JTabbedPane.BOTTOM);
260       Iterator classNameIter = largeViewNames.iterator();
261       while(classNameIter.hasNext()){
262         try{
263           String className = (String)classNameIter.next();
264           ResourceData rData = (ResourceData)Gate.getCreoleRegister().
265                                                   get(className);
266           FeatureMap params = Factory.newFeatureMap();
267           FeatureMap features = Factory.newFeatureMap();
268           Gate.setHiddenAttribute(features, true);
269           VisualResource view = (VisualResource)
270                                 Factory.createResource(className,
271                                                        params,
272                                                        features);
273           view.setTarget(target);
274           view.setHandle(this);
275           ((JTabbedPane)largeView).add((Component)view, rData.getName());
276         }catch(ResourceInstantiationException rie){
277           rie.printStackTrace(Err.getPrintWriter());
278         }
279       }
280       if(largeViewNames.size() == 1){
281         largeView = (JComponent)((JTabbedPane)largeView).getComponentAt(0);
282       }else{
283         ((JTabbedPane)largeView).setSelectedIndex(0);
284       }
285     }
286 
287     //build the small views
288     List smallViewNames = Gate.getCreoleRegister().
289                           getSmallVRsForResource(target.getClass().getName());
290     if(smallViewNames != null && !smallViewNames.isEmpty()){
291       smallView = new JTabbedPane(JTabbedPane.BOTTOM);
292       Iterator classNameIter = smallViewNames.iterator();
293       while(classNameIter.hasNext()){
294         try{
295           String className = (String)classNameIter.next();
296           ResourceData rData = (ResourceData)Gate.getCreoleRegister().
297                                                   get(className);
298           FeatureMap params = Factory.newFeatureMap();
299           FeatureMap features = Factory.newFeatureMap();
300           Gate.setHiddenAttribute(features, true);
301           VisualResource view = (VisualResource)
302                                 Factory.createResource(className,
303                                                        params,
304                                                        features);
305           view.setTarget(target);
306           view.setHandle(this);
307           ((JTabbedPane)smallView).add((Component)view, rData.getName());
308         }catch(ResourceInstantiationException rie){
309           rie.printStackTrace(Err.getPrintWriter());
310         }
311       }
312       if(smallViewNames.size() == 1){
313         smallView = (JComponent)((JTabbedPane)smallView).getComponentAt(0);
314       }else{
315         ((JTabbedPane)smallView).setSelectedIndex(0);
316       }
317     }
318     fireStatusChanged("Views built!");
319   }//protected void buildViews
320 
321   public String toString(){ return title;}
322 
323   public synchronized void removeProgressListener(ProgressListener l) {
324     if (progressListeners != null && progressListeners.contains(l)) {
325       Vector v = (Vector) progressListeners.clone();
326       v.removeElement(l);
327       progressListeners = v;
328     }
329   }//public synchronized void removeProgressListener(ProgressListener l)
330 
331   public synchronized void addProgressListener(ProgressListener l) {
332     Vector v = progressListeners == null ? new Vector(2) : (Vector) progressListeners.clone();
333     if (!v.contains(l)) {
334       v.addElement(l);
335       progressListeners = v;
336     }
337   }//public synchronized void addProgressListener(ProgressListener l)
338 
339   JPopupMenu popup;
340   String title;
341   String tooltipText;
342   NameBearer target;
343   /**
344    * The top level GUI component this hadle belongs to.
345    */
346   Window window;
347   ResourceData rData;
348   Icon icon;
349   JComponent smallView;
350   JComponent largeView;
351 
352   /**
353    * Component used to select the options for corpus populating
354    */
355   CorpusFillerComponent corpusFiller;
356 
357   StatusListener sListenerProxy;
358 
359 //  File currentDir = null;
360   private transient Vector progressListeners;
361   private transient Vector statusListeners;
362 
363   class CloseAction extends AbstractAction {
364     public CloseAction() {
365       super("Close");
366       putValue(SHORT_DESCRIPTION, "Removes this resource from the system");
367     }
368 
369     public void actionPerformed(ActionEvent e){
370       if(target instanceof Resource){
371         Factory.deleteResource((Resource)target);
372       }else if(target instanceof DataStore){
373         try{
374           ((DataStore)target).close();
375         } catch(PersistenceException pe){
376           JOptionPane.showMessageDialog(largeView != null ?
377                                                      largeView : smallView,
378                                         "Error!\n" + pe.toString(),
379                                         "Gate", JOptionPane.ERROR_MESSAGE);
380         }
381       }
382 
383       statusListeners.clear();
384       progressListeners.clear();
385 //      //delete the viewers
386 //      if(largeView instanceof VisualResource){
387 //        Factory.deleteResource((VisualResource)largeView);
388 //      }else if(largeView instanceof JTabbedPane){
389 //        Component[] comps = ((JTabbedPane)largeView).getComponents();
390 //        for(int i = 0; i < comps.length; i++){
391 //          if(comps[i] instanceof VisualResource)
392 //            Factory.deleteResource((VisualResource)comps[i]);
393 //        }
394 //      }
395 //      if(smallView instanceof VisualResource){
396 //        Factory.deleteResource((VisualResource)smallView);
397 //      }else if(smallView instanceof JTabbedPane){
398 //        Component[] comps = ((JTabbedPane)smallView).getComponents();
399 //        for(int i = 0; i < comps.length; i++){
400 //          if(comps[i] instanceof VisualResource)
401 //            Factory.deleteResource((VisualResource)comps[i]);
402 //        }
403 //      }
404 //
405     }//public void actionPerformed(ActionEvent e)
406   }//class CloseAction
407 
408   /**
409    * Used to save a document as XML
410    */
411   class SaveAsXmlAction extends AbstractAction {
412     public SaveAsXmlAction(){
413       super("Save As Xml...");
414       putValue(SHORT_DESCRIPTION, "Saves this resource in XML");
415     }// SaveAsXmlAction()
416 
417     public void actionPerformed(ActionEvent e) {
418       Runnable runableAction = new Runnable(){
419         public void run(){
420           JFileChooser fileChooser = MainFrame.getFileChooser();
421           File selectedFile = null;
422 
423           List filters = Arrays.asList(fileChooser.getChoosableFileFilters());
424           Iterator filtersIter = filters.iterator();
425           FileFilter filter = null;
426           if(filtersIter.hasNext()){
427             filter = (FileFilter)filtersIter.next();
428             while(filtersIter.hasNext() &&
429                   filter.getDescription().indexOf("XML") == -1){
430               filter = (FileFilter)filtersIter.next();
431             }
432           }
433           if(filter == null || filter.getDescription().indexOf("XML") == -1){
434             //no suitable filter found, create a new one
435             ExtensionFileFilter xmlFilter = new ExtensionFileFilter();
436             xmlFilter.setDescription("XML files");
437             xmlFilter.addExtension("xml");
438             xmlFilter.addExtension("gml");
439             fileChooser.addChoosableFileFilter(xmlFilter);
440             filter = xmlFilter;
441           }
442           fileChooser.setFileFilter(filter);
443 
444           fileChooser.setMultiSelectionEnabled(false);
445           fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
446           fileChooser.setDialogTitle("Select document to save ...");
447           fileChooser.setSelectedFiles(null);
448 
449           int res = (getLargeView() != null) ?
450                                   fileChooser.showDialog(getLargeView(), "Save"):
451                     (getSmallView() != null) ?
452                                   fileChooser.showDialog(getSmallView(), "Save") :
453                                               fileChooser.showDialog(null, "Save");
454           if(res == JFileChooser.APPROVE_OPTION){
455             selectedFile = fileChooser.getSelectedFile();
456             File currentDir = fileChooser.getCurrentDirectory();
457             if(selectedFile == null) return;
458             long start = System.currentTimeMillis();
459             NameBearerHandle.this.statusChanged("Saving as XML to " +
460              selectedFile.toString() + "...");
461             try{
462               MainFrame.lockGUI("Saving...");
463               // Prepare to write into the xmlFile using the original encoding
464               String encoding = ((gate.TextualDocument)target).getEncoding();
465               if(encoding == null || encoding.length() == 0)
466                 encoding = System.getProperty("file.encoding");
467               if(encoding == null || encoding.length() == 0) encoding = "UTF-8";
468 
469               OutputStreamWriter writer = new OutputStreamWriter(
470                                             new FileOutputStream(selectedFile),
471                                             encoding);
472 
473               // Write (test the toXml() method)
474               // This Action is added only when a gate.Document is created.
475               // So, is for sure that the resource is a gate.Document
476               writer.write(((gate.Document)target).toXml());
477               writer.flush();
478               writer.close();
479             } catch (Exception ex){
480               ex.printStackTrace(Out.getPrintWriter());
481             }finally{
482               MainFrame.unlockGUI();
483             }
484             long time = System.currentTimeMillis() - start;
485             NameBearerHandle.this.statusChanged("Finished saving as xml into "+
486              " the file: " + selectedFile.toString() +
487              " in " + ((double)time) / 1000 + " s");
488           }// End if
489         }// End run()
490       };// End Runnable
491       Thread thread = new Thread(runableAction, "");
492       thread.setPriority(Thread.MIN_PRIORITY);
493       thread.start();
494     }// actionPerformed()
495   }// SaveAsXmlAction
496 
497   /**
498    * The action that is fired when the user wants to dump annotations
499    * preserving the original document format.
500    */
501   protected class DumpPreserveFormatAction extends AbstractAction{
502 //    private Set annotationsToDump = null;
503 
504     public DumpPreserveFormatAction(){
505       super("Save preserving document format");
506     }
507 
508 
509     /** This method takes care of how the dumping is done*/
510     public void actionPerformed(ActionEvent e){
511       Runnable runableAction = new Runnable(){
512         public void run(){
513           JFileChooser fileChooser = MainFrame.getFileChooser();
514           File selectedFile = null;
515 
516           fileChooser.setMultiSelectionEnabled(false);
517           fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
518           fileChooser.setDialogTitle("Select document to save ...");
519           fileChooser.setSelectedFiles(null);
520 
521           int res = (getLargeView() != null) ?
522                                   fileChooser.showDialog(getLargeView(), "Save"):
523                     (getSmallView() != null) ?
524                                   fileChooser.showDialog(getSmallView(), "Save") :
525                                               fileChooser.showDialog(null, "Save");
526           if(res == JFileChooser.APPROVE_OPTION){
527             selectedFile = fileChooser.getSelectedFile();
528             fileChooser.setCurrentDirectory(fileChooser.getCurrentDirectory());
529             if(selectedFile == null) return;
530             if (NameBearerHandle.this!= null)
531               NameBearerHandle.this.statusChanged("Please wait while dumping annotations"+
532               "in the original format to " + selectedFile.toString() + " ...");
533             // This method construct a set with all annotations that need to be
534             // dupmped as Xml. If the set is null then only the original markups
535             // are dumped.
536             Set annotationsToDump = null;
537             //find the shown document editor. If none, just dump the original
538             //markup annotations, i.e., leave the annotationsToDump null
539             if (largeView instanceof JTabbedPane) {
540               Component shownComponent =
541                 ((JTabbedPane) largeView).getSelectedComponent();
542               if (shownComponent instanceof DocumentEditor) {
543                 //so we only get annotations for dumping if they are shown in the
544                 //table of the document editor, which is currently in front
545                 //of the user
546                 annotationsToDump =
547                   ((DocumentEditor) shownComponent).getDisplayedAnnotations();
548               }//if we have a document editor
549             }//if tabbed pane
550             try{
551               // Prepare to write into the xmlFile using the original encoding
552               String encoding = ((gate.TextualDocument)target).getEncoding();
553               if(encoding == null || encoding.length() == 0)
554                 encoding = System.getProperty("file.encoding");
555               if(encoding == null || encoding.length() == 0) encoding = "UTF-8";
556 
557               OutputStreamWriter writer = new OutputStreamWriter(
558                                             new FileOutputStream(selectedFile),
559                                             encoding);
560 
561               //determine if the features need to be saved first
562               Boolean featuresSaved =
563                   Gate.getUserConfig().getBoolean(
564                     GateConstants.SAVE_FEATURES_WHEN_PRESERVING_FORMAT);
565               boolean saveFeatures = true;
566               if (featuresSaved != null)
567                 saveFeatures = featuresSaved.booleanValue();
568               // Write with the toXml() method
569               writer.write(
570                 ((gate.Document)target).toXml(annotationsToDump, saveFeatures));
571               writer.flush();
572               writer.close();
573             } catch (Exception ex){
574               ex.printStackTrace(Out.getPrintWriter());
575             }// End try
576             if (NameBearerHandle.this!= null)
577               NameBearerHandle.this.statusChanged("Finished dumping into the "+
578               "file : " + selectedFile.toString());
579           }// End if
580         }// End run()
581       };// End Runnable
582       Thread thread = new Thread(runableAction, "");
583       thread.setPriority(Thread.MIN_PRIORITY);
584       thread.start();
585     }//public void actionPerformed(ActionEvent e)
586 
587   }//class DumpPreserveFormatAction
588 
589 
590   /**
591    * Saves a corpus as a set of xml files in a directory.
592    */
593   class SaveCorpusAsXmlAction extends AbstractAction {
594     private boolean preserveFormat;
595     public SaveCorpusAsXmlAction(boolean preserveFormat){
596       super("Save As Xml...");
597       putValue(SHORT_DESCRIPTION, "Saves this corpus in XML");
598       this.preserveFormat = preserveFormat;
599 
600       if(preserveFormat) {
601         putValue(NAME, "Save As Xml preserve format...");
602         putValue(SHORT_DESCRIPTION, "Saves this corpus in XML preserve format");
603       } // if
604     }// SaveAsXmlAction()
605 
606     public void actionPerformed(ActionEvent e) {
607       Runnable runnable = new Runnable(){
608         public void run(){
609           try{
610             //we need a directory
611             JFileChooser filer = MainFrame.getFileChooser();
612             filer.setDialogTitle(
613                 "Select the directory that will contain the corpus");
614             filer.setFileSelectionMode(filer.DIRECTORIES_ONLY);
615             filer.setFileFilter(filer.getAcceptAllFileFilter());
616 
617             if (filer.showDialog(getLargeView() != null ?
618                                      getLargeView() :
619                                      getSmallView(),
620                                      "Select") == filer.APPROVE_OPTION){
621 
622               File dir = filer.getSelectedFile();
623               //create the top directory if needed
624               if(!dir.exists()){
625                 if(!dir.mkdirs()){
626                   JOptionPane.showMessageDialog(
627                     largeView != null ?largeView : smallView,
628                     "Could not create top directory!",
629                     "Gate", JOptionPane.ERROR_MESSAGE);
630                   return;
631                 }
632               }
633 
634               MainFrame.lockGUI("Saving...");
635 
636               //iterate through all the docs and save each of them as xml
637               Corpus corpus = (Corpus)target;
638               Iterator docIter = corpus.iterator();
639               boolean overwriteAll = false;
640               int docCnt = corpus.size();
641               int currentDocIndex = 0;
642               while(docIter.hasNext()){
643                 boolean docWasLoaded = corpus.isDocumentLoaded(currentDocIndex);
644                 Document currentDoc = (Document)docIter.next();
645                 URL sourceURL = currentDoc.getSourceUrl();
646                 String fileName = null;
647                 if(sourceURL != null){
648                   fileName = sourceURL.getFile();
649                   fileName = Files.getLastPathComponent(fileName);
650                 }
651                 if(fileName == null || fileName.length() == 0){
652                   fileName = currentDoc.getName();
653                 }
654                 if(!fileName.toLowerCase().endsWith(".xml")) fileName += ".xml";
655                 File docFile = null;
656                 boolean nameOK = false;
657                 do{
658                   docFile = new File(dir, fileName);
659                   if(docFile.exists() && !overwriteAll){
660                     //ask the user if we can ovewrite the file
661                     Object[] options = new Object[] {"Yes", "All",
662                                                      "No", "Cancel"};
663                     MainFrame.unlockGUI();
664                     int answer = JOptionPane.showOptionDialog(
665                       largeView != null ? largeView : smallView,
666                       "File " + docFile.getName() + " already exists!\n" +
667                       "Overwrite?" ,
668                       "Gate", JOptionPane.DEFAULT_OPTION,
669                       JOptionPane.WARNING_MESSAGE, null, options, options[2]);
670                     MainFrame.lockGUI("Saving...");
671                     switch(answer){
672                       case 0: {
673                         nameOK = true;
674                         break;
675                       }
676                       case 1: {
677                         nameOK = true;
678                         overwriteAll = true;
679                         break;
680                       }
681                       case 2: {
682                         //user said NO, allow them to provide an alternative name;
683                         MainFrame.unlockGUI();
684                         fileName = (String)JOptionPane.showInputDialog(
685                             largeView != null ? largeView : smallView,
686                             "Please provide an alternative file name",
687                             "Gate", JOptionPane.QUESTION_MESSAGE,
688                             null, null, fileName);
689                         if(fileName == null){
690                           fireProcessFinished();
691                           return;
692                         }
693                         MainFrame.lockGUI("Saving");
694                         break;
695                       }
696                       case 3: {
697                         //user gave up; return
698                         fireProcessFinished();
699                         return;
700                       }
701                     }
702 
703                   }else{
704                     nameOK = true;
705                   }
706                 }while(!nameOK);
707                 //save the file
708                 try{
709                   String content = "";
710                   // check for preserve format flag
711                   if(preserveFormat) {
712                     Set annotationsToDump = null;
713                     // Find the shown document editor. 
714                     // If none, just dump the original markup annotations, 
715                     // i.e., leave the annotationsToDump null
716                     if (largeView instanceof JTabbedPane) {
717                       Component shownComponent =
718                         ((JTabbedPane) largeView).getSelectedComponent();
719                       if (shownComponent instanceof DocumentEditor) {
720                         // so we only get annotations for dumping 
721                         // if they are shown in the table of the document editor, 
722                         // which is currently in front of the user
723                         annotationsToDump =
724                           ((DocumentEditor) shownComponent).getDisplayedAnnotations();
725                       }//if we have a document editor
726                     }//if tabbed pane
727 
728                     //determine if the features need to be saved first
729                     Boolean featuresSaved =
730                         Gate.getUserConfig().getBoolean(
731                           GateConstants.SAVE_FEATURES_WHEN_PRESERVING_FORMAT);
732                     boolean saveFeatures = true;
733                     if (featuresSaved != null)
734                       saveFeatures = featuresSaved.booleanValue();
735             
736                     // Write with the toXml() method
737                     content = currentDoc.toXml(annotationsToDump, saveFeatures);
738                   }
739                   else {
740                     content = currentDoc.toXml();
741                   } // if
742 
743                   // Prepare to write into the xmlFile using the original encoding
744                   String encoding = ((gate.TextualDocument)currentDoc).getEncoding();
745                   if(encoding == null || encoding.length() == 0)
746                     encoding = System.getProperty("file.encoding");
747                   if(encoding == null || encoding.length() == 0) 
748                     encoding = "UTF-8";
749           
750                   OutputStreamWriter writer = new OutputStreamWriter(
751                                                 new FileOutputStream(docFile),
752                                                 encoding);
753 
754                   writer.write(content);
755                   writer.flush();
756                   writer.close();
757                 }catch(IOException ioe){
758                   MainFrame.unlockGUI();
759                   JOptionPane.showMessageDialog(
760                     largeView != null ? largeView : smallView,
761                     "Could not create write file:" +
762                     ioe.toString(),
763                     "Gate", JOptionPane.ERROR_MESSAGE);
764                   ioe.printStackTrace(Err.getPrintWriter());
765                   return;
766                 }
767 
768                 fireStatusChanged(currentDoc.getName() + " saved");
769                 //close the doc if it wasn't already loaded
770                 if(!docWasLoaded){
771                   corpus.unloadDocument(currentDoc);
772                   Factory.deleteResource(currentDoc);
773                 }
774 
775                 fireProgressChanged(100 * currentDocIndex++ / docCnt);
776               }//while(docIter.hasNext())
777               fireStatusChanged("Corpus saved");
778               fireProcessFinished();
779             }//select directory
780           }finally{
781             MainFrame.unlockGUI();
782           }
783         }//public void run(){
784       };//Runnable runnable = new Runnable()
785       Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
786                                  runnable, "Corpus XML dumper");
787       thread.setPriority(Thread.MIN_PRIORITY);
788       thread.start();
789 
790     }//public void actionPerformed(ActionEvent e)
791   }//class SaveCorpusAsXmlAction extends AbstractAction
792 
793   /**
794    * Saves a corpus as a set of xml files in a directory.
795    */
796   class ReloadClassAction extends AbstractAction {
797     public ReloadClassAction(){
798       super("Reload resource class");
799       putValue(SHORT_DESCRIPTION, "Reloads the java class for this resource");
800     }// SaveAsXmlAction()
801 
802     public void actionPerformed(ActionEvent e) {
803       int answer = JOptionPane.showOptionDialog(
804                 largeView != null ? largeView : smallView,
805                 "This is an advanced option!\n" +
806                 "You should not use this unless your name is Hamish.\n" +
807                 "Are you sure you want to do this?" ,
808                 "Gate", JOptionPane.YES_NO_OPTION,
809                 JOptionPane.WARNING_MESSAGE, null, null, null);
810       if(answer == JOptionPane.OK_OPTION){
811         try{
812           String className = target.getClass().getName();
813           Gate.getClassLoader().reloadClass(className);
814           fireStatusChanged("Class " + className + " reloaded!");
815         }catch(Exception ex){
816           JOptionPane.showMessageDialog(largeView != null ?
817                                         largeView : smallView,
818                                         "Look what you've done: \n" +
819                                         ex.toString() +
820                                         "\nI told you not to do it...",
821                                         "Gate", JOptionPane.ERROR_MESSAGE);
822           ex.printStackTrace(Err.getPrintWriter());
823         }
824       }
825     }
826   }
827 
828   class SaveAction extends AbstractAction {
829     public SaveAction(){
830       super("Save");
831       putValue(SHORT_DESCRIPTION, "Save back to the datastore");
832     }
833     public void actionPerformed(ActionEvent e){
834       Runnable runnable = new Runnable(){
835         public void run(){
836           DataStore ds = ((LanguageResource)target).getDataStore();
837           if(ds != null){
838             try {
839               MainFrame.lockGUI("Saving " + ((LanguageResource)target).getName());
840               StatusListener sListener = (StatusListener)
841                                          gate.gui.MainFrame.getListeners().
842                                          get("gate.event.StatusListener");
843               if(sListener != null) sListener.statusChanged(
844                 "Saving: " + ((LanguageResource)target).getName());
845               double timeBefore = System.currentTimeMillis();
846               ((LanguageResource)
847                         target).getDataStore().sync((LanguageResource)target);
848               double timeAfter = System.currentTimeMillis();
849               if(sListener != null) sListener.statusChanged(
850                 ((LanguageResource)target).getName() + " saved in " +
851                 NumberFormat.getInstance().format((timeAfter-timeBefore)/1000)
852                 + " seconds");
853             } catch(PersistenceException pe) {
854               MainFrame.unlockGUI();
855               JOptionPane.showMessageDialog(getLargeView(),
856                                             "Save failed!\n " +
857                                             pe.toString(),
858                                             "Gate", JOptionPane.ERROR_MESSAGE);
859             } catch(SecurityException se) {
860               MainFrame.unlockGUI();
861               JOptionPane.showMessageDialog(getLargeView(),
862                                             "Save failed!\n " +
863                                             se.toString(),
864                                             "Gate", JOptionPane.ERROR_MESSAGE);
865             }finally{
866               MainFrame.unlockGUI();
867             }
868           } else {
869             JOptionPane.showMessageDialog(getLargeView(),
870                             "This resource has not been loaded from a datastore.\n"+
871                              "Please use the \"Save to\" option!\n",
872                              "Gate", JOptionPane.ERROR_MESSAGE);
873 
874           }
875         }
876       };
877       new Thread(runnable).start();
878     }//public void actionPerformed(ActionEvent e)
879   }//class SaveAction
880 
881   class DumpArffAction extends AbstractAction{
882     public DumpArffAction(){
883       super("Write data as ARFF");
884       putValue(SHORT_DESCRIPTION,
885                "Saves the data needed to recreate this application");
886     }
887 
888     public void actionPerformed(ActionEvent evt){
889       JFileChooser fileChooser = MainFrame.getFileChooser();
890 
891       fileChooser.setDialogTitle("Select a file for ARFF dump");
892       fileChooser.setFileSelectionMode(fileChooser.FILES_AND_DIRECTORIES);
893       if (fileChooser.showSaveDialog(largeView) ==
894                                             fileChooser.APPROVE_OPTION){
895         final File file = fileChooser.getSelectedFile();
896         Thread thread = new Thread(new Runnable(){
897           public void run(){
898             fireStatusChanged("Writing ARFF output!");
899             gate.ml.DataCollector collector = (gate.ml.DataCollector)target;
900             try{
901                 FileWriter fw = new FileWriter(file);
902                 fw.write(collector.getDataSet().toString());
903                 fw.flush();
904                 fw.close();
905             }catch(IOException ioe){
906                 JOptionPane.showMessageDialog(getLargeView(),
907                                 "Error!\n"+
908                                  ioe.toString(),
909                                  "Gate", JOptionPane.ERROR_MESSAGE);
910                 ioe.printStackTrace(Err.getPrintWriter());
911 
912             }
913             fireStatusChanged("ARFF dump finished!");
914 
915           }
916         });
917         thread.setPriority(Thread.MIN_PRIORITY);
918         thread.start();
919       }
920     }
921   }//class DumpArffData extends AbstractAction{
922 
923   class DumpToFileAction extends AbstractAction {
924     public DumpToFileAction(){
925       super("Save application state");
926       putValue(SHORT_DESCRIPTION,
927                "Saves the data needed to recreate this application");
928     }
929 
930     public void actionPerformed(ActionEvent ae){
931       JFileChooser fileChooser = MainFrame.getFileChooser();
932 
933       fileChooser.setDialogTitle("Select a file for this resource");
934       fileChooser.setFileSelectionMode(fileChooser.FILES_AND_DIRECTORIES);
935       if (fileChooser.showSaveDialog(largeView) ==
936                                             fileChooser.APPROVE_OPTION){
937         final File file = fileChooser.getSelectedFile();
938           Runnable runnable = new Runnable(){
939             public void run(){
940               try{
941                 gate.util.persistence.PersistenceManager.
942                                       saveObjectToFile((Resource)target, file);
943               }catch(Exception e){
944                 JOptionPane.showMessageDialog(getLargeView(),
945                                 "Error!\n"+
946                                  e.toString(),
947                                  "Gate", JOptionPane.ERROR_MESSAGE);
948                 e.printStackTrace(Err.getPrintWriter());
949               }
950             }
951           };
952           Thread thread = new Thread(runnable);
953           thread.setPriority(Thread.MIN_PRIORITY);
954           thread.start();
955       }
956     }
957 
958   }
959 
960   class SaveToAction extends AbstractAction {
961     public SaveToAction(){
962       super("Save to...");
963       putValue(SHORT_DESCRIPTION, "Save this resource to a datastore");
964     }
965 
966     public void actionPerformed(ActionEvent e) {
967       Runnable runnable = new Runnable(){
968         public void run(){
969           try {
970             DataStoreRegister dsReg = Gate.getDataStoreRegister();
971             Map dsByName =new HashMap();
972             Iterator dsIter = dsReg.iterator();
973             while(dsIter.hasNext()){
974               DataStore oneDS = (DataStore)dsIter.next();
975               String name;
976               if((name = (String)oneDS.getName()) != null){
977               } else {
978                 name  = oneDS.getStorageUrl();
979                 try {
980                   URL tempURL = new URL(name);
981                   name = tempURL.getFile();
982                 } catch (java.net.MalformedURLException ex) {
983                   throw new GateRuntimeException(
984                             );
985                 }
986               }
987               dsByName.put(name, oneDS);
988             }
989             List dsNames = new ArrayList(dsByName.keySet());
990             if(dsNames.isEmpty()){
991               JOptionPane.showMessageDialog(getLargeView(),
992                                             "There are no open datastores!\n " +
993                                             "Please open a datastore first!",
994                                             "Gate", JOptionPane.ERROR_MESSAGE);
995 
996             } else {
997               Object answer = JOptionPane.showInputDialog(
998                                   getLargeView(),
999                                   "Select the datastore",
1000                                  "Gate", JOptionPane.QUESTION_MESSAGE,
1001                                  null, dsNames.toArray(),
1002                                  dsNames.get(0));
1003              if(answer == null) return;
1004              DataStore ds = (DataStore)dsByName.get(answer);
1005              if (ds == null){
1006                Err.prln("The datastore does not exists. Saving procedure" +
1007                                  " has FAILED! This should never happen again!");
1008                return;
1009              }// End if
1010              DataStore ownDS = ((LanguageResource)target).getDataStore();
1011              if(ds == ownDS){
1012                MainFrame.lockGUI("Saving " + ((LanguageResource)target).getName());
1013
1014                StatusListener sListener = (StatusListener)
1015                                           gate.gui.MainFrame.getListeners().
1016                                           get("gate.event.StatusListener");
1017                if(sListener != null) sListener.statusChanged(
1018                  "Saving: " + ((LanguageResource)target).getName());
1019                double timeBefore = System.currentTimeMillis();
1020                ds.sync((LanguageResource)target);
1021                double timeAfter = System.currentTimeMillis();
1022                if(sListener != null) sListener.statusChanged(
1023                  ((LanguageResource)target).getName() + " saved in " +
1024                  NumberFormat.getInstance().format((timeAfter-timeBefore)/1000)
1025                  + " seconds");
1026              }else{
1027                FeatureMap securityData = (FeatureMap)
1028                             Gate.getDataStoreRegister().getSecurityData(ds);
1029                SecurityInfo si = null;
1030                //check whether the datastore supports security data
1031                //serial ones do not for example
1032                if (securityData != null) {
1033                  //first get the type of access from the user
1034                  if(!AccessRightsDialog.showDialog(window))
1035                    return;
1036                  int accessType = AccessRightsDialog.getSelectedMode();
1037                  if(accessType < 0)
1038                    return;
1039                  si = new SecurityInfo(accessType,
1040                                        (User) securityData.get("user"),
1041                                        (Group) securityData.get("group"));
1042                }//if security info
1043                StatusListener sListener = (StatusListener)
1044                                           gate.gui.MainFrame.getListeners().
1045                                           get("gate.event.StatusListener");
1046                MainFrame.lockGUI("Saving " + ((LanguageResource)target).getName());
1047
1048                if(sListener != null) sListener.statusChanged(
1049                  "Saving: " + ((LanguageResource)target).getName());
1050                double timeBefore = System.currentTimeMillis();
1051                LanguageResource lr = ds.adopt((LanguageResource)target,si);
1052                ds.sync(lr);
1053                double timeAfter = System.currentTimeMillis();
1054                if(sListener != null) sListener.statusChanged(
1055                  ((LanguageResource)target).getName() + " saved in " +
1056                  NumberFormat.getInstance().format((timeAfter-timeBefore)/1000)
1057                  + " seconds");
1058
1059                //check whether the new LR is different from the transient one and
1060                //if so, unload the transient LR, so the user realises
1061                //it is no longer valid. Don't do this in the adopt() code itself
1062                //because the batch code might wish to keep the transient
1063                //resource for some purpose.
1064                if (lr != target) {
1065                  Factory.deleteResource((LanguageResource)target);
1066                }
1067              }
1068            }
1069          } catch(PersistenceException pe) {
1070            MainFrame.unlockGUI();
1071            JOptionPane.showMessageDialog(getLargeView(),
1072                                          "Save failed!\n " +
1073                                          pe.toString(),
1074                                          "Gate", JOptionPane.ERROR_MESSAGE);
1075          }catch(gate.security.SecurityException se) {
1076            MainFrame.unlockGUI();
1077            JOptionPane.showMessageDialog(getLargeView(),
1078                                          "Save failed!\n " +
1079                                          se.toString(),
1080                                          "Gate", JOptionPane.ERROR_MESSAGE);
1081          }finally{
1082            MainFrame.unlockGUI();
1083          }
1084
1085        }
1086      };
1087      new Thread(runnable).start();
1088    }
1089  }//class SaveToAction extends AbstractAction
1090
1091  class ReloadAction extends AbstractAction {
1092    ReloadAction() {
1093      super("Reinitialise");
1094      putValue(SHORT_DESCRIPTION, "Reloads this resource");
1095    }
1096
1097    public void actionPerformed(ActionEvent e) {
1098      Runnable runnable = new Runnable(){
1099        public void run(){
1100          if(!(target instanceof ProcessingResource)) return;
1101          try{
1102            long startTime = System.currentTimeMillis();
1103            fireStatusChanged("Reinitialising " +
1104                               target.getName());
1105            Map listeners = new HashMap();
1106            StatusListener sListener = new StatusListener(){
1107                                        public void statusChanged(String text){
1108                                          fireStatusChanged(text);
1109                                        }
1110                                       };
1111            listeners.put("gate.event.StatusListener", sListener);
1112
1113            ProgressListener pListener =
1114                new ProgressListener(){
1115                  public void progressChanged(int value){
1116                    fireProgressChanged(value);
1117                  }
1118                  public void processFinished(){
1119                    fireProcessFinished();
1120                  }
1121                };
1122            listeners.put("gate.event.ProgressListener", pListener);
1123
1124            ProcessingResource res = (ProcessingResource)target;
1125            try{
1126              AbstractResource.setResourceListeners(res, listeners);
1127            }catch (Exception e){
1128              e.printStackTrace(Err.getPrintWriter());
1129            }
1130            //show the progress indicator
1131            fireProgressChanged(0);
1132            //the actual reinitialisation
1133            res.reInit();
1134            try{
1135              AbstractResource.removeResourceListeners(res, listeners);
1136            }catch (Exception e){
1137              e.printStackTrace(Err.getPrintWriter());
1138            }
1139            long endTime = System.currentTimeMillis();
1140            fireStatusChanged(target.getName() +
1141                              " reinitialised in " +
1142                              NumberFormat.getInstance().format(
1143                              (double)(endTime - startTime) / 1000) + " seconds");
1144            fireProcessFinished();
1145          }catch(ResourceInstantiationException rie){
1146            fireStatusChanged("reinitialisation failed");
1147            rie.printStackTrace(Err.getPrintWriter());
1148            JOptionPane.showMessageDialog(getLargeView(),
1149                                          "Reload failed!\n " +
1150                                          "See \"Messages\" tab for details!",
1151                                          "Gate", JOptionPane.ERROR_MESSAGE);
1152            fireProcessFinished();
1153          }
1154        }//public void run()
1155      };
1156      Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
1157                                 runnable,
1158                                 "DefaultResourceHandle1");
1159      thread.setPriority(Thread.MIN_PRIORITY);
1160      thread.start();
1161    }//public void actionPerformed(ActionEvent e)
1162
1163  }//class ReloadAction
1164
1165  class PopulateCorpusAction extends AbstractAction {
1166    PopulateCorpusAction() {
1167      super("Populate");
1168      putValue(SHORT_DESCRIPTION,
1169               "Fills this corpus with documents from a directory");
1170    }
1171
1172    public void actionPerformed(ActionEvent e) {
1173      Runnable runnable = new Runnable(){
1174        public void run(){
1175          corpusFiller.setExtensions(new ArrayList());
1176          corpusFiller.setEncoding("");
1177          boolean answer = OkCancelDialog.showDialog(
1178                                  getLargeView(),
1179                                  corpusFiller,
1180                                  "Select a directory and allowed extensions");
1181          if(answer){
1182            URL url = null;
1183            try{
1184              url = new URL(corpusFiller.getUrlString());
1185              java.util.List extensions = corpusFiller.getExtensions();
1186              ExtensionFileFilter filter = null;
1187              if(extensions == null || extensions.isEmpty()) filter = null;
1188              else{
1189                filter = new ExtensionFileFilter();
1190                Iterator extIter = corpusFiller.getExtensions().iterator();
1191                while(extIter.hasNext()){
1192                  filter.addExtension((String)extIter.next());
1193                }
1194              }
1195              ((Corpus)target).populate(url, filter,
1196                                        corpusFiller.getEncoding(),
1197                                        corpusFiller.isRecurseDirectories());
1198              fireStatusChanged("Corpus populated!");
1199
1200            }catch(MalformedURLException mue){
1201              JOptionPane.showMessageDialog(getLargeView(),
1202                                            "Invalid URL!\n " +
1203                                            "See \"Messages\" tab for details!",
1204                                            "Gate", JOptionPane.ERROR_MESSAGE);
1205              mue.printStackTrace(Err.getPrintWriter());
1206            }catch(IOException ioe){
1207              JOptionPane.showMessageDialog(getLargeView(),
1208                                            "I/O error!\n " +
1209                                            "See \"Messages\" tab for details!",
1210                                            "Gate", JOptionPane.ERROR_MESSAGE);
1211              ioe.printStackTrace(Err.getPrintWriter());
1212            }catch(ResourceInstantiationException rie){
1213              JOptionPane.showMessageDialog(getLargeView(),
1214                                            "Could not create document!\n " +
1215                                            "See \"Messages\" tab for details!",
1216                                            "Gate", JOptionPane.ERROR_MESSAGE);
1217              rie.printStackTrace(Err.getPrintWriter());
1218            }
1219          }
1220        }
1221      };
1222      Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
1223                                 runnable);
1224      thread.setPriority(Thread.MIN_PRIORITY);
1225      thread.start();
1226    }
1227  }
1228
1229  class CreateIndexAction1 extends AbstractAction {
1230    CreateIndexAction1() {
1231      super("Create Index");
1232      putValue(SHORT_DESCRIPTION,
1233               "Create index with documents from a corpus");
1234    }
1235
1236    public void actionPerformed(ActionEvent e) {
1237      CreateIndexDialog cid = null;
1238      if (getWindow() instanceof Frame){
1239        cid = new CreateIndexDialog((Frame) getWindow(), (IndexedCorpus) target);
1240      }
1241      if (getWindow() instanceof Dialog){
1242        cid = new CreateIndexDialog((Dialog) getWindow(), (IndexedCorpus) target);
1243      }
1244      cid.show();
1245    }
1246  }
1247
1248  class CreateIndexAction extends AbstractAction {
1249    CreateIndexAction() {
1250      super("Index corpus");
1251      putValue(SHORT_DESCRIPTION,
1252               "Create index with documents from the corpus");
1253      createIndexGui = new CreateIndexGUI();
1254    }
1255
1256    public void actionPerformed(ActionEvent e) {
1257      boolean ok = OkCancelDialog.showDialog(largeView,
1258                                             createIndexGui,
1259                                             "Index \"" + target.getName() +
1260                                             "\" corpus");
1261      if(ok){
1262        DefaultIndexDefinition did = new DefaultIndexDefinition();
1263        IREngine engine = createIndexGui.getIREngine();
1264        did.setIrEngineClassName(engine.getClass().getName());
1265
1266        did.setIndexLocation(createIndexGui.getIndexLocation().toString());
1267
1268        //add the content if wanted
1269        if(createIndexGui.getUseDocumentContent()){
1270          did.addIndexField(new IndexField("body",
1271                                           new DocumentContentReader(),
1272                                           false));
1273        }
1274        //add all the features
1275        Iterator featIter = createIndexGui.getFeaturesList().iterator();
1276        while(featIter.hasNext()){
1277          String featureName = (String)featIter.next();
1278          did.addIndexField(new IndexField(featureName,
1279                                           new FeatureReader(featureName),
1280                                           false));
1281        }
1282
1283        ((IndexedCorpus)target).setIndexDefinition(did);
1284
1285        Thread thread = new Thread(new Runnable(){
1286          public void run(){
1287            try {
1288              fireProgressChanged(1);
1289              fireStatusChanged("Indexing corpus...");
1290              long start = System.currentTimeMillis();
1291              ((IndexedCorpus)target).getIndexManager().deleteIndex();
1292              fireProgressChanged(10);
1293              ((IndexedCorpus)target).getIndexManager().createIndex();
1294              fireProgressChanged(100);
1295              fireProcessFinished();
1296              fireStatusChanged(
1297                "Corpus indexed in " + NumberFormat.getInstance().format(
1298                (double)(System.currentTimeMillis() - start) / 1000) +
1299                " seconds");
1300            } catch (IndexException ie){
1301              JOptionPane.showMessageDialog(getLargeView() != null ?
1302                                            getLargeView() : getSmallView(),
1303                                            "Could not create index!\n " +
1304                                            "See \"Messages\" tab for details!",
1305                                            "Gate", JOptionPane.ERROR_MESSAGE);
1306              ie.printStackTrace(Err.getPrintWriter());
1307            }finally{
1308              fireProcessFinished();
1309            }
1310          }
1311        });
1312        thread.setPriority(Thread.MIN_PRIORITY);
1313        thread.start();
1314      }
1315    }
1316    CreateIndexGUI createIndexGui;
1317  }
1318
1319  class OptimizeIndexAction extends AbstractAction {
1320    OptimizeIndexAction() {
1321      super("Optimize Index");
1322      putValue(SHORT_DESCRIPTION,
1323               "Optimize existing index");
1324    }
1325
1326    public boolean isEnabled(){
1327      return ((IndexedCorpus)target).getIndexDefinition() != null;
1328    }
1329
1330    public void actionPerformed(ActionEvent e) {
1331      IndexedCorpus ic = (IndexedCorpus) target;
1332      Thread thread = new Thread(new Runnable(){
1333        public void run(){
1334          try{
1335            fireProgressChanged(1);
1336            fireStatusChanged("Optimising index...");
1337            long start  = System.currentTimeMillis();
1338            ((IndexedCorpus)target).getIndexManager().optimizeIndex();
1339            fireStatusChanged(
1340              "Index optimised in " + NumberFormat.getInstance().format(
1341              (double)(System.currentTimeMillis() - start) / 1000) +
1342              " seconds");
1343            fireProcessFinished();
1344          }catch(IndexException ie){
1345            JOptionPane.showMessageDialog(getLargeView() != null ?
1346                                          getLargeView() : getSmallView(),
1347                                          "Errors during optimisation!",
1348                                          "Gate",
1349                                          JOptionPane.PLAIN_MESSAGE);
1350            ie.printStackTrace(Err.getPrintWriter());
1351          }finally{
1352            fireProcessFinished();
1353          }
1354        }
1355      });
1356      thread.setPriority(Thread.MIN_PRIORITY);
1357      thread.start();
1358    }
1359  }
1360
1361  class DeleteIndexAction extends AbstractAction {
1362    DeleteIndexAction() {
1363      super("Delete Index");
1364      putValue(SHORT_DESCRIPTION,
1365               "Delete existing index");
1366    }
1367
1368    public boolean isEnabled(){
1369      return ((IndexedCorpus)target).getIndexDefinition() != null;
1370    }
1371
1372    public void actionPerformed(ActionEvent e) {
1373      int answer = JOptionPane.showOptionDialog(
1374              getLargeView() != null ? getLargeView() : getSmallView(),
1375              "Do you want to delete index?", "Gate",
1376              JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
1377              null, null, null);
1378      if (answer == JOptionPane.YES_OPTION) {
1379        try {
1380          IndexedCorpus ic = (IndexedCorpus) target;
1381          if (ic.getIndexManager() != null){
1382            ic.getIndexManager().deleteIndex();
1383            ic.getFeatures().remove(GateConstants.
1384                                    CORPUS_INDEX_DEFINITION_FEATURE_KEY);
1385          } else {
1386            JOptionPane.showMessageDialog(getLargeView() != null ?
1387                                     getLargeView() :
1388                                     getSmallView(),
1389                                     "There is no index to delete!",
1390                                     "Gate", JOptionPane.PLAIN_MESSAGE);
1391          }
1392        } catch (gate.creole.ir.IndexException ie) {
1393          ie.printStackTrace();
1394        }
1395      }
1396    }
1397  }
1398
1399  /**
1400   * Releases the memory, removes the listeners, cleans up.
1401   * Will get called when the target resource is unloaded from the system
1402   */
1403  protected void cleanup(){
1404    //delete all the VRs that were created
1405    if(largeView != null){
1406      if(largeView instanceof VisualResource){
1407        //we only had a view so no tabbed pane was used
1408        Factory.deleteResource((VisualResource)largeView);
1409      }else{
1410        Component vrs[] = ((JTabbedPane)largeView).getComponents();
1411        for(int i = 0; i < vrs.length; i++){
1412          if(vrs[i] instanceof VisualResource){
1413            Factory.deleteResource((VisualResource)vrs[i]);
1414          }
1415        }
1416      }
1417    }
1418
1419    if(smallView != null){
1420      if(smallView instanceof VisualResource){
1421        //we only had a view so no tabbed pane was used
1422        Factory.deleteResource((VisualResource)smallView);
1423      }else{
1424        Component vrs[] = ((JTabbedPane)smallView).getComponents();
1425        for(int i = 0; i < vrs.length; i++){
1426          if(vrs[i] instanceof VisualResource){
1427            Factory.deleteResource((VisualResource)vrs[i]);
1428          }
1429        }
1430      }
1431    }
1432
1433    Gate.getCreoleRegister().removeCreoleListener(this);
1434    popup = null;
1435    target = null;
1436  }
1437
1438  class ProxyStatusListener implements StatusListener{
1439    public void statusChanged(String text){
1440      fireStatusChanged(text);
1441    }
1442  }
1443
1444  protected void fireProgressChanged(int e) {
1445    if (progressListeners != null) {
1446      Vector listeners = progressListeners;
1447      int count = listeners.size();
1448      for (int i = 0; i < count; i++) {
1449        ((ProgressListener) listeners.elementAt(i)).progressChanged(e);
1450      }
1451    }
1452  }//protected void fireProgressChanged(int e)
1453
1454  protected void fireProcessFinished() {
1455    if (progressListeners != null) {
1456      Vector listeners = progressListeners;
1457      int count = listeners.size();
1458      for (int i = 0; i < count; i++) {
1459        ((ProgressListener) listeners.elementAt(i)).processFinished();
1460      }
1461    }
1462  }//protected void fireProcessFinished()
1463
1464  public synchronized void removeStatusListener(StatusListener l) {
1465    if (statusListeners != null && statusListeners.contains(l)) {
1466      Vector v = (Vector) statusListeners.clone();
1467      v.removeElement(l);
1468      statusListeners = v;
1469    }
1470  }//public synchronized void removeStatusListener(StatusListener l)
1471
1472  public synchronized void addStatusListener(StatusListener l) {
1473    Vector v = statusListeners == null ? new Vector(2) : (Vector) statusListeners.clone();
1474    if (!v.contains(l)) {
1475      v.addElement(l);
1476      statusListeners = v;
1477    }
1478  }//public synchronized void addStatusListener(StatusListener l)
1479
1480  protected void fireStatusChanged(String e) {
1481    if (statusListeners != null) {
1482      Vector listeners = statusListeners;
1483      int count = listeners.size();
1484      for (int i = 0; i < count; i++) {
1485        ((StatusListener) listeners.elementAt(i)).statusChanged(e);
1486      }
1487    }
1488  }
1489
1490  public void statusChanged(String e) {
1491    fireStatusChanged(e);
1492  }
1493  public void progressChanged(int e) {
1494    fireProgressChanged(e);
1495  }
1496  public void processFinished() {
1497    fireProcessFinished();
1498  }
1499  public Window getWindow() {
1500    return window;
1501  }
1502
1503  public void resourceLoaded(CreoleEvent e) {
1504  }
1505
1506  public void resourceUnloaded(CreoleEvent e) {
1507    if(getTarget() == e.getResource()) cleanup();
1508
1509  }
1510
1511  public void resourceRenamed(Resource resource, String oldName,
1512                              String newName){
1513    if(target == resource) title = target.getName();
1514  }
1515
1516  public void datastoreOpened(CreoleEvent e) {
1517  }
1518
1519  public void datastoreCreated(CreoleEvent e) {
1520  }
1521
1522  public void datastoreClosed(CreoleEvent e) {
1523    if(getTarget() == e.getDatastore()) cleanup();
1524  }
1525}//class DefaultResourceHandle
1526