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.79 2004/08/06 16:08:25 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         XJMenuItem savePreserveFormatItem =
396                          new XJMenuItem(new DumpPreserveFormatAction(),
397                                         sListenerProxy);
398         staticPopupItems.add(savePreserveFormatItem);
399       }else if(target instanceof Corpus){
400         staticPopupItems.add(null);
401         corpusFiller = new CorpusFillerComponent();
402         staticPopupItems.add(new XJMenuItem(new PopulateCorpusAction(), sListenerProxy));
403         staticPopupItems.add(null);
404         staticPopupItems.add(new XJMenuItem(new SaveCorpusAsXmlAction(false), sListenerProxy));
405         staticPopupItems.add(new XJMenuItem(new SaveCorpusAsXmlAction(true), sListenerProxy));
406         if (target instanceof IndexedCorpus){
407           staticPopupItems.add(null);
408           staticPopupItems.add(new XJMenuItem(new CreateIndexAction(), sListenerProxy));
409           staticPopupItems.add(new XJMenuItem(new OptimizeIndexAction(), sListenerProxy));
410           staticPopupItems.add(new XJMenuItem(new DeleteIndexAction(), sListenerProxy));
411         }
412       }
413       if (target instanceof gate.creole.ProtegeProjectName){
414         fillProtegeActions(staticPopupItems);
415       }// End if
416     }else if(target instanceof Controller){
417       //Applications
418       staticPopupItems.add(null);
419       staticPopupItems.add(new XJMenuItem(new DumpToFileAction(), sListenerProxy));
420     }
421   }//protected void buildViews
422 
423   public String toString(){ return title;}
424 
425   public synchronized void removeProgressListener(ProgressListener l) {
426     if (progressListeners != null && progressListeners.contains(l)) {
427       Vector v = (Vector) progressListeners.clone();
428       v.removeElement(l);
429       progressListeners = v;
430     }
431   }//public synchronized void removeProgressListener(ProgressListener l)
432 
433   public synchronized void addProgressListener(ProgressListener l) {
434     Vector v = progressListeners == null ? new Vector(2) : (Vector) progressListeners.clone();
435     if (!v.contains(l)) {
436       v.addElement(l);
437       progressListeners = v;
438     }
439   }//public synchronized void addProgressListener(ProgressListener l)
440 
441   String title;
442   String tooltipText;
443   NameBearer target;
444 
445   /**
446    * Stores all the action providers for this resource.
447    * They will be questioned when the getPopup() method is called.
448    */
449   protected List actionPublishers;
450 
451   /**
452    * A list of menu items that constitute the static part of the popup.
453    * Null values are used for separators.
454    */
455   protected List staticPopupItems;
456 
457   /**
458    * The top level GUI component this hadle belongs to.
459    */
460   Window window;
461   ResourceData rData;
462   Icon icon;
463   JComponent smallView;
464   JComponent largeView;
465 
466   /**
467    * Component used to select the options for corpus populating
468    */
469   CorpusFillerComponent corpusFiller;
470 
471   StatusListener sListenerProxy;
472 
473 //  File currentDir = null;
474   private transient Vector progressListeners;
475   private transient Vector statusListeners;
476 
477   class CloseAction extends AbstractAction {
478     public CloseAction() {
479       super("Close");
480       putValue(SHORT_DESCRIPTION, "Removes this resource from the system");
481     }
482 
483     public void actionPerformed(ActionEvent e){
484       if(target instanceof Resource){
485         Factory.deleteResource((Resource)target);
486       }else if(target instanceof DataStore){
487         try{
488           ((DataStore)target).close();
489         } catch(PersistenceException pe){
490           JOptionPane.showMessageDialog(largeView != null ?
491                                                      largeView : smallView,
492                                         "Error!\n" + pe.toString(),
493                                         "GATE", JOptionPane.ERROR_MESSAGE);
494         }
495       }
496 
497       statusListeners.clear();
498       progressListeners.clear();
499 //      //delete the viewers
500 //      if(largeView instanceof VisualResource){
501 //        Factory.deleteResource((VisualResource)largeView);
502 //      }else if(largeView instanceof JTabbedPane){
503 //        Component[] comps = ((JTabbedPane)largeView).getComponents();
504 //        for(int i = 0; i < comps.length; i++){
505 //          if(comps[i] instanceof VisualResource)
506 //            Factory.deleteResource((VisualResource)comps[i]);
507 //        }
508 //      }
509 //      if(smallView instanceof VisualResource){
510 //        Factory.deleteResource((VisualResource)smallView);
511 //      }else if(smallView instanceof JTabbedPane){
512 //        Component[] comps = ((JTabbedPane)smallView).getComponents();
513 //        for(int i = 0; i < comps.length; i++){
514 //          if(comps[i] instanceof VisualResource)
515 //            Factory.deleteResource((VisualResource)comps[i]);
516 //        }
517 //      }
518 //
519     }//public void actionPerformed(ActionEvent e)
520   }//class CloseAction
521 
522   /**
523    * Used to save a document as XML
524    */
525   class SaveAsXmlAction extends AbstractAction {
526     public SaveAsXmlAction(){
527       super("Save As Xml...");
528       putValue(SHORT_DESCRIPTION, "Saves this resource in XML");
529     }// SaveAsXmlAction()
530 
531     public void actionPerformed(ActionEvent e) {
532       Runnable runableAction = new Runnable(){
533         public void run(){
534           JFileChooser fileChooser = MainFrame.getFileChooser();
535           File selectedFile = null;
536 
537           List filters = Arrays.asList(fileChooser.getChoosableFileFilters());
538           Iterator filtersIter = filters.iterator();
539           FileFilter filter = null;
540           if(filtersIter.hasNext()){
541             filter = (FileFilter)filtersIter.next();
542             while(filtersIter.hasNext() &&
543                   filter.getDescription().indexOf("XML") == -1){
544               filter = (FileFilter)filtersIter.next();
545             }
546           }
547           if(filter == null || filter.getDescription().indexOf("XML") == -1){
548             //no suitable filter found, create a new one
549             ExtensionFileFilter xmlFilter = new ExtensionFileFilter();
550             xmlFilter.setDescription("XML files");
551             xmlFilter.addExtension("xml");
552             xmlFilter.addExtension("gml");
553             fileChooser.addChoosableFileFilter(xmlFilter);
554             filter = xmlFilter;
555           }
556           fileChooser.setFileFilter(filter);
557 
558           fileChooser.setMultiSelectionEnabled(false);
559           fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
560           fileChooser.setDialogTitle("Select document to save ...");
561           fileChooser.setSelectedFiles(null);
562 
563           int res = (getLargeView() != null) ?
564                                   fileChooser.showDialog(getLargeView(), "Save"):
565                     (getSmallView() != null) ?
566                                   fileChooser.showDialog(getSmallView(), "Save") :
567                                               fileChooser.showDialog(null, "Save");
568           if(res == JFileChooser.APPROVE_OPTION){
569             selectedFile = fileChooser.getSelectedFile();
570             File currentDir = fileChooser.getCurrentDirectory();
571             if(selectedFile == null) return;
572             long start = System.currentTimeMillis();
573             NameBearerHandle.this.statusChanged("Saving as XML to " +
574              selectedFile.toString() + "...");
575             try{
576               MainFrame.lockGUI("Saving...");
577               // Prepare to write into the xmlFile using the original encoding
578               ////////////////////////////////
579               String encoding = ((gate.TextualDocument)target).getEncoding();
580 
581               OutputStreamWriter writer = new OutputStreamWriter(
582                                             new FileOutputStream(selectedFile),
583                                             encoding);
584 
585               // Write (test the toXml() method)
586               // This Action is added only when a gate.Document is created.
587               // So, is for sure that the resource is a gate.Document
588               writer.write(((gate.Document)target).toXml());
589               writer.flush();
590               writer.close();
591             } catch (Exception ex){
592               ex.printStackTrace(Out.getPrintWriter());
593             }finally{
594               MainFrame.unlockGUI();
595             }
596             long time = System.currentTimeMillis() - start;
597             NameBearerHandle.this.statusChanged("Finished saving as xml into "+
598              " the file: " + selectedFile.toString() +
599              " in " + ((double)time) / 1000 + " s");
600           }// End if
601         }// End run()
602       };// End Runnable
603       Thread thread = new Thread(runableAction, "");
604       thread.setPriority(Thread.MIN_PRIORITY);
605       thread.start();
606     }// actionPerformed()
607   }// SaveAsXmlAction
608 
609   /**
610    * The action that is fired when the user wants to dump annotations
611    * preserving the original document format.
612    */
613   protected class DumpPreserveFormatAction extends AbstractAction{
614 //    private Set annotationsToDump = null;
615 
616     public DumpPreserveFormatAction(){
617       super("Save preserving document format");
618     }
619 
620 
621     /** This method takes care of how the dumping is done*/
622     public void actionPerformed(ActionEvent e){
623       Runnable runableAction = new Runnable(){
624         public void run(){
625           JFileChooser fileChooser = MainFrame.getFileChooser();
626           File selectedFile = null;
627 
628           fileChooser.setMultiSelectionEnabled(false);
629           fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
630           fileChooser.setDialogTitle("Select document to save ...");
631           fileChooser.setSelectedFiles(null);
632 
633           int res = (getLargeView() != null) ?
634                                   fileChooser.showDialog(getLargeView(), "Save"):
635                     (getSmallView() != null) ?
636                                   fileChooser.showDialog(getSmallView(), "Save") :
637                                               fileChooser.showDialog(null, "Save");
638           if(res == JFileChooser.APPROVE_OPTION){
639             selectedFile = fileChooser.getSelectedFile();
640             fileChooser.setCurrentDirectory(fileChooser.getCurrentDirectory());
641             if(selectedFile == null) return;
642             if (NameBearerHandle.this!= null)
643               NameBearerHandle.this.statusChanged("Please wait while dumping annotations"+
644               "in the original format to " + selectedFile.toString() + " ...");
645             // This method construct a set with all annotations that need to be
646             // dupmped as Xml. If the set is null then only the original markups
647             // are dumped.
648             Set annotationsToDump = null;
649             //find the shown document editor. If none, just dump the original
650             //markup annotations, i.e., leave the annotationsToDump null
651             if (largeView instanceof JTabbedPane) {
652               Component shownComponent =
653                 ((JTabbedPane) largeView).getSelectedComponent();
654               if (shownComponent instanceof DocumentEditor) {
655                 //so we only get annotations for dumping if they are shown in the
656                 //table of the document editor, which is currently in front
657                 //of the user
658                 annotationsToDump =
659                   ((DocumentEditor) shownComponent).getDisplayedAnnotations();
660               }//if we have a document editor
661             }//if tabbed pane
662             try{
663               // Prepare to write into the xmlFile using the original encoding
664               String encoding = ((gate.TextualDocument)target).getEncoding();
665 
666               OutputStreamWriter writer = new OutputStreamWriter(
667                                             new FileOutputStream(selectedFile),
668                                             encoding);
669 
670               //determine if the features need to be saved first
671               Boolean featuresSaved =
672                   Gate.getUserConfig().getBoolean(
673                     GateConstants.SAVE_FEATURES_WHEN_PRESERVING_FORMAT);
674               boolean saveFeatures = true;
675               if (featuresSaved != null)
676                 saveFeatures = featuresSaved.booleanValue();
677               // Write with the toXml() method
678               writer.write(
679                 ((gate.Document)target).toXml(annotationsToDump, saveFeatures));
680               writer.flush();
681               writer.close();
682             } catch (Exception ex){
683               ex.printStackTrace(Out.getPrintWriter());
684             }// End try
685             if (NameBearerHandle.this!= null)
686               NameBearerHandle.this.statusChanged("Finished dumping into the "+
687               "file : " + selectedFile.toString());
688           }// End if
689         }// End run()
690       };// End Runnable
691       Thread thread = new Thread(runableAction, "");
692       thread.setPriority(Thread.MIN_PRIORITY);
693       thread.start();
694     }//public void actionPerformed(ActionEvent e)
695 
696   }//class DumpPreserveFormatAction
697 
698 
699   /**
700    * Saves a corpus as a set of xml files in a directory.
701    */
702   class SaveCorpusAsXmlAction extends AbstractAction {
703     private boolean preserveFormat;
704     public SaveCorpusAsXmlAction(boolean preserveFormat){
705       super("Save As Xml...");
706       putValue(SHORT_DESCRIPTION, "Saves this corpus in XML");
707       this.preserveFormat = preserveFormat;
708 
709       if(preserveFormat) {
710         putValue(NAME, "Save As Xml preserve format...");
711         putValue(SHORT_DESCRIPTION, "Saves this corpus in XML preserve format");
712       } // if
713     }// SaveAsXmlAction()
714 
715     public void actionPerformed(ActionEvent e) {
716       Runnable runnable = new Runnable(){
717         public void run(){
718 if(preserveFormat) System.out.println("Preserve option set!");
719           try{
720             //we need a directory
721             JFileChooser filer = MainFrame.getFileChooser();
722             filer.setDialogTitle(
723                 "Select the directory that will contain the corpus");
724             filer.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
725             filer.setFileFilter(filer.getAcceptAllFileFilter());
726 
727             if (filer.showDialog(getLargeView() != null ?
728                                      getLargeView() :
729                                      getSmallView(),
730                                      "Select") == JFileChooser.APPROVE_OPTION){
731 
732               File dir = filer.getSelectedFile();
733               //create the top directory if needed
734               if(!dir.exists()){
735                 if(!dir.mkdirs()){
736                   JOptionPane.showMessageDialog(
737                     largeView != null ?largeView : smallView,
738                     "Could not create top directory!",
739                     "GATE", JOptionPane.ERROR_MESSAGE);
740                   return;
741                 }
742               }
743 
744               MainFrame.lockGUI("Saving...");
745 
746               //iterate through all the docs and save each of them as xml
747               Corpus corpus = (Corpus)target;
748               Iterator docIter = corpus.iterator();
749               boolean overwriteAll = false;
750               int docCnt = corpus.size();
751               int currentDocIndex = 0;
752               while(docIter.hasNext()){
753                 boolean docWasLoaded = corpus.isDocumentLoaded(currentDocIndex);
754                 Document currentDoc = (Document)docIter.next();
755                 URL sourceURL = currentDoc.getSourceUrl();
756                 String fileName = null;
757                 if(sourceURL != null){
758                   fileName = sourceURL.getFile();
759                   fileName = Files.getLastPathComponent(fileName);
760                 }
761                 if(fileName == null || fileName.length() == 0){
762                   fileName = currentDoc.getName();
763                 }
764                 if(!fileName.toLowerCase().endsWith(".xml")) fileName += ".xml";
765                 File docFile = null;
766                 boolean nameOK = false;
767                 do{
768                   docFile = new File(dir, fileName);
769                   if(docFile.exists() && !overwriteAll){
770                     //ask the user if we can ovewrite the file
771                     Object[] options = new Object[] {"Yes", "All",
772                                                      "No", "Cancel"};
773                     MainFrame.unlockGUI();
774                     int answer = JOptionPane.showOptionDialog(
775                       largeView != null ? largeView : smallView,
776                       "File " + docFile.getName() + " already exists!\n" +
777                       "Overwrite?" ,
778                       "GATE", JOptionPane.DEFAULT_OPTION,
779                       JOptionPane.WARNING_MESSAGE, null, options, options[2]);
780                     MainFrame.lockGUI("Saving...");
781                     switch(answer){
782                       case 0: {
783                         nameOK = true;
784                         break;
785                       }
786                       case 1: {
787                         nameOK = true;
788                         overwriteAll = true;
789                         break;
790                       }
791                       case 2: {
792                         //user said NO, allow them to provide an alternative name;
793                         MainFrame.unlockGUI();
794                         fileName = (String)JOptionPane.showInputDialog(
795                             largeView != null ? largeView : smallView,
796                             "Please provide an alternative file name",
797                             "GATE", JOptionPane.QUESTION_MESSAGE,
798                             null, null, fileName);
799                         if(fileName == null){
800                           fireProcessFinished();
801                           return;
802                         }
803                         MainFrame.lockGUI("Saving");
804                         break;
805                       }
806                       case 3: {
807                         //user gave up; return
808                         fireProcessFinished();
809                         return;
810                       }
811                     }
812 
813                   }else{
814                     nameOK = true;
815                   }
816                 }while(!nameOK);
817                 //save the file
818                 try{
819                   String content = "";
820                   // check for preserve format flag
821                   if(preserveFormat) {
822                     Set annotationsToDump = null;
823                     // Find the shown document editor.
824                     // If none, just dump the original markup annotations,
825                     // i.e., leave the annotationsToDump null
826                     if (largeView instanceof JTabbedPane) {
827                       Component shownComponent =
828                         ((JTabbedPane) largeView).getSelectedComponent();
829                       if (shownComponent instanceof DocumentEditor) {
830                         // so we only get annotations for dumping
831                         // if they are shown in the table of the document editor,
832                         // which is currently in front of the user
833                         annotationsToDump =
834                           ((DocumentEditor) shownComponent).getDisplayedAnnotations();
835                       }//if we have a document editor
836                     }//if tabbed pane
837 
838                     //determine if the features need to be saved first
839                     Boolean featuresSaved =
840                         Gate.getUserConfig().getBoolean(
841                           GateConstants.SAVE_FEATURES_WHEN_PRESERVING_FORMAT);
842                     boolean saveFeatures = true;
843                     if (featuresSaved != null)
844                       saveFeatures = featuresSaved.booleanValue();
845 
846                     // Write with the toXml() method
847                     content = currentDoc.toXml(annotationsToDump, saveFeatures);
848                   }
849                   else {
850                     content = currentDoc.toXml();
851                   } // if
852 
853                   // Prepare to write into the xmlFile using the original encoding
854                   String encoding = ((gate.TextualDocument)currentDoc).getEncoding();
855 
856                   OutputStreamWriter writer = new OutputStreamWriter(
857                                                 new FileOutputStream(docFile),
858                                                 encoding);
859 
860                   writer.write(content);
861                   writer.flush();
862                   writer.close();
863                 }catch(IOException ioe){
864                   MainFrame.unlockGUI();
865                   JOptionPane.showMessageDialog(
866                     largeView != null ? largeView : smallView,
867                     "Could not create write file:" +
868                     ioe.toString(),
869                     "GATE", JOptionPane.ERROR_MESSAGE);
870                   ioe.printStackTrace(Err.getPrintWriter());
871                   return;
872                 }
873 
874                 fireStatusChanged(currentDoc.getName() + " saved");
875                 //close the doc if it wasn't already loaded
876                 if(!docWasLoaded){
877                   corpus.unloadDocument(currentDoc);
878                   Factory.deleteResource(currentDoc);
879                 }
880 
881                 fireProgressChanged(100 * currentDocIndex++ / docCnt);
882               }//while(docIter.hasNext())
883               fireStatusChanged("Corpus saved");
884               fireProcessFinished();
885             }//select directory
886           }finally{
887             MainFrame.unlockGUI();
888           }
889         }//public void run(){
890       };//Runnable runnable = new Runnable()
891       Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
892                                  runnable, "Corpus XML dumper");
893       thread.setPriority(Thread.MIN_PRIORITY);
894       thread.start();
895 
896     }//public void actionPerformed(ActionEvent e)
897   }//class SaveCorpusAsXmlAction extends AbstractAction
898 
899   /**
900    * Saves a corpus as a set of xml files in a directory.
901    */
902   class ReloadClassAction extends AbstractAction {
903     public ReloadClassAction(){
904       super("Reload resource class");
905       putValue(SHORT_DESCRIPTION, "Reloads the java class for this resource");
906     }// SaveAsXmlAction()
907 
908     public void actionPerformed(ActionEvent e) {
909       int answer = JOptionPane.showOptionDialog(
910                 largeView != null ? largeView : smallView,
911                 "This is an advanced option!\n" +
912                 "You should not use this unless your name is Hamish.\n" +
913                 "Are you sure you want to do this?" ,
914                 "GATE", JOptionPane.YES_NO_OPTION,
915                 JOptionPane.WARNING_MESSAGE, null, null, null);
916       if(answer == JOptionPane.OK_OPTION){
917         try{
918           String className = target.getClass().getName();
919           Gate.getClassLoader().reloadClass(className);
920           fireStatusChanged("Class " + className + " reloaded!");
921         }catch(Exception ex){
922           JOptionPane.showMessageDialog(largeView != null ?
923                                         largeView : smallView,
924                                         "Look what you've done: \n" +
925                                         ex.toString() +
926                                         "\nI told you not to do it...",
927                                         "GATE", JOptionPane.ERROR_MESSAGE);
928           ex.printStackTrace(Err.getPrintWriter());
929         }
930       }
931     }
932   }
933 
934   class SaveAction extends AbstractAction {
935     public SaveAction(){
936       super("Save");
937       putValue(SHORT_DESCRIPTION, "Save back to the datastore");
938     }
939     public void actionPerformed(ActionEvent e){
940       Runnable runnable = new Runnable(){
941         public void run(){
942           DataStore ds = ((LanguageResource)target).getDataStore();
943           if(ds != null){
944             try {
945               MainFrame.lockGUI("Saving " + ((LanguageResource)target).getName());
946               StatusListener sListener = (StatusListener)
947                                          gate.gui.MainFrame.getListeners().
948                                          get("gate.event.StatusListener");
949               if(sListener != null) sListener.statusChanged(
950                 "Saving: " + ((LanguageResource)target).getName());
951               double timeBefore = System.currentTimeMillis();
952               ((LanguageResource)
953                         target).getDataStore().sync((LanguageResource)target);
954               double timeAfter = System.currentTimeMillis();
955               if(sListener != null) sListener.statusChanged(
956                 ((LanguageResource)target).getName() + " saved in " +
957                 NumberFormat.getInstance().format((timeAfter-timeBefore)/1000)
958                 + " seconds");
959             } catch(PersistenceException pe) {
960               MainFrame.unlockGUI();
961               JOptionPane.showMessageDialog(getLargeView(),
962                                             "Save failed!\n " +
963                                             pe.toString(),
964                                             "GATE", JOptionPane.ERROR_MESSAGE);
965             } catch(SecurityException se) {
966               MainFrame.unlockGUI();
967               JOptionPane.showMessageDialog(getLargeView(),
968                                             "Save failed!\n " +
969                                             se.toString(),
970                                             "GATE", JOptionPane.ERROR_MESSAGE);
971             }finally{
972               MainFrame.unlockGUI();
973             }
974           } else {
975             JOptionPane.showMessageDialog(getLargeView(),
976                             "This resource has not been loaded from a datastore.\n"+
977                              "Please use the \"Save to\" option!\n",
978                              "GATE", JOptionPane.ERROR_MESSAGE);
979 
980           }
981         }
982       };
983       new Thread(runnable).start();
984     }//public void actionPerformed(ActionEvent e)
985   }//class SaveAction
986 
987 
988 
989   class DumpToFileAction extends AbstractAction {
990     public DumpToFileAction(){
991       super("Save application state");
992       putValue(SHORT_DESCRIPTION,
993                "Saves the data needed to recreate this application");
994     }
995 
996     public void actionPerformed(ActionEvent ae){
997       JFileChooser fileChooser = MainFrame.getFileChooser();
998 
999       fileChooser.setDialogTitle("Select a file for this resource");
1000      fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
1001      if (fileChooser.showSaveDialog(largeView) ==
1002                                            JFileChooser.APPROVE_OPTION){
1003        final File file = fileChooser.getSelectedFile();
1004          Runnable runnable = new Runnable(){
1005            public void run(){
1006              try{
1007                gate.util.persistence.PersistenceManager.
1008                                      saveObjectToFile((Resource)target, file);
1009              }catch(Exception e){
1010                JOptionPane.showMessageDialog(getLargeView(),
1011                                "Error!\n"+
1012                                 e.toString(),
1013                                 "GATE", JOptionPane.ERROR_MESSAGE);
1014                e.printStackTrace(Err.getPrintWriter());
1015              }
1016            }
1017          };
1018          Thread thread = new Thread(runnable);
1019          thread.setPriority(Thread.MIN_PRIORITY);
1020          thread.start();
1021      }
1022    }
1023
1024  }
1025
1026  class SaveToAction extends AbstractAction {
1027    public SaveToAction(){
1028      super("Save to...");
1029      putValue(SHORT_DESCRIPTION, "Save this resource to a datastore");
1030    }
1031
1032    public void actionPerformed(ActionEvent e) {
1033      Runnable runnable = new Runnable(){
1034        public void run(){
1035          try {
1036            DataStoreRegister dsReg = Gate.getDataStoreRegister();
1037            Map dsByName =new HashMap();
1038            Iterator dsIter = dsReg.iterator();
1039            while(dsIter.hasNext()){
1040              DataStore oneDS = (DataStore)dsIter.next();
1041              String name;
1042              if((name = (String)oneDS.getName()) != null){
1043              } else {
1044                name  = oneDS.getStorageUrl();
1045                try {
1046                  URL tempURL = new URL(name);
1047                  name = tempURL.getFile();
1048                } catch (java.net.MalformedURLException ex) {
1049                  throw new GateRuntimeException(
1050                            );
1051                }
1052              }
1053              dsByName.put(name, oneDS);
1054            }
1055            List dsNames = new ArrayList(dsByName.keySet());
1056            if(dsNames.isEmpty()){
1057              JOptionPane.showMessageDialog(getLargeView(),
1058                                            "There are no open datastores!\n " +
1059                                            "Please open a datastore first!",
1060                                            "GATE", JOptionPane.ERROR_MESSAGE);
1061
1062            } else {
1063              Object answer = JOptionPane.showInputDialog(
1064                                  getLargeView(),
1065                                  "Select the datastore",
1066                                  "GATE", JOptionPane.QUESTION_MESSAGE,
1067                                  null, dsNames.toArray(),
1068                                  dsNames.get(0));
1069              if(answer == null) return;
1070              DataStore ds = (DataStore)dsByName.get(answer);
1071              if (ds == null){
1072                Err.prln("The datastore does not exists. Saving procedure" +
1073                                  " has FAILED! This should never happen again!");
1074                return;
1075              }// End if
1076              DataStore ownDS = ((LanguageResource)target).getDataStore();
1077              if(ds == ownDS){
1078                MainFrame.lockGUI("Saving " + ((LanguageResource)target).getName());
1079
1080                StatusListener sListener = (StatusListener)
1081                                           gate.gui.MainFrame.getListeners().
1082                                           get("gate.event.StatusListener");
1083                if(sListener != null) sListener.statusChanged(
1084                  "Saving: " + ((LanguageResource)target).getName());
1085                double timeBefore = System.currentTimeMillis();
1086                ds.sync((LanguageResource)target);
1087                double timeAfter = System.currentTimeMillis();
1088                if(sListener != null) sListener.statusChanged(
1089                  ((LanguageResource)target).getName() + " saved in " +
1090                  NumberFormat.getInstance().format((timeAfter-timeBefore)/1000)
1091                  + " seconds");
1092              }else{
1093                FeatureMap securityData = (FeatureMap)
1094                             DataStoreRegister.getSecurityData(ds);
1095                SecurityInfo si = null;
1096                //check whether the datastore supports security data
1097                //serial ones do not for example
1098                if (securityData != null) {
1099                  //first get the type of access from the user
1100                  if(!AccessRightsDialog.showDialog(window))
1101                    return;
1102                  int accessType = AccessRightsDialog.getSelectedMode();
1103                  if(accessType < 0)
1104                    return;
1105                  si = new SecurityInfo(accessType,
1106                                        (User) securityData.get("user"),
1107                                        (Group) securityData.get("group"));
1108                }//if security info
1109                StatusListener sListener = (StatusListener)
1110                                           gate.gui.MainFrame.getListeners().
1111                                           get("gate.event.StatusListener");
1112                MainFrame.lockGUI("Saving " + ((LanguageResource)target).getName());
1113
1114                if(sListener != null) sListener.statusChanged(
1115                  "Saving: " + ((LanguageResource)target).getName());
1116                double timeBefore = System.currentTimeMillis();
1117                LanguageResource lr = ds.adopt((LanguageResource)target,si);
1118                ds.sync(lr);
1119                double timeAfter = System.currentTimeMillis();
1120                if(sListener != null) sListener.statusChanged(
1121                  ((LanguageResource)target).getName() + " saved in " +
1122                  NumberFormat.getInstance().format((timeAfter-timeBefore)/1000)
1123                  + " seconds");
1124
1125                //check whether the new LR is different from the transient one and
1126                //if so, unload the transient LR, so the user realises
1127                //it is no longer valid. Don't do this in the adopt() code itself
1128                //because the batch code might wish to keep the transient
1129                //resource for some purpose.
1130                if (lr != target) {
1131                  Factory.deleteResource((LanguageResource)target);
1132                }
1133              }
1134            }
1135          } catch(PersistenceException pe) {
1136            MainFrame.unlockGUI();
1137            JOptionPane.showMessageDialog(getLargeView(),
1138                                          "Save failed!\n " +
1139                                          pe.toString(),
1140                                          "GATE", JOptionPane.ERROR_MESSAGE);
1141          }catch(gate.security.SecurityException se) {
1142            MainFrame.unlockGUI();
1143            JOptionPane.showMessageDialog(getLargeView(),
1144                                          "Save failed!\n " +
1145                                          se.toString(),
1146                                          "GATE", JOptionPane.ERROR_MESSAGE);
1147          }finally{
1148            MainFrame.unlockGUI();
1149          }
1150
1151        }
1152      };
1153      new Thread(runnable).start();
1154    }
1155  }//class SaveToAction extends AbstractAction
1156
1157  class ReloadAction extends AbstractAction {
1158    ReloadAction() {
1159      super("Reinitialise");
1160      putValue(SHORT_DESCRIPTION, "Reloads this resource");
1161    }
1162
1163    public void actionPerformed(ActionEvent e) {
1164      Runnable runnable = new Runnable(){
1165        public void run(){
1166          if(!(target instanceof ProcessingResource)) return;
1167          try{
1168            long startTime = System.currentTimeMillis();
1169            fireStatusChanged("Reinitialising " +
1170                               target.getName());
1171            Map listeners = new HashMap();
1172            StatusListener sListener = new StatusListener(){
1173                                        public void statusChanged(String text){
1174                                          fireStatusChanged(text);
1175                                        }
1176                                       };
1177            listeners.put("gate.event.StatusListener", sListener);
1178
1179            ProgressListener pListener =
1180                new ProgressListener(){
1181                  public void progressChanged(int value){
1182                    fireProgressChanged(value);
1183                  }
1184                  public void processFinished(){
1185                    fireProcessFinished();
1186                  }
1187                };
1188            listeners.put("gate.event.ProgressListener", pListener);
1189
1190            ProcessingResource res = (ProcessingResource)target;
1191            try{
1192              AbstractResource.setResourceListeners(res, listeners);
1193            }catch (Exception e){
1194              e.printStackTrace(Err.getPrintWriter());
1195            }
1196            //show the progress indicator
1197            fireProgressChanged(0);
1198            //the actual reinitialisation
1199            res.reInit();
1200            try{
1201              AbstractResource.removeResourceListeners(res, listeners);
1202            }catch (Exception e){
1203              e.printStackTrace(Err.getPrintWriter());
1204            }
1205            long endTime = System.currentTimeMillis();
1206            fireStatusChanged(target.getName() +
1207                              " reinitialised in " +
1208                              NumberFormat.getInstance().format(
1209                              (double)(endTime - startTime) / 1000) + " seconds");
1210            fireProcessFinished();
1211          }catch(ResourceInstantiationException rie){
1212            fireStatusChanged("reinitialisation failed");
1213            rie.printStackTrace(Err.getPrintWriter());
1214            JOptionPane.showMessageDialog(getLargeView(),
1215                                          "Reload failed!\n " +
1216                                          "See \"Messages\" tab for details!",
1217                                          "GATE", JOptionPane.ERROR_MESSAGE);
1218            fireProcessFinished();
1219          }
1220        }//public void run()
1221      };
1222      Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
1223                                 runnable,
1224                                 "DefaultResourceHandle1");
1225      thread.setPriority(Thread.MIN_PRIORITY);
1226      thread.start();
1227    }//public void actionPerformed(ActionEvent e)
1228
1229  }//class ReloadAction
1230
1231  class PopulateCorpusAction extends AbstractAction {
1232    PopulateCorpusAction() {
1233      super("Populate");
1234      putValue(SHORT_DESCRIPTION,
1235               "Fills this corpus with documents from a directory");
1236    }
1237
1238    public void actionPerformed(ActionEvent e) {
1239      Runnable runnable = new Runnable(){
1240        public void run(){
1241          corpusFiller.setExtensions(new ArrayList());
1242          corpusFiller.setEncoding("");
1243          boolean answer = OkCancelDialog.showDialog(
1244                                  getLargeView(),
1245                                  corpusFiller,
1246                                  "Select a directory and allowed extensions");
1247          if(answer){
1248            long startTime = System.currentTimeMillis();
1249            URL url = null;
1250            try{
1251              url = new URL(corpusFiller.getUrlString());
1252              java.util.List extensions = corpusFiller.getExtensions();
1253              ExtensionFileFilter filter = null;
1254              if(extensions == null || extensions.isEmpty()) filter = null;
1255              else{
1256                filter = new ExtensionFileFilter();
1257                Iterator extIter = corpusFiller.getExtensions().iterator();
1258                while(extIter.hasNext()){
1259                  filter.addExtension((String)extIter.next());
1260                }
1261              }
1262              ((Corpus)target).populate(url, filter,
1263                                        corpusFiller.getEncoding(),
1264                                        corpusFiller.isRecurseDirectories());
1265              long endTime = System.currentTimeMillis();
1266              fireStatusChanged("Corpus populated in " +
1267                      NumberFormat.getInstance().
1268                      format((double)(endTime - startTime) / 1000) +
1269                      " seconds!");
1270
1271            }catch(MalformedURLException mue){
1272              JOptionPane.showMessageDialog(getLargeView(),
1273                                            "Invalid URL!\n " +
1274                                            "See \"Messages\" tab for details!",
1275                                            "GATE", JOptionPane.ERROR_MESSAGE);
1276              mue.printStackTrace(Err.getPrintWriter());
1277            }catch(IOException ioe){
1278              JOptionPane.showMessageDialog(getLargeView(),
1279                                            "I/O error!\n " +
1280                                            "See \"Messages\" tab for details!",
1281                                            "GATE", JOptionPane.ERROR_MESSAGE);
1282              ioe.printStackTrace(Err.getPrintWriter());
1283            }catch(ResourceInstantiationException rie){
1284              JOptionPane.showMessageDialog(getLargeView(),
1285                                            "Could not create document!\n " +
1286                                            "See \"Messages\" tab for details!",
1287                                            "GATE", JOptionPane.ERROR_MESSAGE);
1288              rie.printStackTrace(Err.getPrintWriter());
1289            }
1290          }
1291        }
1292      };
1293      Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
1294                                 runnable);
1295      thread.setPriority(Thread.MIN_PRIORITY);
1296      thread.start();
1297    }
1298  }
1299
1300  class CreateIndexAction1 extends AbstractAction {
1301    CreateIndexAction1() {
1302      super("Create Index");
1303      putValue(SHORT_DESCRIPTION,
1304               "Create index with documents from a corpus");
1305    }
1306
1307    public void actionPerformed(ActionEvent e) {
1308      CreateIndexDialog cid = null;
1309      if (getWindow() instanceof Frame){
1310        cid = new CreateIndexDialog((Frame) getWindow(), (IndexedCorpus) target);
1311      }
1312      if (getWindow() instanceof Dialog){
1313        cid = new CreateIndexDialog((Dialog) getWindow(), (IndexedCorpus) target);
1314      }
1315      cid.setVisible(true);
1316    }
1317  }
1318
1319  class CreateIndexAction extends AbstractAction {
1320    CreateIndexAction() {
1321      super("Index corpus");
1322      putValue(SHORT_DESCRIPTION,
1323               "Create index with documents from the corpus");
1324      createIndexGui = new CreateIndexGUI();
1325    }
1326
1327    public void actionPerformed(ActionEvent e) {
1328      boolean ok = OkCancelDialog.showDialog(largeView,
1329                                             createIndexGui,
1330                                             "Index \"" + target.getName() +
1331                                             "\" corpus");
1332      if(ok){
1333        DefaultIndexDefinition did = new DefaultIndexDefinition();
1334        IREngine engine = createIndexGui.getIREngine();
1335        did.setIrEngineClassName(engine.getClass().getName());
1336
1337        did.setIndexLocation(createIndexGui.getIndexLocation().toString());
1338
1339        //add the content if wanted
1340        if(createIndexGui.getUseDocumentContent()){
1341          did.addIndexField(new IndexField("body",
1342                                           new DocumentContentReader(),
1343                                           false));
1344        }
1345        //add all the features
1346        Iterator featIter = createIndexGui.getFeaturesList().iterator();
1347        while(featIter.hasNext()){
1348          String featureName = (String)featIter.next();
1349          did.addIndexField(new IndexField(featureName,
1350                                           new FeatureReader(featureName),
1351                                           false));
1352        }
1353
1354        ((IndexedCorpus)target).setIndexDefinition(did);
1355
1356        Thread thread = new Thread(new Runnable(){
1357          public void run(){
1358            try {
1359              fireProgressChanged(1);
1360              fireStatusChanged("Indexing corpus...");
1361              long start = System.currentTimeMillis();
1362              ((IndexedCorpus)target).getIndexManager().deleteIndex();
1363              fireProgressChanged(10);
1364              ((IndexedCorpus)target).getIndexManager().createIndex();
1365              fireProgressChanged(100);
1366              fireProcessFinished();
1367              fireStatusChanged(
1368                "Corpus indexed in " + NumberFormat.getInstance().format(
1369                (double)(System.currentTimeMillis() - start) / 1000) +
1370                " seconds");
1371            } catch (IndexException ie){
1372              JOptionPane.showMessageDialog(getLargeView() != null ?
1373                                            getLargeView() : getSmallView(),
1374                                            "Could not create index!\n " +
1375                                            "See \"Messages\" tab for details!",
1376                                            "GATE", JOptionPane.ERROR_MESSAGE);
1377              ie.printStackTrace(Err.getPrintWriter());
1378            }finally{
1379              fireProcessFinished();
1380            }
1381          }
1382        });
1383        thread.setPriority(Thread.MIN_PRIORITY);
1384        thread.start();
1385      }
1386    }
1387    CreateIndexGUI createIndexGui;
1388  }
1389
1390  class OptimizeIndexAction extends AbstractAction {
1391    OptimizeIndexAction() {
1392      super("Optimize Index");
1393      putValue(SHORT_DESCRIPTION,
1394               "Optimize existing index");
1395    }
1396
1397    public boolean isEnabled(){
1398      return ((IndexedCorpus)target).getIndexDefinition() != null;
1399    }
1400
1401    public void actionPerformed(ActionEvent e) {
1402      IndexedCorpus ic = (IndexedCorpus) target;
1403      Thread thread = new Thread(new Runnable(){
1404        public void run(){
1405          try{
1406            fireProgressChanged(1);
1407            fireStatusChanged("Optimising index...");
1408            long start  = System.currentTimeMillis();
1409            ((IndexedCorpus)target).getIndexManager().optimizeIndex();
1410            fireStatusChanged(
1411              "Index optimised in " + NumberFormat.getInstance().format(
1412              (double)(System.currentTimeMillis() - start) / 1000) +
1413              " seconds");
1414            fireProcessFinished();
1415          }catch(IndexException ie){
1416            JOptionPane.showMessageDialog(getLargeView() != null ?
1417                                          getLargeView() : getSmallView(),
1418                                          "Errors during optimisation!",
1419                                          "GATE",
1420                                          JOptionPane.PLAIN_MESSAGE);
1421            ie.printStackTrace(Err.getPrintWriter());
1422          }finally{
1423            fireProcessFinished();
1424          }
1425        }
1426      });
1427      thread.setPriority(Thread.MIN_PRIORITY);
1428      thread.start();
1429    }
1430  }
1431
1432  class DeleteIndexAction extends AbstractAction {
1433    DeleteIndexAction() {
1434      super("Delete Index");
1435      putValue(SHORT_DESCRIPTION,
1436               "Delete existing index");
1437    }
1438
1439    public boolean isEnabled(){
1440      return ((IndexedCorpus)target).getIndexDefinition() != null;
1441    }
1442
1443    public void actionPerformed(ActionEvent e) {
1444      int answer = JOptionPane.showOptionDialog(
1445              getLargeView() != null ? getLargeView() : getSmallView(),
1446              "Do you want to delete index?", "Gate",
1447              JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
1448              null, null, null);
1449      if (answer == JOptionPane.YES_OPTION) {
1450        try {
1451          IndexedCorpus ic = (IndexedCorpus) target;
1452          if (ic.getIndexManager() != null){
1453            ic.getIndexManager().deleteIndex();
1454            ic.getFeatures().remove(GateConstants.
1455                                    CORPUS_INDEX_DEFINITION_FEATURE_KEY);
1456          } else {
1457            JOptionPane.showMessageDialog(getLargeView() != null ?
1458                                     getLargeView() :
1459                                     getSmallView(),
1460                                     "There is no index to delete!",
1461                                     "GATE", JOptionPane.PLAIN_MESSAGE);
1462          }
1463        } catch (gate.creole.ir.IndexException ie) {
1464          ie.printStackTrace();
1465        }
1466      }
1467    }
1468  }
1469
1470  /**
1471   * Releases the memory, removes the listeners, cleans up.
1472   * Will get called when the target resource is unloaded from the system
1473   */
1474  protected void cleanup(){
1475    //delete all the VRs that were created
1476    if(largeView != null){
1477      if(largeView instanceof VisualResource){
1478        //we only had a view so no tabbed pane was used
1479        Factory.deleteResource((VisualResource)largeView);
1480      }else{
1481        Component vrs[] = ((JTabbedPane)largeView).getComponents();
1482        for(int i = 0; i < vrs.length; i++){
1483          if(vrs[i] instanceof VisualResource){
1484            Factory.deleteResource((VisualResource)vrs[i]);
1485          }
1486        }
1487      }
1488    }
1489
1490    if(smallView != null){
1491      if(smallView instanceof VisualResource){
1492        //we only had a view so no tabbed pane was used
1493        Factory.deleteResource((VisualResource)smallView);
1494      }else{
1495        Component vrs[] = ((JTabbedPane)smallView).getComponents();
1496        for(int i = 0; i < vrs.length; i++){
1497          if(vrs[i] instanceof VisualResource){
1498            Factory.deleteResource((VisualResource)vrs[i]);
1499          }
1500        }
1501      }
1502    }
1503
1504    Gate.getCreoleRegister().removeCreoleListener(this);
1505    target = null;
1506  }
1507
1508  class ProxyStatusListener implements StatusListener{
1509    public void statusChanged(String text){
1510      fireStatusChanged(text);
1511    }
1512  }
1513
1514  protected void fireProgressChanged(int e) {
1515    if (progressListeners != null) {
1516      Vector listeners = progressListeners;
1517      int count = listeners.size();
1518      for (int i = 0; i < count; i++) {
1519        ((ProgressListener) listeners.elementAt(i)).progressChanged(e);
1520      }
1521    }
1522  }//protected void fireProgressChanged(int e)
1523
1524  protected void fireProcessFinished() {
1525    if (progressListeners != null) {
1526      Vector listeners = progressListeners;
1527      int count = listeners.size();
1528      for (int i = 0; i < count; i++) {
1529        ((ProgressListener) listeners.elementAt(i)).processFinished();
1530      }
1531    }
1532  }//protected void fireProcessFinished()
1533
1534  public synchronized void removeStatusListener(StatusListener l) {
1535    if (statusListeners != null && statusListeners.contains(l)) {
1536      Vector v = (Vector) statusListeners.clone();
1537      v.removeElement(l);
1538      statusListeners = v;
1539    }
1540  }//public synchronized void removeStatusListener(StatusListener l)
1541
1542  public synchronized void addStatusListener(StatusListener l) {
1543    Vector v = statusListeners == null ? new Vector(2) : (Vector) statusListeners.clone();
1544    if (!v.contains(l)) {
1545      v.addElement(l);
1546      statusListeners = v;
1547    }
1548  }//public synchronized void addStatusListener(StatusListener l)
1549
1550  protected void fireStatusChanged(String e) {
1551    if (statusListeners != null) {
1552      Vector listeners = statusListeners;
1553      int count = listeners.size();
1554      for (int i = 0; i < count; i++) {
1555        ((StatusListener) listeners.elementAt(i)).statusChanged(e);
1556      }
1557    }
1558  }
1559
1560  public void statusChanged(String e) {
1561    fireStatusChanged(e);
1562  }
1563  public void progressChanged(int e) {
1564    fireProgressChanged(e);
1565  }
1566  public void processFinished() {
1567    fireProcessFinished();
1568  }
1569  public Window getWindow() {
1570    return window;
1571  }
1572
1573  public void resourceLoaded(CreoleEvent e) {
1574  }
1575
1576  public void resourceUnloaded(CreoleEvent e) {
1577    if(getTarget() == e.getResource()) cleanup();
1578
1579  }
1580
1581  public void resourceRenamed(Resource resource, String oldName,
1582                              String newName){
1583    if(target == resource) title = target.getName();
1584  }
1585
1586  public void datastoreOpened(CreoleEvent e) {
1587  }
1588
1589  public void datastoreCreated(CreoleEvent e) {
1590  }
1591
1592  public void datastoreClosed(CreoleEvent e) {
1593    if(getTarget() == e.getDatastore()) cleanup();
1594  }
1595}//class DefaultResourceHandle
1596