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