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