SchemaAnnotationEditor.java
001 /*  SchemaAnnotationEditor.java
002  *
003  *  Copyright (c) 1995-2010, The University of Sheffield. See the file
004  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
005  *
006  *  This file is part of GATE (see http://gate.ac.uk/), and is free
007  *  software, licenced under the GNU Library General Public License,
008  *  Version 2, June 1991 (in the distribution as file licence.html,
009  *  and also available at http://gate.ac.uk/gate/licence.html).
010  *
011  *  Cristian URSU,  12/July/2001
012  *
013  *  $Id: SchemaAnnotationEditor.java 12006 2009-12-01 17:24:28Z thomas_heitz $
014  *
015  */
016 
017 package gate.gui;
018 
019 import java.awt.Component;
020 import java.awt.event.ActionEvent;
021 import java.awt.event.ActionListener;
022 import java.lang.reflect.Constructor;
023 import java.util.*;
024 
025 import javax.swing.*;
026 import javax.swing.table.AbstractTableModel;
027 import javax.swing.table.TableCellEditor;
028 
029 import gate.*;
030 import gate.creole.*;
031 import gate.gui.docview.AnnotationEditor;
032 import gate.util.GateException;
033 import gate.util.LuckyException;
034 
035   /** This class is a viewer which adds/edits features on a GATE annotation.
036   * This viewer is {@link gate.creole.AnnotationSchema} driven.
037   
038   * This class has been deprecated! This functionality is now provided by the 
039   {@link AnnotationEditor} and {@link gate.gui.annedit.SchemaAnnotationEditor}
040   * classes. 
041   
042   @deprecated
043   */
044 public class SchemaAnnotationEditor extends AbstractVisualResource
045                                     implements AnnotationVisualResource,
046                                                ResizableVisualResource{
047 
048   /** Default constructor */
049   public SchemaAnnotationEditor(){}
050 
051   // Methods required by AnnotationVisualResource
052 
053   /**
054     * Called by the GUI when this viewer/editor has to initialise itself for a
055     * specific annotation or text span.
056     @param target the object which will always be a {@link gate.AnnotationSet}
057     */
058   public void setTarget(Object target){
059     currentAnnotSet = (AnnotationSettarget;
060   }// setTarget();
061 
062   /**
063     * Used when the viewer/editor has to display/edit an existing annotation
064     @param ann the annotation to be displayed or edited. If ann is null then
065     * the method simply returns
066     */
067   public void editAnnotation(Annotation ann, AnnotationSet set){
068     // If ann is null, then simply return.
069     if (ann == nullreturn;
070 
071     currentAnnot = ann;
072     currentAnnotSet = set;
073     
074     currentStartOffset = currentAnnot.getStartNode().getOffset();
075     currentEndOffset = currentAnnot.getEndNode().getOffset();
076     currentAnnotFeaturesMap = Factory.newFeatureMap();
077     currentAnnotFeaturesMap.putAll(currentAnnot.getFeatures());
078     currentAnnotSchema = null;
079     CreoleRegister creoleReg = Gate.getCreoleRegister();
080     List currentAnnotationSchemaList =
081                       creoleReg.getLrInstances("gate.creole.AnnotationSchema");
082     // If there is no Annotation schema loaded the editor can only do nothing
083     if (currentAnnotationSchemaList.isEmpty()) return;
084     name2annotSchemaMap = new TreeMap();
085     Iterator annotSchemaIter = currentAnnotationSchemaList.iterator();
086     // currentAnnotationSchemaList is not empty
087     currentAnnotSchema = (AnnotationSchemacurrentAnnotationSchemaList.get(0);
088     
089     AnnotationSchema annotSch;
090     String annotSchName;
091     while (annotSchemaIter.hasNext()){
092       annotSch = (AnnotationSchema)annotSchemaIter.next();
093       annotSchName = annotSch.getAnnotationName();
094       if(annotSch != null && annotSchName != null)
095         name2annotSchemaMap.put(annotSchName, annotSch);
096       if (currentAnnot.getType().equals(annotSchName))
097         currentAnnotSchema = annotSch;
098     }// End while
099 
100     initLocalData();
101     buildGuiComponents();
102     initListeners();
103   }// setAnnotation();
104 
105 
106   /**
107    * Called by the GUI when the user has pressed the "OK" button. This should
108    * trigger the saving of the newly created annotation(s)
109    */
110   public void okAction() throws GateException{
111     // Construct the response featutre
112     Iterator iter = tableModel.data.iterator();
113     while (iter.hasNext()){
114       RowData rd = (RowDataiter.next();
115       responseMap.put(rd.getFeatureSchema().getFeatureName(), rd.getValue());
116     }// End while
117     if (currentAnnot == null){
118       currentAnnotSet.addcurrentStartOffset,
119                            currentEndOffset,
120                            currentAnnotSchema.getAnnotationName(),
121                            responseMap);
122     }else{
123       if (currentAnnot.getType().equals(currentAnnotSchema.getAnnotationName())){
124         currentAnnot.setFeatures(responseMap);
125       }else{
126         currentAnnotSet.addcurrentStartOffset,
127                              currentEndOffset,
128                              currentAnnotSchema.getAnnotationName(),
129                              responseMap);
130         currentAnnotSet.remove(currentAnnot);
131       }// End if
132     }// End if
133   }//okAction();
134 
135   public void cancelAction() throws GateException {
136     //no need for any cleanup, because this editor has been implemented
137     //so that it does not modify the document and annotations, unless
138     //OK is pressed
139     return;
140   }
141 
142   /**
143     * Checks whether this viewer/editor can handle a specific annotation type.
144     @param annotationType represents the annotation type being questioned.If
145     * it is <b>null</b> then the method will return false.
146     @return true if the SchemaAnnotationEditor can handle the annotationType
147     * or false otherwise.
148     */
149   public boolean canDisplayAnnotationType(String annotationType){
150     // Returns true only if the there is an AnnotationSchema with the same type
151     // as annotationType.
152     if (annotationType == nullreturn false;
153     CreoleRegister creoleReg = Gate.getCreoleRegister();
154     List currentAnnotationSchemaList =
155                       creoleReg.getLrInstances("gate.creole.AnnotationSchema");
156     if (currentAnnotationSchemaList.isEmpty()) return false;
157     Iterator iter = currentAnnotationSchemaList.iterator();
158     while (iter.hasNext()){
159       AnnotationSchema annotSchema = (AnnotationSchemaiter.next();
160       if (annotationType.equals(annotSchema.getAnnotationName())) return true;
161     }// End while
162     return false;
163   }// canDisplayAnnotationType();
164 
165   
166   /**
167    * Always returns <tt>true</tt>.
168    */
169   public boolean editingFinished() {
170     return true;
171   }
172 
173   /**
174    * Returns the anntoation curerntly edited.
175    */
176   public Annotation getAnnotationCurrentlyEdited() {
177     return currentAnnot;
178   }
179 
180   /* (non-Javadoc)
181    * @see gate.creole.AnnotationVisualResource#getAnnotationSetCurrentlyEdited()
182    */
183   public AnnotationSet getAnnotationSetCurrentlyEdited() {
184     return currentAnnotSet;
185   }
186 
187   /* (non-Javadoc)
188    * @see gate.creole.AnnotationVisualResource#isActive()
189    */
190   public boolean isActive() {
191     return isVisible();
192   }
193 
194   /**
195    * Returns <tt>true</tt>
196    */
197   public boolean supportsCancel() {
198     return true;
199   }
200 
201 
202   // Local data
203   /** The annotation schema present into the system*/
204   List currentAnnotationSchemaList = null;
205   /** The curent annotation set used by the editor*/
206   AnnotationSet currentAnnotSet = null;
207   /** The curent annotation used by the editor*/
208   Annotation currentAnnot = null;
209   /** The start offset of the span covered by the currentAnnot*/
210   Long currentStartOffset = null;
211   /** The end offset of the span covered by the currentAnnot*/
212   Long currentEndOffset = null;
213   /** This is the currentAnnotSchema being used by the editor*/
214   AnnotationSchema currentAnnotSchema = null;
215   /** The current FeatureMap used by the editor*/
216   FeatureMap currentAnnotFeaturesMap = null;
217   /** This field is returned when a featureMap was editted or created*/
218   FeatureMap responseMap = null;
219   /** This field is the table model used to represent features*/
220   FeaturesTableModel tableModel = null;
221   /** A map from feature name to its FeatureSchema definition*/
222   Map name2featureSchemaMap = null;
223   /** A map from annotation type to its AnnotationSchema definition*/
224   Map name2annotSchemaMap = null;
225   /** A list model used to represent the features not assigned to an annot*/
226   DefaultListModel listModel = null;
227 
228   // Gui Components
229   /** Displays the current features of the annotation being editted */
230   JTable  featuresTable = null;
231   /** A JScroll for the featuresTable component */
232   JScrollPane featuresTableScroll = null;
233   /** Displays all possible features of the annotation being
234    *  editted (taken from AnnotationSchema)
235    */
236   JList   featureSchemaList = null;
237   /** A JScroll for the featuresTable component */
238   JScrollPane featuresListScroll = null;
239   /** This button removes current features and add them to possible feature list*/
240   JButton removeFeatButton = null;
241   /** This button does the opposite of the above*/
242   JButton addFeatButton = null;
243   /** Displays all possible annotation schema loaded into the system*/
244   JComboBox annotSchemaComboBox = null;
245   /** This inner class deals with feature editting*/
246   InnerFeaturesEditor featuresEditor = null;
247 
248   /** Init local data needed by the GUI components to initialize*/
249   protected void initLocalData(){
250     // Create the response feature Map
251     responseMap = Factory.newFeatureMap();
252 
253     if (currentAnnotFeaturesMap == null)
254       currentAnnotFeaturesMap = Factory.newFeatureMap();
255 
256     name2featureSchemaMap = new HashMap();
257     // Construct a set of feature names from feature schema
258     Map fSNames2FSMap = new HashMap();
259 
260     listModel = new DefaultListModel();
261     // Init name2featureSchemaMap
262     // If the feature map provided was null, then we are in the creation mode
263     Set featuresSch = currentAnnotSchema.getFeatureSchemaSet();
264     if (featuresSch != null){
265       Iterator iter = featuresSch.iterator();
266       while (iter.hasNext()){
267         FeatureSchema fs = (FeatureSchemaiter.next();
268         // If the currentAnnotFeaturesMap doesn't contain the feature
269         // from FeatureSchema then
270         // add the featureSchema to the list
271         if (fs != null){
272           fSNames2FSMap.put(fs.getFeatureName(),fs);
273           if!currentAnnotFeaturesMap.containsKey(fs.getFeatureName())){
274               name2featureSchemaMap.put(fs.getFeatureName(),fs);
275               listModel.addElement(fs.getFeatureName());
276           }// end if
277         }// end if
278       }// end while
279     }// end if
280 
281     // Init the table model
282     Set tableData = new HashSet();
283     Iterator iterator = currentAnnotFeaturesMap.keySet().iterator();
284     while (iterator.hasNext()){
285       String key = (Stringiterator.next();
286       // If in currentAnnotFeaturesMap there is a key contained into
287       // fSNames2FSMap then
288       // add this feature to the table model together with its corresponding
289       // FeatureSchema
290       if (fSNames2FSMap.keySet().contains(key)){
291         // Add it to the table model
292         Object value = currentAnnotFeaturesMap.get(key);
293         tableData.add(new RowData(value,(FeatureSchema)fSNames2FSMap.get(key)));
294       else
295         // Add it to the responseFeatureMap
296         // It might be a feature detected by the nameMatcher module, etc.
297         // Those features must be preserved.
298         responseMap.put(key,currentAnnotFeaturesMap.get(key));
299     }// end while
300     tableModel = new FeaturesTableModel(tableData);
301   }// initLocalData();
302 
303   /** This method creates the GUI components and places them into the layout*/
304   protected void buildGuiComponents(){
305     this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
306     // Create the annotationSchema JComboBox box
307 
308     JPanel annotSchBox = new JPanel();
309     annotSchBox.setLayout(new BoxLayout(annotSchBox, BoxLayout.Y_AXIS));
310     annotSchBox.setAlignmentX(Component.LEFT_ALIGNMENT);
311     annotSchBox.add(Box.createVerticalStrut(5));
312     annotSchemaComboBox = new JComboBox(name2annotSchemaMap.keySet().toArray());
313     annotSchemaComboBox.setEditable(false);
314     annotSchemaComboBox.setAlignmentX(Component.LEFT_ALIGNMENT);
315     annotSchemaComboBox.setSelectedItem(currentAnnotSchema.getAnnotationName());
316     JLabel annotSchemaLabel = new JLabel("Select annotation type");
317     annotSchemaLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
318     annotSchBox.add(annotSchemaLabel);
319     annotSchBox.add(annotSchemaComboBox);
320 
321 
322     //Create the main box
323     JPanel componentsBox = new JPanel();
324     componentsBox.setLayout(new BoxLayout(componentsBox, BoxLayout.X_AXIS));
325     componentsBox.setAlignmentX(Component.LEFT_ALIGNMENT);
326 
327     // Create the feature table
328     featuresTable = new JTable();
329     featuresTable.setSelectionMode(
330                   ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
331     featuresTable.setModel(new FeaturesTableModel(new HashSet()));
332 //    featuresTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
333     featuresEditor = new InnerFeaturesEditor();
334     featuresTable.setDefaultEditor(java.lang.Object.class, featuresEditor);
335     featuresTableScroll = new JScrollPane(featuresTable);
336 
337     Box box = Box.createVerticalBox();
338     JLabel currentFeat = new JLabel("Current features");
339     currentFeat.setAlignmentX(Component.LEFT_ALIGNMENT);
340     box.add(currentFeat);
341     box.add(Box.createVerticalStrut(10));
342     box.add(featuresTableScroll);
343     featuresTableScroll.setAlignmentX(Component.LEFT_ALIGNMENT);
344 
345     componentsBox.add(box);
346     componentsBox.add(Box.createHorizontalStrut(10));
347 
348     // add the remove put buttons
349     Box buttBox = Box.createVerticalBox();
350     removeFeatButton = new JButton(">>");
351     addFeatButton = new JButton("<<");
352 
353     buttBox.add(addFeatButton);
354     buttBox.add(Box.createVerticalStrut(10));
355     buttBox.add(removeFeatButton);
356 
357     componentsBox.add(buttBox);
358 
359     componentsBox.add(Box.createHorizontalStrut(10));
360 
361     // add the Feature Schema list
362     featureSchemaList = new JList();
363     featureSchemaList.setSelectionMode(
364                   ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
365     Set featuresSch = currentAnnotSchema.getFeatureSchemaSet();
366     if(featuresSch != null){
367       featureSchemaList.setVisibleRowCount(featuresSch.size());
368     }
369     featuresListScroll = new JScrollPane(featureSchemaList);
370 
371     box = Box.createVerticalBox();
372     JLabel possibFeaturesLabel = new JLabel("Possible features");
373     possibFeaturesLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
374     box.add(possibFeaturesLabel);
375     box.add(Box.createVerticalStrut(10));
376     featuresListScroll.setAlignmentX(Component.LEFT_ALIGNMENT);
377     box.add(featuresListScroll);
378 
379     componentsBox.add(box);
380     componentsBox.add(Box.createHorizontalStrut(5));
381 
382     box = Box.createVerticalBox();
383     box.add(annotSchBox);
384     box.add(componentsBox);
385     this.add(box);
386     this.initGuiComponents();
387   }//buildGuiComponents();
388 
389   /** Init GUI components with values taken from local data*/
390   protected void initGuiComponents(){
391     featuresTable.setModel(tableModel);
392     featureSchemaList.setModel(listModel);
393   }//initGuiComponents()
394 
395   /** Init all the listeners*/
396   protected void initListeners(){
397 
398     annotSchemaComboBox.addActionListener(new ActionListener() {
399       public void actionPerformed(ActionEvent e) {
400         currentAnnotSchema = (AnnotationSchemaname2annotSchemaMap.get(
401                                  (String)annotSchemaComboBox.getSelectedItem());
402         initLocalData();
403         initGuiComponents();
404       }// actionPerformed();
405     });//addActionListener();
406 
407     // -> removeFeatButton
408     removeFeatButton.addActionListener(new ActionListener() {
409       public void actionPerformed(ActionEvent e) {
410         doRemoveFeatures();
411       }//actionPerformed();
412     });// addActionListener();
413 
414     // <- addFeatButton
415     addFeatButton.addActionListener(new ActionListener() {
416       public void actionPerformed(ActionEvent e) {
417         doAddFeatures();
418       }// actionPerformed();
419     });// addActionListener();
420   }//initListeners()
421 
422   /** This method remove a feature from the table and adds it to the list*/
423   private void doRemoveFeatures(){
424     int[] selectedRows = featuresTable.getSelectedRows();
425 
426     if (selectedRows.length <= 0return;
427 
428     for (int i = (selectedRows.length - 1); i > -; i--)
429       doRemoveFeature(selectedRows[i]);
430 
431     tableModel.fireTableDataChanged();
432   }// doRemoveFeatures();
433 
434   /** This removes the feature @ rowIndex*/
435   private void doRemoveFeature(int rowIndex){
436     RowData rd =  (RowDatatableModel.data.get(rowIndex);
437 
438     name2featureSchemaMap.put(rd.getFeatureSchema().getFeatureName(),
439                                                       rd.getFeatureSchema());
440 
441     listModel.addElement(rd.getFeatureSchema().getFeatureName());
442     tableModel.data.remove(rowIndex);
443   }// doRemoveFeature();
444 
445   /** This method adds features from the list to the table*/
446   private void doAddFeatures(){
447     Object[] selectedFeaturesName = featureSchemaList.getSelectedValues();
448     for (int i = ; i < selectedFeaturesName.length; i ++){
449       doAddFeature((StringselectedFeaturesName[i]);
450     }// end for
451     tableModel.fireTableDataChanged();
452   }//doAddFeatures();
453 
454   /** This method adds a feature from the list to the table*/
455   private void doAddFeature(String aFeatureName){
456       FeatureSchema fs=(FeatureSchemaname2featureSchemaMap.get(aFeatureName);
457 
458       // Remove the feature schema from the list
459       name2featureSchemaMap.remove(aFeatureName);
460       listModel.removeElement(aFeatureName);
461 
462       Object value = null;
463       if (fs.isDefault() || fs.isFixed())
464         value = fs.getFeatureValue();
465       if (value == null && fs.isEnumeration()){
466         Iterator iter = fs.getPermittedValues().iterator();
467         if (iter.hasNext()) value = iter.next();
468       }
469       tableModel.data.add(new RowData(value,fs));
470   }// doAddFeature();
471 
472   // Inner classes
473 
474   // TABLE MODEL
475   protected class FeaturesTableModel extends AbstractTableModel{
476 
477     ArrayList data = null;
478 
479     public FeaturesTableModel(Set aData){
480       data = new ArrayList(aData);
481     }// FeaturesTableModel
482 
483     public void fireTableDataChanged(){
484       super.fireTableDataChanged();
485     }// fireTableDataChanged();
486 
487     public int getColumnCount(){return 3;}
488 
489     public Class getColumnClass(int columnIndex){
490       switch(columnIndex){
491         case 0return String.class;
492         case 1return Object.class;
493         case 2return String.class;
494         defaultreturn Object.class;
495       }
496     }//getColumnClass()
497 
498     public String getColumnName(int columnIndex){
499       switch(columnIndex){
500         case 0return "Name";
501         case 1return "Value";
502         case 2return "Type";
503         defaultreturn "?";
504       }
505     }//public String getColumnName(int columnIndex)
506 
507     public boolean isCellEditableint rowIndex,
508                                    int columnIndex){
509 
510 
511         if(columnIndex == 1){
512           RowData rd = (RowDatadata.get(rowIndex);
513           FeatureSchema fs = rd.getFeatureSchema();
514           if (fs.isFixed() || fs.isProhibited()) return false;
515           else return true;
516         }// end if
517         if(columnIndex == || columnIndex == 2return false;
518         return false;
519     }//isCellEditable
520 
521     public int getRowCount(){
522       return data.size();
523     }//getRowCount()
524 
525     /** Returns the value at row,column from Table Model */
526     public Object getValueAtint rowIndex,
527                               int columnIndex){
528 
529       RowData rd = (RowDatadata.get(rowIndex);
530 
531       switch(columnIndex){
532         case 0return rd.getFeatureSchema().getFeatureName();
533         case 1return (rd.getValue() == null)new String(""): rd.getValue();
534         case 2{
535                   // Show only the last substring. For example, for
536                   // java.lang.Integer -> Integer
537                   Class<?> type = rd.getFeatureSchema().getFeatureValueClass();
538                   if(type == null)
539                       return new String("");
540                   else{
541                     return type.getName();
542                   }// End if
543                 }
544 
545         defaultreturn "?";
546       }// End Switch
547     }//getValueAt
548 
549     /** Set the value from the Cell Editor into the table model*/
550     public void setValueAtObject aValue,
551                             int rowIndex,
552                             int columnIndex){
553 
554       if (data == null || data.isEmpty()) return;
555       RowData rd = (RowDatadata.get(rowIndex);
556       switch(columnIndex){
557         case 0:{break;}
558         case 1:{
559           // Try to perform type conversion
560           String className = null;
561           String aValueClassName = null;
562           // Need to create an object belonging to class "className" based on
563           // the string object "aValue"
564           if (aValue == null){
565             rd.setValue("?");
566             return;
567           }// End if
568           // Get the class name the final object must belong
569           className = rd.getFeatureSchema().getFeatureValueClass().
570               getCanonicalName();
571           // Get the class name that aValue object belongs to.
572           aValueClassName = aValue.getClass().toString();
573           // If there is no class to convert to, let the aValue object as it is
574           // and return.
575           if (className == null){
576               rd.setValue(aValue);
577               return;
578           }// End if
579 
580           // If both classes are the same, then return. There is nothing to
581           // convert to
582           if (className.equals(aValueClassName)){
583             rd.setValue(aValue);
584             return;
585           }// End if
586           // If the class "aValue" object belongs to is not String then return.
587           // This method tries to convert a string to various other types.
588           if (!"class java.lang.String".equals(aValueClassName)){
589             rd.setValue(aValue);
590             return;
591           }// End if
592 
593           // The aValue object belonging to java.lang.String needs to be
594           // converted into onother object belonging to "className"
595           Class  classObj = null;
596           try{
597             // Create a class object from className
598             classObj = Gate.getClassLoader().loadClass(className);
599           }catch (ClassNotFoundException cnfex){
600             try{
601               //now let's try the system classloader
602               classObj = Class.forName(className);
603             }catch (ClassNotFoundException cnfe){
604             rd.setValue(aValue);
605             return;
606             }
607           }// End catch
608           // Get its list of constructors
609           Constructor[] constrArray = classObj.getConstructors();
610           if (constrArray == null){
611             rd.setValue(aValue);
612             return;
613           }// End if
614 
615           // Search for the constructo which takes only one String parameter
616           boolean found = false;
617           Constructor constructor = null;
618           for (int i=0; i<constrArray.length; i++){
619             constructor = constrArray[i];
620             if constructor.getParameterTypes().length == &&
621                  "class java.lang.String".equals(
622                                 constructor.getParameterTypes()[0].toString())
623                ){
624                   found = true;
625                   break;
626             }// End if
627           }// End for
628 
629           if (!found){
630             rd.setValue(aValue);
631             return;
632           }// End if
633           try{
634             // Try to create an object with this constructor
635             Object[] paramsArray = new Object[1];
636             paramsArray[0= aValue;
637             Object newValueObject = constructor.newInstance(paramsArray);
638 
639             rd.setValue(newValueObject);
640 
641           catch (Exception e){
642             rd.setValue("");
643           }// End catch
644 
645 //          rd.setValue(aValue);
646           break;
647         }// End case
648         case 2:{break;}
649         case 3:{break;}
650         default:{}
651       }// End switch
652     }// setValueAt();
653 
654   }///class FeaturesTableModel extends DefaultTableModel
655 
656   /** Internal class used in the inner FeaturesTableModel class*/
657   class RowData {
658     private Object value = null;
659     private FeatureSchema featSchema = null;
660 
661     /** Constructor*/
662     RowData(Object aValue, FeatureSchema aFeatureSchema){
663       value = aValue;
664       featSchema = aFeatureSchema;
665     }//RowData
666 
667     public void setValue(Object aValue){
668       value = aValue;
669     }// setValue();
670 
671     public Object getValue(){
672       return value;
673     }//getValue()
674 
675     public void setFeatureSchema(FeatureSchema aFeatureSchema){
676       featSchema = aFeatureSchema;
677     }// setFeatureSchema();
678 
679     public FeatureSchema getFeatureSchema(){
680       return featSchema;
681     }//getFeatureSchema()
682 
683   }// RowData
684 
685   // The EDITOR RENDERER
686   /** This inner class deals with the feature type being eddited. What it does
687     * is to decide what GUI component to use (JComboBox, JTextField or JLabel)
688     */
689   class InnerFeaturesEditor extends AbstractCellEditor  implements TableCellEditor{
690     // Fields
691     JComboBox cb = null;
692     JTextField tf = null;
693     int thisRow = 0;
694     int thisColumn = 0;
695     /** Constructor*/
696     public InnerFeaturesEditor(){}
697     /** The method overridden in order to implement behaviour*/
698     public Component getTableCellEditorComponentJTable table,
699                                                   Object value,
700                                                   boolean isSelected,
701                                                   int row,
702                                                   int column){
703        thisRow = row;
704        thisColumn = column;
705        RowData rd = (RowDatatableModel.data.get(row);
706        if (rd.getFeatureSchema().isEnumeration()){
707           cb = new JComboBox(rd.getFeatureSchema().
708                                             getPermittedValues().toArray());
709           cb.setSelectedItem(value);
710           cb.addActionListener(new ActionListener(){
711             public void actionPerformed(ActionEvent e){
712               tableModel.setValueAt(cb.getSelectedItem(),thisRow,thisColumn);
713             }// actionPerformed();
714           });//addActionListener();
715           tf = null;
716           return cb;
717        }// End if
718        if rd.getFeatureSchema().isDefault() ||
719             rd.getFeatureSchema().isOptional() ||
720             rd.getFeatureSchema().isRequired() ){
721 
722             tf = new JTextField(value.toString());
723             cb = null;
724             return tf;
725        }// End iff
726        return new JLabel(value.toString());
727     }//getTableCellEditorComponent
728     /** @return the object representing the value stored at that cell*/
729     public Object getCellEditorValue(){
730       if (cb != null return cb.getSelectedItem();
731       if (tf != null return tf.getText();
732       return new String("");
733     }//getCellEditorValue
734   }///InnerFeaturesEditor inner class
735 }// End class SchemaAnnotationEditor