1   /*  UnrestrictedAnnotationEditor.java
2    *
3    *  Copyright (c) 1998-2001, The University of Sheffield.
4    *
5    *  This file is part of GATE (see http://gate.ac.uk/), and is free
6    *  software, licenced under the GNU Library General Public License,
7    *  Version 2, June 1991 (in the distribution as file licence.html,
8    *  and also available at http://gate.ac.uk/gate/licence.html).
9    *
10   *  Cristian URSU,  13/July/2001
11   *
12   *  $Id: UnrestrictedAnnotationEditor.java,v 1.4 2001/08/07 17:01:32 kalina Exp $
13   *
14   */
15  
16  package gate.gui;
17  
18  import java.awt.Frame;
19  import java.awt.BorderLayout;
20  import java.awt.Component;
21  import java.awt.event.*;
22  import javax.swing.*;
23  import javax.swing.table.*;
24  
25  import java.util.*;
26  import java.lang.reflect.*;
27  import java.net.*;
28  
29  import gate.*;
30  import gate.annotation.*;
31  import gate.util.*;
32  import gate.creole.*;
33  
34  /** This class visually adds/edits features and annot type of an annotation
35    * It does this without using an {@link gate.creole.AnnotationSchema}.
36    * The user can manipulate annotation and features at his own will.
37    * It's his responsability.
38    */
39  public class UnrestrictedAnnotationEditor extends AbstractVisualResource
40                                            implements AnnotationVisualResource{
41  
42    /** Default constructor*/
43    public UnrestrictedAnnotationEditor() {}
44  
45    // Methods required by AnnotationVisualResource
46  
47    /**
48      * Called by the GUI when this viewer/editor has to initialise itself for a
49      * specific annotation or text span.
50      * @param target the object which will always be a {@link gate.AnnotationSet}
51      */
52    public void setTarget(Object target){
53      currentAnnotSet = (AnnotationSet) target;
54    }// setTarget();
55  
56    /**
57      * Used when the viewer/editor has to display/edit an existing annotation
58      * @param ann the annotation to be displayed or edited. If ann is null then
59      * the method simply returns
60      */
61    public void setAnnotation(Annotation ann){
62      // If ann is null, then simply return.
63      if (ann == null) return;
64      currentAnnot = ann;
65      currentStartOffset = currentAnnot.getStartNode().getOffset();
66      currentEndOffset = currentAnnot.getEndNode().getOffset();
67  
68      initLocalData();
69      initGuiComponents();
70  
71    }// setAnnotation();
72  
73    /**
74      * Used when the viewer has to create new annotations.
75      * @param startOffset the start offset of the span covered by the new
76      * annotation(s). If is <b>null</b> the method will simply return.
77      * @param endOffset the end offset of the span covered by the new
78      * annotation(s). If is <b>null</b> the method will simply return.
79      */
80    public void setSpan(Long startOffset, Long endOffset, String annotationType){
81      // If one of them is null, then simply return.
82      if (startOffset == null || endOffset == null) return;
83  
84      currentStartOffset = startOffset;
85      currentEndOffset = endOffset;
86      currentAnnot = null;
87  
88      initLocalData();
89      initGuiComponents();
90    }// setSpan();
91  
92    /**
93     * Called by the GUI when the user has pressed the "OK" button. This should
94     * trigger the saving of the newly created annotation(s)
95     */
96    public void okAction() throws GateException {
97      if (annotTypeTextField.getText().equals("")){
98        throw new GateException("An annotation type must be specified !");
99      }// End if
100     // This code must be uncomented if the desired behaviour for
101     // UnrestrictedAnnoatationEditor is not to allow annotation types
102     // which have a schema present in the system.
103 /*
104     CreoleRegister creoleReg = Gate.getCreoleRegister();
105     List currentAnnotationSchemaList =
106                       creoleReg.getLrInstances("gate.creole.AnnotationSchema");
107     Iterator iter = currentAnnotationSchemaList.iterator();
108     while (iter.hasNext()){
109       AnnotationSchema annotSchema = (AnnotationSchema) iter.next();
110       if (annotTypeTextField.getText().equals(annotSchema.getAnnotationName()))
111         throw new GAteException("There is a schema type for this annotation");
112     }// End while
113 */
114     data.setAnnotType(annotTypeTextField.getText());
115     if (currentAnnot == null){
116       currentAnnotSet.add( currentStartOffset,
117                            currentEndOffset,
118                            this.getAnnotType(),
119                            this.getCurrentAnnotationFeatures());
120     }else{
121       if (currentAnnot.getType().equals(this.getAnnotType())){
122         currentAnnot.setFeatures(this.getCurrentAnnotationFeatures());
123       }else{
124         currentAnnotSet.remove(currentAnnot);
125         currentAnnotSet.add( currentStartOffset,
126                              currentEndOffset,
127                              this.getAnnotType(),
128                              this.getCurrentAnnotationFeatures());
129       }// End if
130     }// End if
131   }//okAction();
132 
133 
134   public void cancelAction() throws GateException {
135     //no need to do anything, because the editor has not modified anything
136     //on the document or the annotation sets
137     //Had to be added for the tree editor, which does
138     return;
139   }
140 
141   /**
142     * Checks whether this viewer/editor can handle a specific annotation type.
143     * @param annotationType represents the annotation type being questioned.If
144     * it is <b>null</b> then the method will return false.
145     * @return true if the SchemaAnnotationEditor can handle the annotationType
146     * or false otherwise.
147     */
148   public boolean canDisplayAnnotationType(String annotationType){
149     return true;
150   }// canDisplayAnnotationType();
151 
152   // The Unrestricted Editor functionality
153   // Local data
154 
155   /** The curent annotation set used by the editor*/
156   AnnotationSet currentAnnotSet = null;
157   /** The curent annotation used by the editor*/
158   Annotation currentAnnot = null;
159   /** The start offset of the span covered by the currentAnnot*/
160   Long currentStartOffset = null;
161   /** The end offset of the span covered by the currentAnnot*/
162   Long currentEndOffset = null;
163 
164   // Local data
165   private MyCustomFeatureBearer data = null;
166 
167   // Gui Components
168   JLabel annotTypeLabel = null;
169   JTextField annotTypeTextField = null;
170 
171   JLabel featuresLabel = null;
172   FeaturesEditor  featuresEditor = null;
173 
174   /** Init local data*/
175   protected void initLocalData(){
176     data = new MyCustomFeatureBearer(currentAnnot);
177   }// initLocalData();
178 
179   /** Init GUI components with values taken from local data*/
180   protected void initGuiComponents(){
181     this.setLayout(new BoxLayout( this, BoxLayout.Y_AXIS));
182     //create the main box
183     Box componentsBox = Box.createVerticalBox();
184 
185     componentsBox.add(Box.createVerticalStrut(10));
186 
187     // Add the Annot Type
188     Box box = Box.createVerticalBox();
189     Box box1 = Box.createHorizontalBox();
190     annotTypeLabel = new JLabel("Annotation type");
191     annotTypeLabel.setToolTipText("The type of the annotation you are" +
192                                                     " creating or editing");
193     annotTypeLabel.setOpaque(true);
194 
195     box1.add(annotTypeLabel);
196     box1.add(Box.createHorizontalGlue());
197     box.add(box1);
198 
199     annotTypeTextField = new JTextField(data.getAnnotType());
200     annotTypeTextField.setColumns(80);
201     annotTypeTextField.setPreferredSize(
202                                   annotTypeTextField.getPreferredSize());
203     annotTypeTextField.setMinimumSize(
204                                   annotTypeTextField.getPreferredSize());
205     annotTypeTextField.setMaximumSize(
206                                   annotTypeTextField.getPreferredSize());
207 
208 
209     box1 = Box.createHorizontalBox();
210     box1.add(annotTypeTextField);
211     box1.add(Box.createHorizontalGlue());
212     box.add(box1);
213     box.add(Box.createVerticalStrut(10));
214 
215     componentsBox.add(box);
216     // add the features editor
217     box = Box.createVerticalBox();
218 
219     featuresLabel = new JLabel("Features");
220     featuresLabel.setToolTipText("The features of the annotation you are" +
221                                                     " creating or editing");
222     featuresLabel.setOpaque(true);
223 
224     box1 = Box.createHorizontalBox();
225     box1.add(featuresLabel);
226     box1.add(Box.createHorizontalGlue());
227     box.add(box1);
228     box.add(Box.createVerticalStrut(5));
229 
230     featuresEditor = new FeaturesEditor();
231     featuresEditor.setFeatureBearer(data);
232 
233     box.add(featuresEditor);
234     box.add(Box.createVerticalStrut(10));
235 
236     componentsBox.add(box);
237     componentsBox.add(Box.createVerticalStrut(10));
238 
239     this.add(componentsBox);
240     this.add(Box.createVerticalStrut(10));
241   }//initGuiComponents()
242 
243   /** Init all the listeners*/
244   protected void initListeners(){
245   }//initListeners()
246 
247   /** Returns annot type edited with this tool*/
248   public String getAnnotType(){ return data.getAnnotType();}
249 
250   /** Returns the features edited with this tool*/
251   protected FeatureMap getCurrentAnnotationFeatures(){ return data.getFeatures();}
252 
253   // INNER CLASS
254   /** This class implements a feature bearer. It is used as internal data.
255     * The FeatureEditor will use an object belonging to this class.
256     */
257   class MyCustomFeatureBearer extends AbstractFeatureBearer
258                                                     implements FeatureBearer{
259 
260     // Members
261     private FeatureMap features = null;
262     private String annotType = null;
263 
264     /** Constructs a custom feature bearer. If annot is null then it creates
265       * empty annotType and fetures.
266       */
267     public MyCustomFeatureBearer(Annotation anAnnot){
268       if (anAnnot != null){
269         features = Factory.newFeatureMap();
270         features.putAll(anAnnot.getFeatures());
271         annotType = new String(anAnnot.getType());
272       }else{
273         features = Factory.newFeatureMap();
274         annotType = new String("");
275       }// End if
276     }//MyCustomFeatureBearer
277 
278     // Mutators and accesors
279     public void setFeatures(FeatureMap aFeatureMap){
280       features = aFeatureMap;
281     }// setFeatures();
282 
283     public FeatureMap getFeatures(){
284       return features;
285     }// getFeatures()
286 
287     public void setAnnotType(String anAnnotType){
288       annotType = anAnnotType;
289     }// setAnnotType();
290 
291     public String getAnnotType(){
292       return annotType;
293     }//getAnnotType()
294   }// End class MyCustomFeatureBearer
295 }// End class UnrestrictedAnnotationEditor