1   /*
2    *  Copyright (c) 1998-2001, The University of Sheffield.
3    *
4    *  This file is part of GATE (see http://gate.ac.uk/), and is free
5    *  software, licenced under the GNU Library General Public License,
6    *  Version 2, June 1991 (in the distribution as file licence.html,
7    *  and also available at http://gate.ac.uk/gate/licence.html).
8    *
9    *  Valentin Tablan 23/01/2001
10   *
11   *  $Id: NameBearerHandle.java,v 1.50 2002/03/07 18:22:43 valyt Exp $
12   *
13   */
14  
15  package gate.gui;
16  
17  import javax.swing.*;
18  import java.util.*;
19  import java.net.*;
20  import java.awt.Component;
21  import java.awt.Window;
22  import java.awt.event.*;
23  import java.text.NumberFormat;
24  import java.io.*;
25  import javax.swing.filechooser.FileFilter;
26  
27  import gate.*;
28  import gate.util.*;
29  import gate.swing.*;
30  import gate.creole.*;
31  import gate.persist.*;
32  import gate.event.*;
33  import gate.security.*;
34  import gate.security.SecurityException;
35  
36  /**
37   * Class used to store the GUI information about an open entity (resource,
38   * controller, datastore).
39   * Such information will include icon to be used for tree components,
40   * popup menu for right click events, large and small views, etc.
41   */
42  public class NameBearerHandle implements Handle,
43                                           StatusListener,
44                                           ProgressListener, CreoleListener {
45  
46    public NameBearerHandle(NameBearer target, Window window) {
47      this.target = target;
48      this.window = window;
49      sListenerProxy = new ProxyStatusListener();
50      String iconName = null;
51      if(target instanceof Resource){
52        rData = (ResourceData)Gate.getCreoleRegister().
53                                                get(target.getClass().getName());
54        if(rData != null){
55          iconName = rData.getIcon();
56          if(iconName == null){
57            if(target instanceof LanguageResource) iconName = "lr.gif";
58            else if(target instanceof ProcessingResource) iconName = "pr.gif";
59            else if(target instanceof Controller) iconName = "controller.gif";
60          }
61          tooltipText = "<HTML> <b>" + rData.getComment() + "</b><br>(<i>" +
62                        rData.getClassName() + "</i>)</HTML>";
63        } else {
64          this.icon = MainFrame.getIcon("lr.gif");
65        }
66      }else if(target instanceof DataStore){
67        iconName = ((DataStore)target).getIconName();
68        tooltipText = ((DataStore)target).getComment();
69      }
70  
71      popup = null;
72      title = (String)target.getName();
73      this.icon = MainFrame.getIcon(iconName);
74  
75      Gate.getCreoleRegister().addCreoleListener(this);
76      buildViews();
77      // Add the CTRL +F4 key & action combination to the resource
78      JComponent largeView = this.getLargeView();
79      if (largeView != null){
80        largeView.getActionMap().put("Close resource",
81                          new CloseAction());
82        if (target instanceof gate.corpora.DocumentImpl){
83          largeView.getActionMap().put("Save As XML", new SaveAsXmlAction());
84        }// End if
85      }// End if
86    }//public DefaultResourceHandle(FeatureBearer res)
87  
88    public Icon getIcon(){
89      return icon;
90    }
91  
92    public void setIcon(Icon icon){
93      this.icon = icon;
94    }
95  
96    public String getTitle(){
97      return title;
98    }
99  
100   public void setTitle(String newTitle){
101     this.title = newTitle;
102   }
103 
104   /**
105    * Returns a GUI component to be used as a small viewer/editor, e.g. below
106    * the main tree in the Gate GUI for the selected resource
107    */
108   public JComponent getSmallView() {
109     return smallView;
110   }
111 
112   /**
113    * Returns the large view for this resource. This view will go into the main
114    * display area.
115    */
116   public JComponent getLargeView() {
117     return largeView;
118   }
119 
120   public JPopupMenu getPopup() {
121     return popup;
122   }
123 
124   public void setPopup(JPopupMenu popup) {
125     this.popup = popup;
126   }
127 
128   public String getTooltipText() {
129     return tooltipText;
130   }
131 
132   public void setTooltipText(String text) {
133     this.tooltipText = text;
134   }
135 
136   public Object getTarget() {
137     return target;
138   }
139 
140   public Action getCloseAction(){
141     return new CloseAction();
142   }
143   protected void buildViews() {
144     //build the popup
145     popup = new JPopupMenu();
146     XJMenuItem closeItem = new XJMenuItem(new CloseAction(), sListenerProxy);
147     closeItem.setAccelerator(KeyStroke.getKeyStroke(
148                                 KeyEvent.VK_F4, ActionEvent.CTRL_MASK));
149     popup.add(closeItem);
150 
151     if(target instanceof ProcessingResource){
152       popup.addSeparator();
153       popup.add(new XJMenuItem(new ReloadAction(), sListenerProxy));
154     }else if(target instanceof LanguageResource) {
155       //Language Resources
156       popup.addSeparator();
157       popup.add(new XJMenuItem(new SaveAction(), sListenerProxy));
158       popup.add(new XJMenuItem(new SaveToAction(), sListenerProxy));
159       if(target instanceof gate.corpora.DocumentImpl){
160         XJMenuItem saveAsXmlItem =
161                          new XJMenuItem(new SaveAsXmlAction(), sListenerProxy);
162         saveAsXmlItem.setAccelerator(KeyStroke.getKeyStroke(
163                                         KeyEvent.VK_X, ActionEvent.CTRL_MASK));
164 
165         popup.add(saveAsXmlItem);
166         XJMenuItem savePreserveFormatItem =
167                          new XJMenuItem(new DumpPreserveFormatAction(),
168                                         sListenerProxy);
169         popup.add(savePreserveFormatItem);
170       }else if(target instanceof Corpus){
171         popup.addSeparator();
172         corpusFiller = new CorpusFillerComponent();
173         popup.add(new XJMenuItem(new PopulateCorpusAction(), sListenerProxy));
174         popup.addSeparator();
175         popup.add(new XJMenuItem(new SaveCorpusAsXmlAction(), sListenerProxy));
176       }
177     }else if(target instanceof Controller){
178       //Applications
179       popup.addSeparator();
180       popup.add(new XJMenuItem(new DumpToFileAction(), sListenerProxy));
181     }
182 
183     fireStatusChanged("Building views...");
184 
185     //build the large views
186     List largeViewNames = Gate.getCreoleRegister().
187                           getLargeVRsForResource(target.getClass().getName());
188     if(largeViewNames != null && !largeViewNames.isEmpty()){
189       largeView = new JTabbedPane(JTabbedPane.BOTTOM);
190       Iterator classNameIter = largeViewNames.iterator();
191       while(classNameIter.hasNext()){
192         try{
193           String className = (String)classNameIter.next();
194           ResourceData rData = (ResourceData)Gate.getCreoleRegister().
195                                                   get(className);
196           FeatureMap params = Factory.newFeatureMap();
197           FeatureMap features = Factory.newFeatureMap();
198           Gate.setHiddenAttribute(features, true);
199           VisualResource view = (VisualResource)
200                                 Factory.createResource(className,
201                                                        params,
202                                                        features);
203           view.setTarget(target);
204           view.setHandle(this);
205           ((JTabbedPane)largeView).add((Component)view, rData.getName());
206         }catch(ResourceInstantiationException rie){
207           rie.printStackTrace(Err.getPrintWriter());
208         }
209       }
210       if(largeViewNames.size() == 1){
211         largeView = (JComponent)((JTabbedPane)largeView).getComponentAt(0);
212       }else{
213         ((JTabbedPane)largeView).setSelectedIndex(0);
214       }
215     }
216 
217     //build the small views
218     List smallViewNames = Gate.getCreoleRegister().
219                           getSmallVRsForResource(target.getClass().getName());
220     if(smallViewNames != null && !smallViewNames.isEmpty()){
221       smallView = new JTabbedPane(JTabbedPane.BOTTOM);
222       Iterator classNameIter = smallViewNames.iterator();
223       while(classNameIter.hasNext()){
224         try{
225           String className = (String)classNameIter.next();
226           ResourceData rData = (ResourceData)Gate.getCreoleRegister().
227                                                   get(className);
228           FeatureMap params = Factory.newFeatureMap();
229           FeatureMap features = Factory.newFeatureMap();
230           Gate.setHiddenAttribute(features, true);
231           VisualResource view = (VisualResource)
232                                 Factory.createResource(className,
233                                                        params,
234                                                        features);
235           view.setTarget(target);
236           view.setHandle(this);
237           ((JTabbedPane)smallView).add((Component)view, rData.getName());
238         }catch(ResourceInstantiationException rie){
239           rie.printStackTrace(Err.getPrintWriter());
240         }
241       }
242       if(smallViewNames.size() == 1){
243         smallView = (JComponent)((JTabbedPane)smallView).getComponentAt(0);
244       }else{
245         ((JTabbedPane)smallView).setSelectedIndex(0);
246       }
247     }
248     fireStatusChanged("Views built!");
249   }//protected void buildViews
250 
251   public String toString(){ return title;}
252 
253   public synchronized void removeProgressListener(ProgressListener l) {
254     if (progressListeners != null && progressListeners.contains(l)) {
255       Vector v = (Vector) progressListeners.clone();
256       v.removeElement(l);
257       progressListeners = v;
258     }
259   }//public synchronized void removeProgressListener(ProgressListener l)
260 
261   public synchronized void addProgressListener(ProgressListener l) {
262     Vector v = progressListeners == null ? new Vector(2) : (Vector) progressListeners.clone();
263     if (!v.contains(l)) {
264       v.addElement(l);
265       progressListeners = v;
266     }
267   }//public synchronized void addProgressListener(ProgressListener l)
268 
269   JPopupMenu popup;
270   String title;
271   String tooltipText;
272   NameBearer target;
273   /**
274    * The top level GUI component this hadle belongs to.
275    */
276   Window window;
277   ResourceData rData;
278   Icon icon;
279   JComponent smallView;
280   JComponent largeView;
281 
282   /**
283    * Component used to select the options for corpus populating
284    */
285   CorpusFillerComponent corpusFiller;
286 
287   StatusListener sListenerProxy;
288 
289 //  File currentDir = null;
290   private transient Vector progressListeners;
291   private transient Vector statusListeners;
292 
293   class CloseAction extends AbstractAction {
294     public CloseAction() {
295       super("Close");
296       putValue(SHORT_DESCRIPTION, "Removes this resource from the system");
297     }
298 
299     public void actionPerformed(ActionEvent e){
300       if(target instanceof Resource){
301         Factory.deleteResource((Resource)target);
302       }else if(target instanceof DataStore){
303         try{
304           ((DataStore)target).close();
305         } catch(PersistenceException pe){
306           JOptionPane.showMessageDialog(largeView != null ?
307                                                      largeView : smallView,
308                                         "Error!\n" + pe.toString(),
309                                         "Gate", JOptionPane.ERROR_MESSAGE);
310         }
311       }
312 
313       statusListeners.clear();
314       progressListeners.clear();
315 //      //delete the viewers
316 //      if(largeView instanceof VisualResource){
317 //        Factory.deleteResource((VisualResource)largeView);
318 //      }else if(largeView instanceof JTabbedPane){
319 //        Component[] comps = ((JTabbedPane)largeView).getComponents();
320 //        for(int i = 0; i < comps.length; i++){
321 //          if(comps[i] instanceof VisualResource)
322 //            Factory.deleteResource((VisualResource)comps[i]);
323 //        }
324 //      }
325 //      if(smallView instanceof VisualResource){
326 //        Factory.deleteResource((VisualResource)smallView);
327 //      }else if(smallView instanceof JTabbedPane){
328 //        Component[] comps = ((JTabbedPane)smallView).getComponents();
329 //        for(int i = 0; i < comps.length; i++){
330 //          if(comps[i] instanceof VisualResource)
331 //            Factory.deleteResource((VisualResource)comps[i]);
332 //        }
333 //      }
334 //
335     }//public void actionPerformed(ActionEvent e)
336   }//class CloseAction
337 
338   /**
339    * Used to save a document as XML
340    */
341   class SaveAsXmlAction extends AbstractAction {
342     public SaveAsXmlAction(){
343       super("Save As Xml...");
344       putValue(SHORT_DESCRIPTION, "Saves this resource in XML");
345     }// SaveAsXmlAction()
346 
347     public void actionPerformed(ActionEvent e) {
348       Runnable runableAction = new Runnable(){
349         public void run(){
350           JFileChooser fileChooser = MainFrame.getFileChooser();
351           File selectedFile = null;
352 
353           List filters = Arrays.asList(fileChooser.getChoosableFileFilters());
354           Iterator filtersIter = filters.iterator();
355           FileFilter filter = null;
356           if(filtersIter.hasNext()){
357             filter = (FileFilter)filtersIter.next();
358             while(filtersIter.hasNext() &&
359                   filter.getDescription().indexOf("XML") == -1){
360               filter = (FileFilter)filtersIter.next();
361             }
362           }
363           if(filter == null || filter.getDescription().indexOf("XML") == -1){
364             //no suitable filter found, create a new one
365             ExtensionFileFilter xmlFilter = new ExtensionFileFilter();
366             xmlFilter.setDescription("XML files");
367             xmlFilter.addExtension("xml");
368             xmlFilter.addExtension("gml");
369             fileChooser.addChoosableFileFilter(xmlFilter);
370             filter = xmlFilter;
371           }
372           fileChooser.setFileFilter(filter);
373 
374           fileChooser.setMultiSelectionEnabled(false);
375           fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
376           fileChooser.setDialogTitle("Select document to save ...");
377           fileChooser.setSelectedFiles(null);
378 
379           int res = (getLargeView() != null) ?
380                                   fileChooser.showDialog(getLargeView(), "Save"):
381                     (getSmallView() != null) ?
382                                   fileChooser.showDialog(getSmallView(), "Save") :
383                                               fileChooser.showDialog(null, "Save");
384           if(res == JFileChooser.APPROVE_OPTION){
385             selectedFile = fileChooser.getSelectedFile();
386             File currentDir = fileChooser.getCurrentDirectory();
387             if(selectedFile == null) return;
388             NameBearerHandle.this.statusChanged("Saving as XML to " +
389              selectedFile.toString() + "...");
390             try{
391               MainFrame.lockGUI("Saving...");
392               // Prepare to write into the xmlFile using UTF-8 encoding
393               OutputStreamWriter writer = new OutputStreamWriter(
394                               new FileOutputStream(selectedFile),"UTF-8");
395 
396               // Write (test the toXml() method)
397               // This Action is added only when a gate.Document is created.
398               // So, is for sure that the resource is a gate.Document
399               writer.write(((gate.Document)target).toXml());
400               writer.flush();
401               writer.close();
402             } catch (Exception ex){
403               ex.printStackTrace(Out.getPrintWriter());
404             }finally{
405               MainFrame.unlockGUI();
406             }
407             NameBearerHandle.this.statusChanged("Finished saving as xml into "+
408              " the file : "+ selectedFile.toString());
409           }// End if
410         }// End run()
411       };// End Runnable
412       Thread thread = new Thread(runableAction, "");
413       thread.setPriority(Thread.MIN_PRIORITY);
414       thread.start();
415     }// actionPerformed()
416   }// SaveAsXmlAction
417 
418   /**
419    * The action that is fired when the user wants to dump annotations
420    * preserving the original document format.
421    */
422   protected class DumpPreserveFormatAction extends AbstractAction{
423 //    private Set annotationsToDump = null;
424 
425     public DumpPreserveFormatAction(){
426       super("Save preserving document format");
427     }
428 
429 
430     /** This method takes care of how the dumping is done*/
431     public void actionPerformed(ActionEvent e){
432       Runnable runableAction = new Runnable(){
433         public void run(){
434           JFileChooser fileChooser = MainFrame.getFileChooser();
435           File selectedFile = null;
436 
437           fileChooser.setMultiSelectionEnabled(false);
438           fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
439           fileChooser.setDialogTitle("Select document to save ...");
440           fileChooser.setSelectedFiles(null);
441 
442           int res = (getLargeView() != null) ?
443                                   fileChooser.showDialog(getLargeView(), "Save"):
444                     (getSmallView() != null) ?
445                                   fileChooser.showDialog(getSmallView(), "Save") :
446                                               fileChooser.showDialog(null, "Save");
447           if(res == JFileChooser.APPROVE_OPTION){
448             selectedFile = fileChooser.getSelectedFile();
449             fileChooser.setCurrentDirectory(fileChooser.getCurrentDirectory());
450             if(selectedFile == null) return;
451             if (NameBearerHandle.this!= null)
452               NameBearerHandle.this.statusChanged("Please wait while dumping annotations"+
453               "in the original format to " + selectedFile.toString() + " ...");
454             // This method construct a set with all annotations that need to be
455             // dupmped as Xml. If the set is null then only the original markups
456             // are dumped.
457             Set annotationsToDump = null;
458             //find the shown document editor. If none, just dump the original
459             //markup annotations, i.e., leave the annotationsToDump null
460             if (largeView instanceof JTabbedPane) {
461               Component shownComponent =
462                 ((JTabbedPane) largeView).getSelectedComponent();
463               if (shownComponent instanceof DocumentEditor) {
464                 //so we only get annotations for dumping if they are shown in the
465                 //table of the document editor, which is currently in front
466                 //of the user
467                 annotationsToDump =
468                   ((DocumentEditor) shownComponent).getDisplayedAnnotations();
469               }//if we have a document editor
470             }//if tabbed pane
471             try{
472               // Prepare to write into the xmlFile using UTF-8 encoding
473               OutputStreamWriter writer = new OutputStreamWriter(
474                                     new FileOutputStream(selectedFile),"UTF-8");
475 
476               //determine if the features need to be saved first
477               Boolean featuresSaved =
478                   Gate.getUserConfig().getBoolean(
479                     GateConstants.SAVE_FEATURES_WHEN_PRESERVING_FORMAT);
480               boolean saveFeatures = true;
481               if (featuresSaved != null)
482                 saveFeatures = featuresSaved.booleanValue();
483               // Write with the toXml() method
484               writer.write(
485                 ((gate.Document)target).toXml(annotationsToDump, saveFeatures));
486               writer.flush();
487               writer.close();
488             } catch (Exception ex){
489               ex.printStackTrace(Out.getPrintWriter());
490             }// End try
491             if (NameBearerHandle.this!= null)
492               NameBearerHandle.this.statusChanged("Finished dumping into the "+
493               "file : " + selectedFile.toString());
494           }// End if
495         }// End run()
496       };// End Runnable
497       Thread thread = new Thread(runableAction, "");
498       thread.setPriority(Thread.MIN_PRIORITY);
499       thread.start();
500     }//public void actionPerformed(ActionEvent e)
501 
502   }//class DumpPreserveFormatAction
503 
504 
505   /**
506    * Saves a corpus as a set of xml files in a directory.
507    */
508   class SaveCorpusAsXmlAction extends AbstractAction {
509     public SaveCorpusAsXmlAction(){
510       super("Save As Xml...");
511       putValue(SHORT_DESCRIPTION, "Saves this corpus in XML");
512     }// SaveAsXmlAction()
513 
514     public void actionPerformed(ActionEvent e) {
515       Runnable runnable = new Runnable(){
516         public void run(){
517           try{
518             //we need a directory
519             JFileChooser filer = MainFrame.getFileChooser();
520             filer.setDialogTitle(
521                 "Select the directory that will contain the corpus");
522             filer.setFileSelectionMode(filer.DIRECTORIES_ONLY);
523             filer.setFileFilter(filer.getAcceptAllFileFilter());
524 
525             if (filer.showDialog(getLargeView() != null ?
526                                      getLargeView() :
527                                      getSmallView(),
528                                      "Select") == filer.APPROVE_OPTION){
529 
530               File dir = filer.getSelectedFile();
531               //create the top directory if needed
532               if(!dir.exists()){
533                 if(!dir.mkdirs()){
534                   JOptionPane.showMessageDialog(
535                     largeView != null ?largeView : smallView,
536                     "Could not create top directory!",
537                     "Gate", JOptionPane.ERROR_MESSAGE);
538                   return;
539                 }
540               }
541 
542               MainFrame.lockGUI("Saving...");
543 
544               //iterate through all the docs and save each of them as xml
545               Corpus corpus = (Corpus)target;
546               Iterator docIter = corpus.iterator();
547               boolean overwriteAll = false;
548               int docCnt = corpus.size();
549               int currentDocIndex = 0;
550               while(docIter.hasNext()){
551                 Document currentDoc = (Document)docIter.next();
552                 URL sourceURL = currentDoc.getSourceUrl();
553                 String fileName = null;
554                 if(sourceURL != null){
555                   fileName = sourceURL.getFile();
556                   fileName = Files.getLastPathComponent(fileName);
557                 }
558                 if(fileName == null || fileName.length() == 0){
559                   fileName = currentDoc.getName();
560                 }
561                 if(!fileName.toLowerCase().endsWith(".xml")) fileName += ".xml";
562                 File docFile = null;
563                 boolean nameOK = false;
564                 do{
565                   docFile = new File(dir, fileName);
566                   if(docFile.exists() && !overwriteAll){
567                     //ask the user if we can ovewrite the file
568                     Object[] options = new Object[] {"Yes", "All",
569                                                      "No", "Cancel"};
570                     MainFrame.unlockGUI();
571                     int answer = JOptionPane.showOptionDialog(
572                       largeView != null ? largeView : smallView,
573                       "File " + docFile.getName() + " already exists!\n" +
574                       "Overwrite?" ,
575                       "Gate", JOptionPane.DEFAULT_OPTION,
576                       JOptionPane.WARNING_MESSAGE, null, options, options[2]);
577                     MainFrame.lockGUI("Saving...");
578                     switch(answer){
579                       case 0: {
580                         nameOK = true;
581                         break;
582                       }
583                       case 1: {
584                         nameOK = true;
585                         overwriteAll = true;
586                         break;
587                       }
588                       case 2: {
589                         //user said NO, allow them to provide an alternative name;
590                         MainFrame.unlockGUI();
591                         fileName = (String)JOptionPane.showInputDialog(
592                             largeView != null ? largeView : smallView,
593                             "Please provide an alternative file name",
594                             "Gate", JOptionPane.QUESTION_MESSAGE,
595                             null, null, fileName);
596                         if(fileName == null){
597                           fireProcessFinished();
598                           return;
599                         }
600                         MainFrame.lockGUI("Saving");
601                         break;
602                       }
603                       case 3: {
604                         //user gave up; return
605                         fireProcessFinished();
606                         return;
607                       }
608                     }
609 
610                   }else{
611                     nameOK = true;
612                   }
613                 }while(!nameOK);
614                 //save the file
615                 try{
616                   OutputStreamWriter writer = new OutputStreamWriter(
617                                 new FileOutputStream(docFile),"UTF-8");
618                   writer.write(currentDoc.toXml());
619                   writer.flush();
620                   writer.close();
621                 }catch(IOException ioe){
622                   MainFrame.unlockGUI();
623                   JOptionPane.showMessageDialog(
624                     largeView != null ? largeView : smallView,
625                     "Could not create write file:" +
626                     ioe.toString(),
627                     "Gate", JOptionPane.ERROR_MESSAGE);
628                   ioe.printStackTrace(Err.getPrintWriter());
629                   return;
630                 }
631 
632                 fireStatusChanged(currentDoc.getName() + " saved");
633                 fireProgressChanged(100 * currentDocIndex++ / docCnt);
634               }//while(docIter.hasNext())
635               fireStatusChanged("Corpus saved");
636               fireProcessFinished();
637             }//select directory
638           }finally{
639             MainFrame.unlockGUI();
640           }
641         }//public void run(){
642       };//Runnable runnable = new Runnable()
643       Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
644                                  runnable, "Corpus XML dumper");
645       thread.setPriority(Thread.MIN_PRIORITY);
646       thread.start();
647 
648     }//public void actionPerformed(ActionEvent e)
649   }//class SaveCorpusAsXmlAction extends AbstractAction
650 
651   /**
652    * Saves a corpus as a set of xml files in a directory.
653    */
654   class ReloadClassAction extends AbstractAction {
655     public ReloadClassAction(){
656       super("Reload resource class");
657       putValue(SHORT_DESCRIPTION, "Reloads the java class for this resource");
658     }// SaveAsXmlAction()
659 
660     public void actionPerformed(ActionEvent e) {
661       int answer = JOptionPane.showOptionDialog(
662                 largeView != null ? largeView : smallView,
663                 "This is an advanced option!\n" +
664                 "You should not use this unless your name is Hamish.\n" +
665                 "Are you sure you want to do this?" ,
666                 "Gate", JOptionPane.YES_NO_OPTION,
667                 JOptionPane.WARNING_MESSAGE, null, null, null);
668       if(answer == JOptionPane.OK_OPTION){
669         try{
670           String className = target.getClass().getName();
671           Gate.getClassLoader().reloadClass(className);
672           fireStatusChanged("Class " + className + " reloaded!");
673         }catch(Exception ex){
674           JOptionPane.showMessageDialog(largeView != null ?
675                                         largeView : smallView,
676                                         "Look what you've done: \n" +
677                                         ex.toString() +
678                                         "\nI told you not to do it...",
679                                         "Gate", JOptionPane.ERROR_MESSAGE);
680           ex.printStackTrace(Err.getPrintWriter());
681         }
682       }
683     }
684   }
685 
686   class SaveAction extends AbstractAction {
687     public SaveAction(){
688       super("Save");
689       putValue(SHORT_DESCRIPTION, "Save back to the datastore");
690     }
691     public void actionPerformed(ActionEvent e){
692       Runnable runnable = new Runnable(){
693         public void run(){
694           DataStore ds = ((LanguageResource)target).getDataStore();
695           if(ds != null){
696             try {
697               MainFrame.lockGUI("Saving " + ((LanguageResource)target).getName());
698               StatusListener sListener = (StatusListener)
699                                          gate.gui.MainFrame.getListeners().
700                                          get("gate.event.StatusListener");
701               if(sListener != null) sListener.statusChanged(
702                 "Saving: " + ((LanguageResource)target).getName());
703               double timeBefore = System.currentTimeMillis();
704               ((LanguageResource)
705                         target).getDataStore().sync((LanguageResource)target);
706               double timeAfter = System.currentTimeMillis();
707               if(sListener != null) sListener.statusChanged(
708                 ((LanguageResource)target).getName() + " saved in " +
709                 NumberFormat.getInstance().format((timeAfter-timeBefore)/1000)
710                 + " seconds");
711             } catch(PersistenceException pe) {
712               MainFrame.unlockGUI();
713               JOptionPane.showMessageDialog(getLargeView(),
714                                             "Save failed!\n " +
715                                             pe.toString(),
716                                             "Gate", JOptionPane.ERROR_MESSAGE);
717             } catch(SecurityException se) {
718               MainFrame.unlockGUI();
719               JOptionPane.showMessageDialog(getLargeView(),
720                                             "Save failed!\n " +
721                                             se.toString(),
722                                             "Gate", JOptionPane.ERROR_MESSAGE);
723             }finally{
724               MainFrame.unlockGUI();
725             }
726           } else {
727             JOptionPane.showMessageDialog(getLargeView(),
728                             "This resource has not been loaded from a datastore.\n"+
729                              "Please use the \"Save to\" option!\n",
730                              "Gate", JOptionPane.ERROR_MESSAGE);
731 
732           }
733         }
734       };
735       new Thread(runnable).start();
736     }//public void actionPerformed(ActionEvent e)
737   }//class SaveAction
738 
739   class DumpToFileAction extends AbstractAction {
740     public DumpToFileAction(){
741       super("Save application state");
742       putValue(SHORT_DESCRIPTION,
743                "Saves the data needed to recreate this application");
744     }
745 
746     public void actionPerformed(ActionEvent ae){
747       JFileChooser fileChooser = MainFrame.getFileChooser();
748 
749       fileChooser.setDialogTitle("Select a file for this resource");
750       fileChooser.setFileSelectionMode(fileChooser.FILES_AND_DIRECTORIES);
751       if (fileChooser.showSaveDialog(largeView) ==
752                                             fileChooser.APPROVE_OPTION){
753         final File file = fileChooser.getSelectedFile();
754           Runnable runnable = new Runnable(){
755             public void run(){
756               try{
757                 gate.util.persistence.PersistenceManager.
758                                       saveObjectToFile((Resource)target, file);
759               }catch(Exception e){
760                 JOptionPane.showMessageDialog(getLargeView(),
761                                 "Error!\n"+
762                                  e.toString(),
763                                  "Gate", JOptionPane.ERROR_MESSAGE);
764                 e.printStackTrace(Err.getPrintWriter());
765               }
766             }
767           };
768           Thread thread = new Thread(runnable);
769           thread.setPriority(Thread.MIN_PRIORITY);
770           thread.start();
771       }
772     }
773 
774   }
775 
776   class SaveToAction extends AbstractAction {
777     public SaveToAction(){
778       super("Save to...");
779       putValue(SHORT_DESCRIPTION, "Save this resource to a datastore");
780     }
781 
782     public void actionPerformed(ActionEvent e) {
783       Runnable runnable = new Runnable(){
784         public void run(){
785           try {
786             DataStoreRegister dsReg = Gate.getDataStoreRegister();
787             Map dsByName =new HashMap();
788             Iterator dsIter = dsReg.iterator();
789             while(dsIter.hasNext()){
790               DataStore oneDS = (DataStore)dsIter.next();
791               String name;
792               if((name = (String)oneDS.getName()) != null){
793               } else {
794                 name  = oneDS.getStorageUrl();
795                 try {
796                   URL tempURL = new URL(name);
797                   name = tempURL.getFile();
798                 } catch (java.net.MalformedURLException ex) {
799                   throw new GateRuntimeException(
800                             );
801                 }
802               }
803               dsByName.put(name, oneDS);
804             }
805             List dsNames = new ArrayList(dsByName.keySet());
806             if(dsNames.isEmpty()){
807               JOptionPane.showMessageDialog(getLargeView(),
808                                             "There are no open datastores!\n " +
809                                             "Please open a datastore first!",
810                                             "Gate", JOptionPane.ERROR_MESSAGE);
811 
812             } else {
813               Object answer = JOptionPane.showInputDialog(
814                                   getLargeView(),
815                                   "Select the datastore",
816                                   "Gate", JOptionPane.QUESTION_MESSAGE,
817                                   null, dsNames.toArray(),
818                                   dsNames.get(0));
819               if(answer == null) return;
820               DataStore ds = (DataStore)dsByName.get(answer);
821               if (ds == null){
822                 Err.prln("The datastore does not exists. Saving procedure" +
823                                   " has FAILED! This should never happen again!");
824                 return;
825               }// End if
826               DataStore ownDS = ((LanguageResource)target).getDataStore();
827               if(ds == ownDS){
828                 MainFrame.lockGUI("Saving " + ((LanguageResource)target).getName());
829 
830                 StatusListener sListener = (StatusListener)
831                                            gate.gui.MainFrame.getListeners().
832                                            get("gate.event.StatusListener");
833                 if(sListener != null) sListener.statusChanged(
834                   "Saving: " + ((LanguageResource)target).getName());
835                 double timeBefore = System.currentTimeMillis();
836                 ds.sync((LanguageResource)target);
837                 double timeAfter = System.currentTimeMillis();
838                 if(sListener != null) sListener.statusChanged(
839                   ((LanguageResource)target).getName() + " saved in " +
840                   NumberFormat.getInstance().format((timeAfter-timeBefore)/1000)
841                   + " seconds");
842               }else{
843                 FeatureMap securityData = (FeatureMap)
844                              Gate.getDataStoreRegister().getSecurityData(ds);
845                 SecurityInfo si = null;
846                 //check whether the datastore supports security data
847                 //serial ones do not for example
848                 if (securityData != null) {
849                   //first get the type of access from the user
850                   if(!AccessRightsDialog.showDialog(window))
851                     return;
852                   int accessType = AccessRightsDialog.getSelectedMode();
853                   if(accessType < 0)
854                     return;
855                   si = new SecurityInfo(accessType,
856                                         (User) securityData.get("user"),
857                                         (Group) securityData.get("group"));
858                 }//if security info
859                 StatusListener sListener = (StatusListener)
860                                            gate.gui.MainFrame.getListeners().
861                                            get("gate.event.StatusListener");
862                 MainFrame.lockGUI("Saving " + ((LanguageResource)target).getName());
863 
864                 if(sListener != null) sListener.statusChanged(
865                   "Saving: " + ((LanguageResource)target).getName());
866                 double timeBefore = System.currentTimeMillis();
867                 LanguageResource lr = ds.adopt((LanguageResource)target,si);
868                 ds.sync(lr);
869                 double timeAfter = System.currentTimeMillis();
870                 if(sListener != null) sListener.statusChanged(
871                   ((LanguageResource)target).getName() + " saved in " +
872                   NumberFormat.getInstance().format((timeAfter-timeBefore)/1000)
873                   + " seconds");
874 
875                 //check whether the new LR is different from the transient one and
876                 //if so, unload the transient LR, so the user realises
877                 //it is no longer valid. Don't do this in the adopt() code itself
878                 //because the batch code might wish to keep the transient
879                 //resource for some purpose.
880                 if (lr != target) {
881                   Factory.deleteResource((LanguageResource)target);
882                 }
883               }
884             }
885           } catch(PersistenceException pe) {
886             MainFrame.unlockGUI();
887             JOptionPane.showMessageDialog(getLargeView(),
888                                           "Save failed!\n " +
889                                           pe.toString(),
890                                           "Gate", JOptionPane.ERROR_MESSAGE);
891           }catch(gate.security.SecurityException se) {
892             MainFrame.unlockGUI();
893             JOptionPane.showMessageDialog(getLargeView(),
894                                           "Save failed!\n " +
895                                           se.toString(),
896                                           "Gate", JOptionPane.ERROR_MESSAGE);
897           }finally{
898             MainFrame.unlockGUI();
899           }
900 
901         }
902       };
903       new Thread(runnable).start();
904     }
905   }//class SaveToAction extends AbstractAction
906 
907   class ReloadAction extends AbstractAction {
908     ReloadAction() {
909       super("Reinitialise");
910       putValue(SHORT_DESCRIPTION, "Reloads this resource");
911     }
912 
913     public void actionPerformed(ActionEvent e) {
914       Runnable runnable = new Runnable(){
915         public void run(){
916           if(!(target instanceof ProcessingResource)) return;
917           try{
918             long startTime = System.currentTimeMillis();
919             fireStatusChanged("Reinitialising " +
920                                target.getName());
921             Map listeners = new HashMap();
922             StatusListener sListener = new StatusListener(){
923                                         public void statusChanged(String text){
924                                           fireStatusChanged(text);
925                                         }
926                                        };
927             listeners.put("gate.event.StatusListener", sListener);
928 
929             ProgressListener pListener =
930                 new ProgressListener(){
931                   public void progressChanged(int value){
932                     fireProgressChanged(value);
933                   }
934                   public void processFinished(){
935                     fireProcessFinished();
936                   }
937                 };
938             listeners.put("gate.event.ProgressListener", pListener);
939 
940             ProcessingResource res = (ProcessingResource)target;
941             try{
942               AbstractResource.setResourceListeners(res, listeners);
943             }catch (Exception e){
944               e.printStackTrace(Err.getPrintWriter());
945             }
946             //show the progress indicator
947             fireProgressChanged(0);
948             //the actual reinitialisation
949             res.reInit();
950             try{
951               AbstractResource.removeResourceListeners(res, listeners);
952             }catch (Exception e){
953               e.printStackTrace(Err.getPrintWriter());
954             }
955             long endTime = System.currentTimeMillis();
956             fireStatusChanged(target.getName() +
957                               " reinitialised in " +
958                               NumberFormat.getInstance().format(
959                               (double)(endTime - startTime) / 1000) + " seconds");
960             fireProcessFinished();
961           }catch(ResourceInstantiationException rie){
962             fireStatusChanged("reinitialisation failed");
963             rie.printStackTrace(Err.getPrintWriter());
964             JOptionPane.showMessageDialog(getLargeView(),
965                                           "Reload failed!\n " +
966                                           "See \"Messages\" tab for details!",
967                                           "Gate", JOptionPane.ERROR_MESSAGE);
968             fireProcessFinished();
969           }
970         }//public void run()
971       };
972       Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
973                                  runnable,
974                                  "DefaultResourceHandle1");
975       thread.setPriority(Thread.MIN_PRIORITY);
976       thread.start();
977     }//public void actionPerformed(ActionEvent e)
978 
979   }//class ReloadAction
980 
981   class PopulateCorpusAction extends AbstractAction {
982     PopulateCorpusAction() {
983       super("Populate");
984       putValue(SHORT_DESCRIPTION,
985                "Fills this corpus with documents from a directory");
986     }
987 
988     public void actionPerformed(ActionEvent e) {
989       Runnable runnable = new Runnable(){
990         public void run(){
991           corpusFiller.setExtensions(new ArrayList());
992           corpusFiller.setEncoding("");
993           boolean answer = OkCancelDialog.showDialog(
994                                   getLargeView(),
995                                   corpusFiller,
996                                   "Select a directory and allowed extensions");
997           if(answer){
998             URL url = null;
999             try{
1000              url = new URL(corpusFiller.getUrlString());
1001              java.util.List extensions = corpusFiller.getExtensions();
1002              ExtensionFileFilter filter = null;
1003              if(extensions == null || extensions.isEmpty()) filter = null;
1004              else{
1005                filter = new ExtensionFileFilter();
1006                Iterator extIter = corpusFiller.getExtensions().iterator();
1007                while(extIter.hasNext()){
1008                  filter.addExtension((String)extIter.next());
1009                }
1010              }
1011              ((Corpus)target).populate(url, filter,
1012                                        corpusFiller.getEncoding(),
1013                                        corpusFiller.isRecurseDirectories());
1014              fireStatusChanged("Corpus populated!");
1015
1016            }catch(MalformedURLException mue){
1017              JOptionPane.showMessageDialog(getLargeView(),
1018                                            "Invalid URL!\n " +
1019                                            "See \"Messages\" tab for details!",
1020                                            "Gate", JOptionPane.ERROR_MESSAGE);
1021              mue.printStackTrace(Err.getPrintWriter());
1022            }catch(IOException ioe){
1023              JOptionPane.showMessageDialog(getLargeView(),
1024                                            "I/O error!\n " +
1025                                            "See \"Messages\" tab for details!",
1026                                            "Gate", JOptionPane.ERROR_MESSAGE);
1027              ioe.printStackTrace(Err.getPrintWriter());
1028            }catch(ResourceInstantiationException rie){
1029              JOptionPane.showMessageDialog(getLargeView(),
1030                                            "Could not create document!\n " +
1031                                            "See \"Messages\" tab for details!",
1032                                            "Gate", JOptionPane.ERROR_MESSAGE);
1033              rie.printStackTrace(Err.getPrintWriter());
1034            }
1035          }
1036        }
1037      };
1038      Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
1039                                 runnable);
1040      thread.setPriority(Thread.MIN_PRIORITY);
1041      thread.start();
1042    }
1043  }
1044
1045  /**
1046   * Releases the memory, removes the listeners, cleans up.
1047   * Will get called when the target resource is unloaded from the system
1048   */
1049  protected void cleanup(){
1050    //delete all the VRs that were created
1051    if(largeView != null){
1052      if(largeView instanceof VisualResource){
1053        //we only had a view so no tabbed pane was used
1054        Factory.deleteResource((VisualResource)largeView);
1055      }else{
1056        Component vrs[] = ((JTabbedPane)largeView).getComponents();
1057        for(int i = 0; i < vrs.length; i++){
1058          if(vrs[i] instanceof VisualResource){
1059            Factory.deleteResource((VisualResource)vrs[i]);
1060          }
1061        }
1062      }
1063    }
1064
1065    if(smallView != null){
1066      if(smallView instanceof VisualResource){
1067        //we only had a view so no tabbed pane was used
1068        Factory.deleteResource((VisualResource)smallView);
1069      }else{
1070        Component vrs[] = ((JTabbedPane)smallView).getComponents();
1071        for(int i = 0; i < vrs.length; i++){
1072          if(vrs[i] instanceof VisualResource){
1073            Factory.deleteResource((VisualResource)vrs[i]);
1074          }
1075        }
1076      }
1077    }
1078
1079    Gate.getCreoleRegister().removeCreoleListener(this);
1080    popup = null;
1081    target = null;
1082  }
1083
1084  class ProxyStatusListener implements StatusListener{
1085    public void statusChanged(String text){
1086      fireStatusChanged(text);
1087    }
1088  }
1089
1090  protected void fireProgressChanged(int e) {
1091    if (progressListeners != null) {
1092      Vector listeners = progressListeners;
1093      int count = listeners.size();
1094      for (int i = 0; i < count; i++) {
1095        ((ProgressListener) listeners.elementAt(i)).progressChanged(e);
1096      }
1097    }
1098  }//protected void fireProgressChanged(int e)
1099
1100  protected void fireProcessFinished() {
1101    if (progressListeners != null) {
1102      Vector listeners = progressListeners;
1103      int count = listeners.size();
1104      for (int i = 0; i < count; i++) {
1105        ((ProgressListener) listeners.elementAt(i)).processFinished();
1106      }
1107    }
1108  }//protected void fireProcessFinished()
1109
1110  public synchronized void removeStatusListener(StatusListener l) {
1111    if (statusListeners != null && statusListeners.contains(l)) {
1112      Vector v = (Vector) statusListeners.clone();
1113      v.removeElement(l);
1114      statusListeners = v;
1115    }
1116  }//public synchronized void removeStatusListener(StatusListener l)
1117
1118  public synchronized void addStatusListener(StatusListener l) {
1119    Vector v = statusListeners == null ? new Vector(2) : (Vector) statusListeners.clone();
1120    if (!v.contains(l)) {
1121      v.addElement(l);
1122      statusListeners = v;
1123    }
1124  }//public synchronized void addStatusListener(StatusListener l)
1125
1126  protected void fireStatusChanged(String e) {
1127    if (statusListeners != null) {
1128      Vector listeners = statusListeners;
1129      int count = listeners.size();
1130      for (int i = 0; i < count; i++) {
1131        ((StatusListener) listeners.elementAt(i)).statusChanged(e);
1132      }
1133    }
1134  }
1135
1136  public void statusChanged(String e) {
1137    fireStatusChanged(e);
1138  }
1139  public void progressChanged(int e) {
1140    fireProgressChanged(e);
1141  }
1142  public void processFinished() {
1143    fireProcessFinished();
1144  }
1145  public Window getWindow() {
1146    return window;
1147  }
1148
1149  public void resourceLoaded(CreoleEvent e) {
1150  }
1151
1152  public void resourceUnloaded(CreoleEvent e) {
1153    if(getTarget() == e.getResource()) cleanup();
1154
1155  }
1156
1157  public void resourceRenamed(Resource resource, String oldName,
1158                              String newName){
1159    if(target == resource) title = target.getName();
1160  }
1161
1162  public void datastoreOpened(CreoleEvent e) {
1163  }
1164
1165  public void datastoreCreated(CreoleEvent e) {
1166  }
1167
1168  public void datastoreClosed(CreoleEvent e) {
1169    if(getTarget() == e.getDatastore()) cleanup();
1170  }
1171}//class DefaultResourceHandle
1172