ResourceParametersEditor.java
0001 /*
0002  *  Copyright (c) 1995-2013, The University of Sheffield. See the file
0003  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
0004  *
0005  *  This file is part of GATE (see http://gate.ac.uk/), and is free
0006  *  software, licenced under the GNU Library General Public License,
0007  *  Version 2, June 1991 (in the distribution as file licence.html,
0008  *  and also available at http://gate.ac.uk/gate/licence.html).
0009  *
0010  *  Valentin Tablan 03/10/2001
0011  *
0012  *  $Id: ResourceParametersEditor.java 18323 2014-09-12 12:05:36Z markagreenwood $
0013  *
0014  */
0015 
0016 package gate.gui;
0017 
0018 import gate.DocumentFormat;
0019 import gate.Factory;
0020 import gate.FeatureMap;
0021 import gate.Gate;
0022 import gate.Resource;
0023 import gate.corpora.DocumentImpl;
0024 import gate.creole.Parameter;
0025 import gate.creole.ResourceData;
0026 import gate.creole.ResourceInstantiationException;
0027 import gate.event.CreoleEvent;
0028 import gate.event.CreoleListener;
0029 import gate.swing.XJFileChooser;
0030 import gate.swing.XJTable;
0031 import gate.util.Err;
0032 import gate.util.ExtensionFileFilter;
0033 import gate.util.GateException;
0034 import gate.util.LuckyException;
0035 import gate.util.NameBearer;
0036 
0037 import java.awt.Component;
0038 import java.awt.Dimension;
0039 import java.awt.Toolkit;
0040 import java.awt.Window;
0041 import java.awt.event.ActionEvent;
0042 import java.awt.event.ActionListener;
0043 import java.awt.event.FocusAdapter;
0044 import java.awt.event.FocusEvent;
0045 import java.awt.event.KeyAdapter;
0046 import java.awt.event.KeyEvent;
0047 import java.awt.event.MouseAdapter;
0048 import java.awt.event.MouseEvent;
0049 import java.io.IOException;
0050 import java.lang.reflect.Method;
0051 import java.util.ArrayList;
0052 import java.util.Collection;
0053 import java.util.Comparator;
0054 import java.util.Iterator;
0055 import java.util.List;
0056 import java.util.Objects;
0057 import java.util.Set;
0058 
0059 import javax.swing.AbstractCellEditor;
0060 import javax.swing.Box;
0061 import javax.swing.BoxLayout;
0062 import javax.swing.DefaultCellEditor;
0063 import javax.swing.DefaultComboBoxModel;
0064 import javax.swing.JButton;
0065 import javax.swing.JComboBox;
0066 import javax.swing.JFileChooser;
0067 import javax.swing.JLabel;
0068 import javax.swing.JList;
0069 import javax.swing.JPanel;
0070 import javax.swing.JTable;
0071 import javax.swing.JTextField;
0072 import javax.swing.ListCellRenderer;
0073 import javax.swing.SwingUtilities;
0074 import javax.swing.event.ChangeEvent;
0075 import javax.swing.table.AbstractTableModel;
0076 import javax.swing.table.DefaultTableCellRenderer;
0077 import javax.swing.table.TableCellEditor;
0078 
0079 /**
0080  * Allows the editing of a set of parameters for a resource. It needs a
0081  * pointer to the resource and a list of the parameter names for the
0082  * parameters that should be displayed. The list of the parameters is
0083  * actually a list of lists of strings representing parameter
0084  * disjunctions.
0085  */
0086 @SuppressWarnings({"serial","rawtypes","unchecked"})
0087 public class ResourceParametersEditor extends XJTable implements CreoleListener {
0088 
0089   public ResourceParametersEditor() {
0090     initLocalData();
0091     initGuiComponents();
0092     initListeners();
0093     setSortable(true);
0094     setSortedColumn(0);
0095     setComparator(0new ParameterDisjunctionComparator());
0096     setTabSkipUneditableCell(true);
0097     setEditCellAsSoonAsFocus(true);
0098   }
0099   
0100   public void init(Resource resource, ResourceData resourceData, List<List<Parameter>> parameters) {
0101     cleanup();
0102     this.resource = resource;
0103     this.resourceData = resourceData;
0104     if(parameters != null) {
0105       parameterDisjunctions = new ArrayList<ParameterDisjunction>(parameters.size());
0106       for(int i = 0; i < parameters.size(); i++) {
0107         parameterDisjunctions.add(new ParameterDisjunction(resource,
0108                 parameters.get(i)));
0109       }
0110     }
0111     else {
0112       parameterDisjunctions = null;
0113     }
0114     tableModel.fireTableDataChanged();
0115     fileChooser = MainFrame.getFileChooser();
0116     // must be saved now as it will be reset when the file chooser is hidden
0117     fileChooserResource = (resource != null?
0118       resource.getClass().getName() : fileChooser.getResource();
0119   }
0120   
0121   /**
0122    * Initialises this GUI component.
0123    
0124    @param resource the resource for which the parameters need to be
0125    *          set.
0126    @param parameters a list of lists of {@link Parameter} representing
0127    *          parameter disjunctions.
0128    */
0129   public void init(Resource resource, List<List<Parameter>> parameters) {
0130     init(resource, null, parameters);
0131   }
0132 
0133   protected void initLocalData() {
0134     resource = null;
0135     parameterDisjunctions = null;
0136     resourceData = null;
0137   }// protected void initLocalData()
0138 
0139   protected void initGuiComponents() {
0140     setModel(tableModel = new ParametersTableModel());
0141     getColumnModel().getColumn(0).setCellRenderer(
0142             new ParameterDisjunctionRenderer());
0143     getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer());
0144     getColumnModel().getColumn(2).setCellRenderer(new BooleanRenderer());
0145     getColumnModel().getColumn(3).setCellRenderer(new ParameterValueRenderer());
0146     getColumnModel().getColumn(0).setCellEditor(
0147             new ParameterDisjunctionEditor());
0148     getColumnModel().getColumn(3).setCellEditor(new ParameterValueEditor());
0149     setAutoResizeMode(AUTO_RESIZE_LAST_COLUMN);
0150 
0151     setSurrendersFocusOnKeystroke(true);
0152   }// protected void initGuiComponents()
0153 
0154   protected void initListeners() {
0155     Gate.getCreoleRegister().addCreoleListener(this);
0156   }
0157 
0158   /**
0159    * Cleans the internal data and prepares this object to be collected
0160    */
0161   public void cleanup() {
0162     Gate.getCreoleRegister().removeCreoleListener(this);
0163     if(parameterDisjunctions != null && parameterDisjunctions.size() 0) {
0164       for(int i = 0; i < parameterDisjunctions.size(); i++) {
0165         parameterDisjunctions.get(i).cleanup();
0166       }
0167     }
0168     resource = null;
0169     resourceData = null;
0170   }
0171 
0172   /**
0173    * Sets the parameters for the resource to their new values as
0174    * resulted from the user's edits.
0175    */
0176   public void setParameters() throws ResourceInstantiationException {
0177     if(resource == null || parameterDisjunctions == nullreturn;
0178     // stop current edits
0179     if(getEditingColumn() != -&& getEditingRow() != -1) {
0180       editingStopped(new ChangeEvent(getCellEditor(getEditingRow(),
0181               getEditingColumn())));
0182     }
0183     // set the parameters
0184     for(int i = 0; i < parameterDisjunctions.size(); i++) {
0185       ParameterDisjunction pDisj = parameterDisjunctions
0186               .get(i);
0187       resource.setParameterValue(pDisj.getName(), pDisj.getValue());
0188     }
0189   }
0190 
0191   /**
0192    * Does this GUI component allow editing?
0193    */
0194 
0195   public Resource getResource() {
0196     return resource;
0197   }
0198 
0199   /**
0200    * Gets the current values for the parameters.
0201    
0202    @return {@link FeatureMap} containing the curent values for the
0203    *         currently selected parameters in each disjunction.
0204    */
0205   public FeatureMap getParameterValues() {
0206     // stop current edits
0207     if(getEditingColumn() != -&& getEditingRow() != -1) {
0208       editingStopped(new ChangeEvent(getCellEditor(getEditingRow(),
0209               getEditingColumn())));
0210     }
0211     // get the parameters
0212     FeatureMap values = Factory.newFeatureMap();
0213     if(parameterDisjunctions != null) {
0214       for(int i = 0; i < parameterDisjunctions.size(); i++) {
0215         ParameterDisjunction pDisj = parameterDisjunctions.get(i);
0216         values.put(pDisj.getName(), pDisj.getValue());
0217       }
0218     }
0219     return values;
0220   }
0221 
0222   @Override
0223   public void resourceLoaded(CreoleEvent e) {
0224     repaint();
0225   }
0226 
0227   @Override
0228   public void resourceUnloaded(CreoleEvent e) {
0229     repaint();
0230   }
0231 
0232   @Override
0233   public void resourceRenamed(Resource resource, String oldName, String newName) {
0234     repaint();
0235   }
0236 
0237   @Override
0238   public void datastoreOpened(CreoleEvent e) {
0239   }
0240 
0241   @Override
0242   public void datastoreCreated(CreoleEvent e) {
0243   }
0244 
0245   @Override
0246   public void datastoreClosed(CreoleEvent e) {
0247   }
0248 
0249   public void setEditable(boolean editable) {
0250     this.editable = editable;
0251   }
0252 
0253   public boolean isEditable() {
0254     return editable;
0255   }
0256 
0257   /**
0258    * Called by other GUI classes that use this as a subcomponent that
0259    * doesn't need to update with the creole register changes.
0260    */
0261   void removeCreoleListenerLink() {
0262     // this component is only used as a viewer now; it doesn't need to
0263     // update
0264     // so we don't need to listen to creole events
0265     Gate.getCreoleRegister().removeCreoleListener(this);
0266     if(parameterDisjunctions != null && parameterDisjunctions.size() 0) {
0267       for(int i = 0; i < parameterDisjunctions.size(); i++) {
0268         parameterDisjunctions.get(i).removeCreoleListenerLink();
0269       }
0270     }
0271 
0272   }
0273 
0274   ParametersTableModel tableModel;
0275 
0276   Resource resource;
0277   
0278   ResourceData resourceData;
0279 
0280   /**
0281    * A pointer to the filechooser from MainFrame.
0282    */
0283   static XJFileChooser fileChooser;
0284 
0285   String fileChooserResource;
0286 
0287   /**
0288    * A list of {@link ParameterDisjunction}
0289    */
0290   protected List<ParameterDisjunction> parameterDisjunctions;
0291 
0292   protected boolean editable = true;
0293 
0294   // inner classes
0295   protected class ParametersTableModel extends AbstractTableModel {
0296 
0297     @Override
0298     public int getColumnCount() {
0299       return 4;
0300     }
0301 
0302     @Override
0303     public Class<?> getColumnClass(int columnIndex) {
0304       switch(columnIndex) {
0305         case 0:
0306           return ParameterDisjunction.class;
0307         case 1:
0308           return String.class;
0309         case 2:
0310           return Boolean.class;
0311         case 3:
0312           return Object.class;
0313         default:
0314           return Object.class;
0315       }
0316     }// public Class getColumnClass(int columnIndex)
0317 
0318     @Override
0319     public String getColumnName(int columnIndex) {
0320       switch(columnIndex) {
0321         case 0:
0322           return "Name";
0323         case 1:
0324           return "Type";
0325         case 2:
0326           return "Required";
0327         case 3:
0328           return "Value";
0329         default:
0330           return "?";
0331       }
0332     }// public String getColumnName(int columnIndex)
0333 
0334     @Override
0335     public boolean isCellEditable(int rowIndex, int columnIndex) {
0336       switch(columnIndex) {
0337         case 0:
0338           return parameterDisjunctions.get(rowIndex).size() 1;
0339         case 1:
0340           return false;
0341         case 2:
0342           return false;
0343         case 3:
0344           return editable;
0345         default:
0346           return false;
0347       }
0348     }// public boolean isCellEditable
0349 
0350     @Override
0351     public int getRowCount() {
0352       return (parameterDisjunctions == null: parameterDisjunctions.size();
0353     }
0354 
0355     @Override
0356     public Object getValueAt(int rowIndex, int columnIndex) {
0357       ParameterDisjunction pDisj = parameterDisjunctions.get(rowIndex);
0358       switch(columnIndex) {
0359         case 0:
0360           return pDisj;
0361         case 1:
0362           String paramType = pDisj.getType();
0363           return paramType.substring(paramType.lastIndexOf('.'1)
0364         case 2:
0365           return pDisj.isRequired();
0366         case 3:
0367           return pDisj.getValue();
0368         default:
0369           return "?";
0370       }
0371     }// public Object getValueAt
0372 
0373     @Override
0374     public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
0375       ParameterDisjunction pDisj = parameterDisjunctions.get(rowIndex);
0376       switch(columnIndex) {
0377         case 0{
0378           if(aValue instanceof ParameterDisjunction){
0379             //do nothing
0380           else if (aValue instanceof Integer){
0381             pDisj.setSelectedIndex((IntegeraValue);
0382           }
0383           break;
0384         }
0385         case 1{
0386           break;
0387         }
0388         case 2{
0389           break;
0390         }
0391         case 3{
0392           Object oldValue = pDisj.getValue();
0393           if (!Objects.equals(oldValue, aValue)) {
0394             pDisj.setValue(aValue);
0395             if (ResourceParametersEditor.this == null || ResourceParametersEditor.this.resource == nullbreak;
0396             try {
0397               ResourceParametersEditor.this.resource.setParameterValue(pDisj.getName(), pDisj.getValue());
0398             catch(ResourceInstantiationException e) {
0399               e.printStackTrace();
0400             }            
0401           }
0402           break;
0403         }
0404         default{
0405         }
0406       }
0407       tableModel.fireTableCellUpdated(rowIndex, columnIndex);
0408     }// public void setValueAt
0409   }// /class FeaturesTableModel extends DefaultTableModel
0410 
0411   class ParameterDisjunctionRenderer extends DefaultTableCellRenderer {
0412     public ParameterDisjunctionRenderer() {
0413       combo = new JComboBox();
0414       class CustomRenderer extends JLabel implements ListCellRenderer {
0415         @Override
0416         public Component getListCellRendererComponent(JList list, Object value,
0417                 int index, boolean isSelected, boolean cellHasFocus) {
0418 
0419           setText(text);
0420           setIcon(MainFrame.getIcon(iconName));
0421           return this;
0422         }
0423       }
0424       combo.setRenderer(new CustomRenderer());
0425     }
0426 
0427     @Override
0428     public Component getTableCellRendererComponent(JTable table, Object value,
0429             boolean isSelected, boolean hasFocus, int row, int column) {
0430       ParameterDisjunction pDisj = (ParameterDisjunction)value;
0431       text = pDisj.getName();
0432       String type = pDisj.getType();
0433       iconName = "param";
0434       if(Gate.isGateType(type)) {
0435         ResourceData rData = Gate.getCreoleRegister().get(type);
0436         if(rData != nulliconName = rData.getIcon();
0437       }
0438       if(pDisj.size() 1) {
0439         combo.setModel(new DefaultComboBoxModel(new Object[] {text}));
0440         return combo;
0441       }
0442       // prepare the renderer
0443       super.getTableCellRendererComponent(table, text, isSelected,
0444         hasFocus, row, column);
0445       setIcon(MainFrame.getIcon(iconName));
0446       return this;
0447     }// public Component getTableCellRendererComponent
0448 
0449     // combobox used for OR parameters
0450     JComboBox combo;
0451 
0452     String iconName;
0453 
0454     String text;
0455   }// class ParameterDisjunctionRenderer
0456 
0457   /**
0458    * A renderer that displays a File Open button next to a text field.
0459    * Used for setting URLs from files.
0460    */
0461   class ParameterValueRenderer extends DefaultTableCellRenderer {
0462     public ParameterValueRenderer() {
0463       fileButton = new JButton(MainFrame.getIcon("open-file"));
0464       fileButton.setToolTipText("Browse the file system");
0465       listButton = new JButton(MainFrame.getIcon("edit-list"));
0466       listButton.setToolTipText("Edit the list");
0467       fmButton = new JButton(MainFrame.getIcon("edit-list"));
0468       fmButton.setToolTipText("Edit the feature map");
0469       textField = new JTextField(){
0470         @Override
0471         public Dimension getMinimumSize() {
0472           //we don't want to be squashed!
0473           Dimension size = getPreferredSize();
0474           if(size.width < 300) {
0475             size.width = 300;
0476           }
0477           // we should not be larger than the screen
0478           Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
0479           if(size.width > 0.95 * screenSize.width) {
0480             size.width = (int)0.95 * screenSize.width;
0481           }
0482           return size;
0483         }
0484       };
0485       textButtonBox = new JPanel();
0486       textButtonBox.setLayout(new BoxLayout(textButtonBox, BoxLayout.X_AXIS));
0487       textButtonBox.setOpaque(false);
0488       combo = new JComboBox();
0489       combo.setRenderer(new ResourceRenderer());
0490     }// CustomObjectRenderer()
0491 
0492     @Override
0493     public Component getTableCellRendererComponent(JTable table, Object value,
0494             boolean isSelected, boolean hasFocus, int row, int column) {
0495 
0496       ParameterDisjunction pDisj = (ParameterDisjunction)table
0497         .getValueAt(row, convertColumnIndexToView(0));
0498       String type = pDisj.getType();
0499       // set the tooltip
0500       combo.setToolTipText(pDisj.getComment());
0501       textField.setToolTipText(pDisj.getComment());
0502       textButtonBox.setToolTipText(pDisj.getComment());
0503 
0504       if(Gate.isGateType(type)) {
0505         // Gate type
0506         if(ResourceParametersEditor.this.isEditable()) {
0507           combo.setModel(new DefaultComboBoxModel(new Object[] {value == null
0508                   "<none>"
0509                   : value}));
0510           return combo;
0511         }
0512         else {
0513           // not editable; we'll just use the text field
0514           // prepare the renderer
0515           String text = value == null "<none>" : value.toString();
0516           // super.getTableCellRendererComponent(table, text,
0517           // isSelected,
0518           // hasFocus, row, column);
0519           textField.setText(text);
0520           return textField;
0521         }
0522       }
0523       else {
0524         Class<?> typeClass = null;
0525         try {
0526           // load type class through GATE classloader
0527           typeClass = Class.forName(type, true, Gate.getClassLoader());
0528         }
0529         catch(ClassNotFoundException cnfe) {
0530           cnfe.printStackTrace();
0531         }
0532         // non Gate type -> we'll use the text field
0533         String text = (value == null)
0534                 ""
0535                 : value.toString();
0536         // prepare the renderer
0537         textField.setText(text);
0538         // super.getTableCellRendererComponent(table, text, isSelected,
0539         // hasFocus, row, column);
0540 
0541         if(type.equals("java.net.URL")) {
0542           if(ResourceParametersEditor.this.isEditable()) {
0543             textButtonBox.removeAll();
0544             textField.setText(text);
0545             // textButtonBox.add(this);
0546             textButtonBox.add(textField);
0547             // this.setMaximumSize(new Dimension(Integer.MAX_VALUE,
0548             // getPreferredSize().height));
0549             textButtonBox.add(Box.createHorizontalStrut(5));
0550             textButtonBox.add(fileButton);
0551             return textButtonBox;
0552           }
0553           else {
0554             // return this;
0555             return textField;
0556           }
0557         }
0558         else if(typeClass != null
0559                 && Collection.class.isAssignableFrom(typeClass)) {
0560           // List value
0561           // setText(textForList((List)value));
0562           textField.setText(textForList((Collection<?>)value));
0563           if(ResourceParametersEditor.this.isEditable()) {
0564             textButtonBox.removeAll();
0565             // textButtonBox.add(this);
0566             textButtonBox.add(textField);
0567             // this.setMaximumSize(new Dimension(Integer.MAX_VALUE,
0568             // getPreferredSize().height));
0569             textButtonBox.add(Box.createHorizontalStrut(5));
0570             textButtonBox.add(listButton);
0571             return textButtonBox;
0572           }
0573         }
0574         else if(typeClass != null
0575                 && FeatureMap.class.isAssignableFrom(typeClass)) {
0576           textField.setText(textForFeatureMap((FeatureMap)value));
0577           if(ResourceParametersEditor.this.isEditable()) {
0578             textButtonBox.removeAll();
0579             textButtonBox.add(textField);
0580             textButtonBox.add(Box.createHorizontalStrut(5));
0581             textButtonBox.add(fmButton);
0582             return textButtonBox;
0583           }
0584         }
0585         else if(typeClass != null && typeClass.isEnum()) {
0586           if(ResourceParametersEditor.this.isEditable()) {
0587             combo.setModel(new DefaultComboBoxModel(new Object[] {value == null
0588                     "<none>"
0589                     : value}));
0590             return combo;
0591           }
0592           else {
0593             return textField;
0594           }
0595         }
0596         else {
0597           // return this;
0598           return textField;
0599         }
0600 
0601         // not actually reachable, but keeps the compiler happy
0602         return textField;
0603       }
0604     }// public Component getTableCellRendererComponent
0605 
0606 
0607     JButton fileButton;
0608 
0609     JButton listButton;
0610 
0611     JButton fmButton;
0612 
0613     JComboBox combo;
0614 
0615     JPanel textButtonBox;
0616 
0617     JTextField textField;
0618   }// class ObjectRenderer extends DefaultTableCellRenderer
0619 
0620   class ParameterDisjunctionComparator implements Comparator<ParameterDisjunction> {
0621     @Override
0622     public int compare(ParameterDisjunction pDisj1, ParameterDisjunction pDisj2) {
0623       return pDisj1.getName().compareTo(pDisj2.getName());
0624     }
0625   }
0626 
0627   class ParameterDisjunctionEditor extends DefaultCellEditor {
0628     public ParameterDisjunctionEditor() {
0629       super(new JComboBox());
0630       combo = (JComboBox)super.getComponent();
0631       class CustomRenderer extends JLabel implements ListCellRenderer {
0632         public CustomRenderer() {
0633           setOpaque(true);
0634         }
0635 
0636         @Override
0637         public Component getListCellRendererComponent(JList list, Object value,
0638                 int index, boolean isSelected, boolean cellHasFocus) {
0639           if(isSelected) {
0640             setBackground(list.getSelectionBackground());
0641             setForeground(list.getSelectionForeground());
0642           }
0643           else {
0644             setBackground(list.getBackground());
0645             setForeground(list.getForeground());
0646           }
0647 
0648           setFont(list.getFont());
0649 
0650           setText((String)value);
0651 
0652           String iconName = "param";
0653           Parameter[] params = pDisj.getParameters();
0654           for(int i = 0; i < params.length; i++) {
0655             Parameter param = params[i];
0656             if(param.getName().equals(value)) {
0657               String type = param.getTypeName();
0658               if(Gate.getCreoleRegister().containsKey(type)) {
0659                 ResourceData rData = Gate.getCreoleRegister()
0660                         .get(type);
0661                 if(rData != nulliconName = rData.getIcon();
0662               }
0663               break;
0664             }// if(params[i].getName().equals(value))
0665           }// for(int i = 0; params.length; i++)
0666 
0667           setIcon(MainFrame.getIcon(iconName));
0668           return this;
0669         }
0670       // class CustomRenderer extends JLabel implements
0671         // ListCellRenderer
0672       combo.setRenderer(new CustomRenderer());
0673       combo.addActionListener(new ActionListener() {
0674         @Override
0675         public void actionPerformed(ActionEvent e) {
0676           pDisj.setSelectedIndex(combo.getSelectedIndex());
0677           stopCellEditing();
0678         }
0679       });
0680     }// public ParameterDisjunctionEditor()
0681 
0682     @Override
0683     public Component getTableCellEditorComponent(JTable table, Object value,
0684             boolean isSelected, int row, int column) {
0685       pDisj = (ParameterDisjunction)value;
0686       DefaultComboBoxModel comboModel = new DefaultComboBoxModel(pDisj.getNames());
0687       combo.setModel(comboModel);
0688       combo.setSelectedIndex(pDisj.getSelectedIndex());
0689       return combo;
0690     }// public Component getTableCellEditorComponent
0691 
0692     @Override
0693     public Object getCellEditorValue() {
0694       pDisj.setSelectedIndex(combo.getSelectedIndex());
0695 //      return combo.getSelectedIndex();
0696       return pDisj;
0697     }
0698 
0699     @Override
0700     public boolean stopCellEditing() {
0701       combo.hidePopup();
0702       return super.stopCellEditing();
0703     }
0704 
0705     JComboBox combo;
0706 
0707     ParameterDisjunction pDisj;
0708   }// class ParameterDisjunctionEditor extends DefaultCellEditor
0709 
0710   class ParameterValueEditor extends AbstractCellEditor implements
0711                                                        TableCellEditor {
0712     ParameterValueEditor() {
0713       combo = new JComboBox();
0714       combo.setRenderer(new ResourceRenderer());
0715       combo.setEditable(false);
0716 
0717       textField = new JTextField(20);
0718 
0719       fileButton = new JButton(MainFrame.getIcon("open-file"));
0720       fileButton.setToolTipText("Browse the file system");
0721       fileButton.addActionListener(new ActionListener() {
0722         @Override
0723         public void actionPerformed(ActionEvent e) {
0724           fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
0725           fileChooser.setDialogTitle("Select a file");
0726           fileChooser.setResource(fileChooserResource);
0727           int res = fileChooser.showOpenDialog(ResourceParametersEditor.this);
0728           if(res == JFileChooser.APPROVE_OPTION) {
0729             try {
0730               textField.setText(fileChooser.getSelectedFile().toURI().toURL()
0731                       .toExternalForm());
0732             }
0733             catch(IOException ioe) {
0734               ioe.printStackTrace();
0735             }
0736             fireEditingStopped();
0737           }
0738           else {
0739             fireEditingCanceled();
0740           }
0741         }
0742       });
0743 
0744       listButton = new JButton(MainFrame.getIcon("edit-list"));
0745       listButton.setToolTipText("Edit the list");
0746       listButton.addActionListener(new ActionListener() {
0747         @Override
0748         public void actionPerformed(ActionEvent e) {
0749           List<?> returnedList = listEditor.showDialog();
0750           if(returnedList != null) {
0751             listValue = returnedList;
0752             fireEditingStopped();
0753           }
0754           else {
0755             fireEditingCanceled();
0756           }
0757         }
0758       });
0759 
0760       fmButton = new JButton(MainFrame.getIcon("edit-list"));
0761       fmButton.setToolTipText("Edit the feature map");
0762       fmButton.addActionListener(new ActionListener() {
0763         @Override
0764         public void actionPerformed(ActionEvent e) {
0765           FeatureMap returnedFM = fmEditor.showDialog();
0766           if(returnedFM != null) {
0767             fmValue = returnedFM;
0768             fireEditingStopped();
0769           }
0770           else {
0771             fireEditingCanceled();
0772           }
0773         }
0774       });
0775 
0776       textButtonBox = new JPanel();
0777       textButtonBox.setLayout(new BoxLayout(textButtonBox, BoxLayout.X_AXIS));
0778       textButtonBox.setOpaque(false);
0779       textFieldBoolean = new JTextField();
0780       textFieldBoolean.setEditable(false);
0781       textFieldBoolean.addMouseListener(new MouseAdapter() {
0782         @Override
0783         public void mouseClicked(MouseEvent e) {
0784           Boolean value = Boolean.valueOf(textFieldBoolean.getText());
0785           value = !value;
0786           textFieldBoolean.setText(value.toString());
0787         }
0788       });
0789       textFieldBoolean.addKeyListener(new KeyAdapter() {
0790         @Override
0791         public void keyTyped(KeyEvent e) {
0792           Boolean value = Boolean.valueOf(textFieldBoolean.getText());
0793           value = !value;
0794           textFieldBoolean.setText(value.toString());
0795         }
0796       });
0797 
0798       textButtonBox.addFocusListener(new FocusAdapter() {
0799         @Override
0800         public void focusGained(FocusEvent e) {
0801           if(!comboUsed) {
0802             // needed because the focus would otherwise stay
0803             // on the textButtonBox panel
0804             textField.requestFocusInWindow();
0805           }
0806         }
0807       });
0808       // select the opposite element when tab key is pressed
0809       textField.addKeyListener(new KeyAdapter() {
0810         @Override
0811         public void keyPressed(KeyEvent e) {
0812           JTextField textField = (JTextFielde.getSource();
0813           if((e.getKeyCode() == KeyEvent.VK_TAB)
0814           && textField.getParent().getComponentCount() == 3) {
0815             textField.getParent().getComponent(2).requestFocusInWindow();
0816             e.consume();
0817           }
0818         }
0819       });
0820 
0821     }// ParameterValueEditor()
0822 
0823     @Override
0824     public Component getTableCellEditorComponent(JTable table, Object value,
0825             boolean isSelected, int row, int column) {
0826       comboUsed = false;
0827       listUsed = false;
0828       fmUsed = false;
0829       ParameterDisjunction pDisj = (ParameterDisjunction)table
0830         .getValueAt(row, convertColumnIndexToView(0));
0831       type = pDisj.getType();
0832       // set the tooltip
0833       combo.setToolTipText(pDisj.getComment());
0834       textField.setToolTipText(pDisj.getComment());
0835       textFieldBoolean.setToolTipText(pDisj.getComment());
0836 
0837       if(Gate.isGateType(type)) {
0838         // Gate type
0839         comboUsed = true;
0840         ArrayList<Object> values = new ArrayList<Object>();
0841         try {
0842           values.addAll(Gate.getCreoleRegister().getAllInstances(type));
0843         }
0844         catch(GateException ge) {
0845           ge.printStackTrace(Err.getPrintWriter());
0846         }
0847         values.add(0"<none>");
0848         combo.setModel(new DefaultComboBoxModel(values.toArray()));
0849         combo.setSelectedItem(value == null "<none>" : value);
0850         return combo;
0851       }
0852       else {
0853         // non Gate type
0854         Class<?> typeClass = null;
0855         try {
0856           // load type class through GATE classloader
0857           typeClass = Class.forName(type, true, Gate.getClassLoader());
0858         }
0859         catch(ClassNotFoundException cnfe) {
0860           cnfe.printStackTrace();
0861         }
0862 
0863         textField.setText((value == null"" : value.toString());
0864         if(type.equals("java.net.URL")) {
0865           // clean up all filters
0866           fileChooser.resetChoosableFileFilters();
0867           fileChooser.setAcceptAllFileFilterUsed(true);
0868           fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
0869           Parameter param = pDisj.getParameter();
0870           
0871           Set<String> sufixes = null;          
0872           
0873           //This handles the special case of the sourceUrl param when creating documents
0874           //so that we get the suffix list from the set of loaded document formats rather
0875           //than from the data for the resource type we are loading.
0876           if (resourceData != null) {
0877             if (param.getName().equals("sourceUrl"&& resourceData.getClassName().equals(DocumentImpl.class.getName())) {
0878               sufixes = DocumentFormat.getSupportedFileSuffixes();
0879             }
0880           }
0881           
0882           //if we haven't loaded any suffixes then fall back to the original behaviour
0883           if (sufixes == null || sufixes.isEmpty()) sufixes = param.getSuffixes();
0884           
0885           if(sufixes != null) {
0886             ExtensionFileFilter fileFilter = new ExtensionFileFilter();
0887             Iterator<String> sufIter = sufixes.iterator();
0888             while(sufIter.hasNext()) {
0889               fileFilter.addExtension(sufIter.next());
0890             }
0891             fileFilter.setDescription("Known file types " + sufixes.toString());
0892             fileChooser.addChoosableFileFilter(fileFilter);
0893             fileChooser.setFileFilter(fileFilter);
0894           }
0895 
0896           textField.setEditable(true);
0897           textButtonBox.removeAll();
0898           textButtonBox.add(textField);
0899           textButtonBox.add(Box.createHorizontalStrut(5));
0900           textButtonBox.add(fileButton);
0901           return textButtonBox;
0902         }
0903         else if(type.equals("java.lang.Boolean")) {
0904           textFieldBoolean.setText(value == null "false" : value.toString());
0905           return textFieldBoolean;
0906         }
0907         else if(typeClass != null
0908                 && Collection.class.isAssignableFrom(typeClass)) {
0909           // List value
0910           listUsed = true;
0911           Parameter param = pDisj.getParameter();
0912 
0913           listValue = (Collection<?>)value;
0914           listEditor = new ListEditorDialog(SwingUtilities.getAncestorOfClass(
0915                   Window.class, ResourceParametersEditor.this),
0916                   (Collection<?>)value, typeClass, param.getItemClassName());
0917 
0918           textField.setEditable(false);
0919           textField.setText(textForList((Collection<?>)value));
0920           textButtonBox.removeAll();
0921           textButtonBox.add(textField);
0922           textButtonBox.add(Box.createHorizontalStrut(5));
0923           textButtonBox.add(listButton);
0924           return textButtonBox;
0925         }
0926         else if(typeClass != null
0927                 && FeatureMap.class.isAssignableFrom(typeClass)) {
0928           // List value
0929           fmUsed = true;
0930 
0931           fmValue = (FeatureMap)value;
0932           fmEditor = new FeatureMapEditorDialog(SwingUtilities
0933                   .getAncestorOfClass(Window.class,
0934                           ResourceParametersEditor.this)(FeatureMap)value);
0935 
0936           textField.setEditable(false);
0937           textField.setText(textForFeatureMap((FeatureMap)value));
0938           textButtonBox.removeAll();
0939           textButtonBox.add(textField);
0940           textButtonBox.add(Box.createHorizontalStrut(5));
0941           textButtonBox.add(fmButton);
0942           return textButtonBox;
0943         }
0944         else if(typeClass != null && typeClass.isEnum()) {
0945           comboUsed = true;
0946           try {
0947             // extract list of allowable values by reflection - every
0948             // enum type has a values method returning an array of values
0949             Method getValuesMethod = typeClass.getMethod("values");
0950             Object[] enumValues = (Object[])getValuesMethod.invoke(null);
0951             Object[] comboValues = null;
0952             Parameter param = pDisj.getParameter();
0953             // only allow selection of "<none>" for optional parameters
0954             if(param.isOptional()) {
0955               comboValues = new Object[enumValues.length + 1];
0956               comboValues[0"<none>";
0957               System.arraycopy(enumValues, 0, comboValues, 1,enumValues.length);
0958             }
0959             else {
0960               comboValues = enumValues;
0961             }
0962             combo.setModel(new DefaultComboBoxModel(comboValues));
0963             combo.setSelectedItem(value == null "<none>" : value);
0964             return combo;
0965           }
0966           catch(Exception ex) {
0967             throw new LuckyException("Error calling \"values\" method of an "
0968                     "enum type", ex);
0969           }
0970         }
0971         else {
0972           textField.setEditable(true);
0973           return textField;
0974         }
0975       }
0976     }// getTableCellEditorComponent
0977 
0978     @Override
0979     public Object getCellEditorValue() {
0980       if(comboUsed) {
0981         Object value = combo.getSelectedItem();
0982         return value == "<none>" null : value;
0983       }
0984       else if(listUsed) {
0985         return listValue;
0986       }
0987       else if(fmUsed) {
0988         return fmValue;
0989       }
0990       else {
0991         if(type.equals("java.lang.Boolean")) {
0992           // get the value from the label
0993           return Boolean.valueOf(textFieldBoolean.getText());
0994         }
0995         else {
0996           // get the value from the text field
0997           return textField.getText();
0998           // return ((textField.getText().equals("")) ? null :
0999           // textField.getText());
1000         }
1001       }
1002     }// public Object getCellEditorValue()
1003 
1004     /**
1005      * The type of the value currently being edited
1006      */
1007     String type;
1008 
1009     /**
1010      * Combobox use as editor for Gate objects (chooses between
1011      * instances)
1012      */
1013     JComboBox combo;
1014 
1015     /**
1016      * Generic editor for all types that are not treated special
1017      */
1018     JTextField textField;
1019 
1020     /**
1021      * Editor used for boolean values.
1022      */
1023     JTextField textFieldBoolean;
1024 
1025     ListEditorDialog listEditor = null;
1026 
1027     Collection<?> listValue;
1028 
1029     FeatureMapEditorDialog fmEditor = null;
1030 
1031     FeatureMap fmValue;
1032 
1033     boolean comboUsed;
1034 
1035     boolean listUsed;
1036 
1037     boolean fmUsed;
1038 
1039     JButton fileButton;
1040 
1041     JButton listButton;
1042 
1043     JButton fmButton;
1044 
1045     /** Contains a textfield and a button */
1046     JPanel textButtonBox;
1047   }// /class ParameterValueEditor
1048 
1049   /**
1050    * Gets a string representation for a list value
1051    */
1052   protected String textForList(Collection<?> list) {
1053     if(list == null || list.isEmpty()) return "[]";
1054     StringBuilder res = new StringBuilder("[");
1055     Iterator<?> elemIter = list.iterator();
1056     while(elemIter.hasNext()) {
1057       Object elem = elemIter.next();
1058       if(elem != null)
1059         res.append((elem instanceof NameBearer?
1060           ((NameBearerelem).getName() : elem.toString())
1061           .append(", ");
1062       else res.append("<null>, ");
1063     }
1064     res.delete(res.length() 2, res.length() 1);
1065     res.append("]");
1066     return res.toString();
1067   }
1068 
1069   /**
1070    * Get a string representation for a FeatureMap value.
1071    */
1072   protected String textForFeatureMap(FeatureMap fm) {
1073     return (fm == null"" : fm.toString();
1074   }
1075 
1076 }// class NewResourceDialog