1   /*
2    *  Copyright (c) 1998-2001, The University of Sheffield.
3    *
4    *  This file is part of GATE (see http://gate.ac.uk/), and is free
5    *  software, licenced under the GNU Library General Public License,
6    *  Version 2, June 1991 (in the distribution as file licence.html,
7    *  and also available at http://gate.ac.uk/gate/licence.html).
8    *
9    *  Valentin Tablan 03/10/2001
10   *
11   *  $Id: ResourceParametersEditor.java,v 1.20 2001/11/29 15:15:01 valyt Exp $
12   *
13   */
14  
15  package gate.gui;
16  
17  import java.awt.Frame;
18  import java.awt.BorderLayout;
19  import java.awt.Component;
20  import java.awt.Dimension;
21  import java.awt.Insets;
22  import java.awt.Graphics;
23  import java.awt.event.*;
24  import javax.swing.*;
25  import javax.swing.table.*;
26  import javax.swing.tree.*;
27  import javax.swing.event.*;
28  import javax.swing.border.*;
29  
30  import java.util.*;
31  import java.net.URL;
32  import java.io.IOException;
33  import java.text.*;
34  
35  import gate.*;
36  import gate.util.*;
37  import gate.swing.*;
38  import gate.creole.*;
39  import gate.event.*;
40  
41  /**
42   * Allows the editing of a set of parameters for a resource. It needs a pointer
43   * to the resource and a list of the parameter names for the parameters that
44   * should be displayed. The list of the parameters is actually a list of lists
45   * of strings representing parameter disjunctions.
46   */
47  public class ResourceParametersEditor extends XJTable implements CreoleListener{
48  
49    public ResourceParametersEditor(){
50      initLocalData();
51      initGuiComponents();
52      initListeners();
53    }
54  
55    /**
56     * Initialises this GUI component.
57     * @param the resource for which the parameters need to be set.
58     * @param paramaters a list of lists of {@link Parameter} representing
59     * parameter disjunctions.
60     */
61    public void init(Resource resource, List parameters){
62      this.resource = resource;
63      if(parameters != null){
64        parameterDisjunctions = new ArrayList(parameters.size());
65        for(int i = 0; i < parameters.size(); i++){
66          parameterDisjunctions.add(
67                              new ParameterDisjunction(resource,
68                                                       (List)parameters.get(i)));
69        }
70      }else{
71        parameterDisjunctions = null;
72      }
73      tableModel.fireTableDataChanged();
74      adjustSizes();
75    }
76  
77    protected void initLocalData(){
78      resource = null;
79      parameterDisjunctions = null;
80    }// protected void initLocalData()
81  
82    protected void initGuiComponents(){
83      setModel(tableModel = new ParametersTableModel());
84  
85      getColumnModel().getColumn(0).
86                       setCellRenderer(new ParameterDisjunctionRenderer());
87  
88      getColumnModel().getColumn(1).
89                       setCellRenderer(new DefaultTableCellRenderer());
90  
91      getColumnModel().getColumn(2).
92                       setCellRenderer(new BooleanRenderer());
93  
94      getColumnModel().getColumn(3).
95                       setCellRenderer(new ParameterValueRenderer());
96  
97  
98      getColumnModel().getColumn(0).
99                       setCellEditor(new ParameterDisjunctionEditor());
100 
101     getColumnModel().getColumn(3).
102                      setCellEditor(new ParameterValueEditor());
103 
104     setIntercellSpacing(new Dimension(5, 5));
105   }// protected void initGuiComponents()
106 
107 
108   protected void initListeners(){
109     Gate.getCreoleRegister().addCreoleListener(this);
110     addKeyListener(new KeyAdapter() {
111       public void keyTyped(KeyEvent e) {
112         if(e.getKeyCode() == e.VK_ENTER){
113           if(getEditingColumn() == -1 && getEditingRow() == -1){
114             getParent().dispatchEvent(e);
115           }
116         }
117       }
118 
119       public void keyPressed(KeyEvent e) {
120       }
121 
122       public void keyReleased(KeyEvent e) {
123       }
124     });
125   }
126 
127   /**
128    * Disable key handling for most keys by JTable when not editing.
129    */
130   protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
131                                       int condition, boolean pressed) {
132     int keyCode = e.getKeyCode();
133     if(isEditing() ||
134        keyCode == KeyEvent.VK_UP ||
135        keyCode == KeyEvent.VK_DOWN ||
136        keyCode == KeyEvent.VK_LEFT ||
137        keyCode == KeyEvent.VK_RIGHT ||
138        keyCode == KeyEvent.VK_TAB) return super.processKeyBinding(ks, e,
139                                                                   condition,
140                                                                   pressed);
141     return false;
142   }
143 
144   /**
145    * Should this GUI comonent allow editing?
146    */
147 
148   /**
149    * Sets the parameters for the resource to their new values as resulted
150    * from the user's edits.
151    */
152   public void setParameters() throws ResourceInstantiationException{
153     if(resource == null || parameterDisjunctions == null) return;
154     //stop current edits
155     if(getEditingColumn() != -1 && getEditingRow() != -1){
156       editingStopped(new ChangeEvent(getCellEditor(getEditingRow(),
157                                                    getEditingColumn())));
158     }
159     //set the parameters
160     for(int i = 0; i < parameterDisjunctions.size(); i++){
161       ParameterDisjunction pDisj = (ParameterDisjunction)
162                                    parameterDisjunctions.get(i);
163       resource.setParameterValue(pDisj.getName(), pDisj.getValue());
164     }
165   }
166 
167   /**
168    * Does this GUI component allow editing?
169    */
170 
171   public Resource getResource() {
172     return resource;
173   }
174 
175   /**
176    * Gets the current values for the parameters.
177    * @return a {@link FeatureMap} conatining the curent values for the curently
178    * selected parameters in each disjunction.
179    */
180   public FeatureMap getParameterValues(){
181     //stop current edits
182     if(getEditingColumn() != -1 && getEditingRow() != -1){
183       editingStopped(new ChangeEvent(getCellEditor(getEditingRow(),
184                                                    getEditingColumn())));
185     }
186     //get the parameters
187     FeatureMap values = Factory.newFeatureMap();
188     if(parameterDisjunctions != null){
189       for(int i = 0; i < parameterDisjunctions.size(); i++){
190         ParameterDisjunction pDisj = (ParameterDisjunction)
191                                      parameterDisjunctions.get(i);
192         values.put(pDisj.getName(), pDisj.getValue());
193       }
194     }
195     return values;
196   }
197 
198   public void resourceLoaded(CreoleEvent e) {
199     repaint();
200   }
201   public void resourceUnloaded(CreoleEvent e) {
202     repaint();
203   }
204   public void datastoreOpened(CreoleEvent e) {
205   }
206   public void datastoreCreated(CreoleEvent e) {
207   }
208   public void datastoreClosed(CreoleEvent e) {
209   }
210 
211   ParametersTableModel tableModel;
212   Resource resource;
213 
214 
215 
216   /**
217    * A list of {@link ParameterDisjunction}
218    */
219   protected List parameterDisjunctions;
220 
221   //inner classes
222   protected class ParametersTableModel extends AbstractTableModel{
223 
224     public int getColumnCount(){return 4;}
225 
226     public Class getColumnClass(int columnIndex){
227       switch(columnIndex){
228         case 0: return ParameterDisjunction.class;
229         case 1: return String.class;
230         case 2: return Boolean.class;
231         case 3: return Object.class;
232         default: return Object.class;
233       }
234     }// public Class getColumnClass(int columnIndex)
235 
236     public String getColumnName(int columnIndex){
237       switch(columnIndex){
238         case 0: return "Name";
239         case 1: return "Type";
240         case 2: return "Required";
241         case 3: return "Value";
242         default: return "?";
243       }
244     }//public String getColumnName(int columnIndex)
245 
246     public boolean isCellEditable(int rowIndex,
247                               int columnIndex) {
248       switch(columnIndex){
249         case 0: return ((ParameterDisjunction)
250                         parameterDisjunctions.get(rowIndex)).size() > 1;
251         case 1: return false;
252         case 2: return false;
253         case 3: return true;
254         default: return false;
255       }
256     }// public boolean isCellEditable
257 
258     public int getRowCount(){
259       return (parameterDisjunctions == null) ? 0 : parameterDisjunctions.size();
260     }
261 
262     public Object getValueAt(int rowIndex,
263                          int columnIndex) {
264       ParameterDisjunction pDisj = (ParameterDisjunction)
265                                    parameterDisjunctions.get(rowIndex);
266       switch(columnIndex){
267         case 0: return pDisj;
268         case 1: return pDisj.getType();
269         case 2: return pDisj.isRequired();
270         case 3: return pDisj.getValue();
271         default: return "?";
272       }
273     }// public Object getValueAt
274 
275     public void setValueAt(Object aValue, int rowIndex, int columnIndex){
276       ParameterDisjunction pDisj = (ParameterDisjunction)
277                                    parameterDisjunctions.get(rowIndex);
278       switch(columnIndex){
279         case 0:{
280           pDisj.setSelectedIndex(((Integer)aValue).intValue());
281           break;
282         }
283         case 1:{
284           break;
285         }
286         case 2:{
287           break;
288         }
289         case 3:{
290           pDisj.setValue(aValue);
291           break;
292         }
293         default:{}
294       }
295     }// public void setValueAt
296   }///class FeaturesTableModel extends DefaultTableModel
297 
298   class ParameterDisjunctionRenderer extends DefaultTableCellRenderer {
299     public ParameterDisjunctionRenderer(){
300       combo = new JComboBox();
301       class CustomRenderer extends JLabel implements ListCellRenderer {
302         public Component getListCellRendererComponent(JList list,
303                                                       Object value,
304                                                       int index,
305                                                       boolean isSelected,
306                                                       boolean cellHasFocus){
307 
308           setText(text);
309           setIcon(MainFrame.getIcon(iconName));
310           return this;
311         }
312       };
313       combo.setRenderer(new CustomRenderer());
314     }
315 
316     public Component getTableCellRendererComponent(JTable table,
317                                                    Object value,
318                                                    boolean isSelected,
319                                                    boolean hasFocus,
320                                                    int row,
321                                                    int column) {
322       ParameterDisjunction pDisj = (ParameterDisjunction)value;
323       text = pDisj.getName();
324       String type = pDisj.getType();
325       iconName = "param.gif";
326       if(Gate.isGateType(type)){
327         ResourceData rData = (ResourceData)Gate.getCreoleRegister().get(type);
328         if(rData != null) iconName = rData.getIcon();
329       }
330       if(pDisj.size() > 1){
331         combo.setModel(new DefaultComboBoxModel(new Object[]{text}));
332         return combo;
333       }
334       //prepare the renderer
335       Component comp = super.getTableCellRendererComponent(table,
336                                                            text,
337                                                            isSelected, hasFocus,
338                                                            row, column);
339       setIcon(MainFrame.getIcon(iconName));
340       return this;
341     }// public Component getTableCellRendererComponent
342 
343     //combobox used for OR parameters
344     JComboBox combo;
345     String iconName;
346     String text;
347   }//class ParameterDisjunctionRenderer
348 
349 
350   /**
351    * A renderer that displays a File Open button next to a text field.
352    * Used for setting URLs from files.
353    */
354   class ParameterValueRenderer extends ObjectRenderer {
355     ParameterValueRenderer() {
356       fileButton = new JButton(MainFrame.getIcon("loadFile.gif"));
357       fileButton.setToolTipText("Set from file...");
358       listButton = new JButton(MainFrame.getIcon("editList.gif"));
359       listButton.setToolTipText("Edit the list");
360       textButtonBox = new JPanel();
361       textButtonBox.setLayout(new BoxLayout(textButtonBox, BoxLayout.X_AXIS));
362       textButtonBox.setOpaque(false);
363 
364       combo = new JComboBox();
365       combo.setRenderer(new ResourceRenderer());
366     }// CustomObjectRenderer()
367 
368     public Component getTableCellRendererComponent(JTable table,
369                                                    Object value,
370                                                    boolean isSelected,
371                                                    boolean hasFocus,
372                                                    int row,
373                                                    int column) {
374 
375       String type = ((ParameterDisjunction)table.getValueAt(row, 0)).getType();
376 
377       if(Gate.isGateType(type)){
378         //Gate type
379         combo.setModel(new DefaultComboBoxModel(new Object[]{value == null ?
380                                                              "<none>" :
381                                                              value }));
382 
383         return combo;
384       }else{
385         Class typeClass = null;
386         try{
387           typeClass = Class.forName(type);
388         }catch(ClassNotFoundException cnfe){
389         }
390         //non Gate type -> we'll use the text field
391         String text = (value == null) ?
392                       "                                        " +
393                       "                                        " :
394                       value.toString();
395         //prepare the renderer
396         super.getTableCellRendererComponent(table, text, isSelected,
397                                               hasFocus, row, column);
398 
399         if(type.equals("java.net.URL")){
400           textButtonBox.removeAll();
401           textButtonBox.add(this);
402           this.setMaximumSize(new Dimension(Integer.MAX_VALUE,
403                                             getPreferredSize().height));
404           textButtonBox.add(Box.createHorizontalStrut(5));
405           textButtonBox.add(fileButton);
406           return textButtonBox;
407         }else if(typeClass != null &&
408                  List.class.isAssignableFrom(typeClass)){
409           //List value
410           setText(textForList((List)value));
411           textButtonBox.removeAll();
412           textButtonBox.add(this);
413           this.setMaximumSize(new Dimension(Integer.MAX_VALUE,
414                                             getPreferredSize().height));
415           textButtonBox.add(Box.createHorizontalStrut(5));
416           textButtonBox.add(listButton);
417           return textButtonBox;
418         }else return this;
419       }
420     }// public Component getTableCellRendererComponent
421 
422     /**
423      * Gets a string representation for a list value
424      */
425     protected String textForList(List list){
426       if(list == null) return "[]";
427       StringBuffer res = new StringBuffer("[");
428       Iterator elemIter = list.iterator();
429       while(elemIter.hasNext()){
430         Object elem = elemIter.next();
431         res.append( ((elem instanceof NameBearer) ?
432                     ((NameBearer)elem).getName() :
433                     elem.toString()) + ", ");
434       }
435       res.delete(res.length() - 2, res.length() - 1);
436       res.append("]");
437       return res.toString();
438     }
439 
440     JButton fileButton;
441     JButton listButton;
442     JComboBox combo;
443     JPanel textButtonBox;
444   }//class ObjectRenderer extends DefaultTableCellRenderer
445 
446   class ParameterDisjunctionEditor extends DefaultCellEditor{
447     public ParameterDisjunctionEditor(){
448       super(new JComboBox());
449       combo = (JComboBox)super.getComponent();
450       class CustomRenderer extends JLabel implements ListCellRenderer {
451         public CustomRenderer(){
452           setOpaque(true);
453         }
454         public Component getListCellRendererComponent(JList list,
455                                                       Object value,
456                                                       int index,
457                                                       boolean isSelected,
458                                                       boolean cellHasFocus){
459           if (isSelected) {
460               setBackground(list.getSelectionBackground());
461               setForeground(list.getSelectionForeground());
462           }
463           else {
464               setBackground(list.getBackground());
465               setForeground(list.getForeground());
466           }
467 
468           setFont(list.getFont());
469 
470           setText((String)value);
471 
472           String iconName = "param.gif";
473           Parameter[] params = pDisj.getParameters();
474           for(int i = 0; i < params.length; i++){
475             Parameter param = (Parameter)params[i];
476             if(param.getName().equals(value)){
477               String type = param.getTypeName();
478               if(Gate.getCreoleRegister().containsKey(type)){
479                 ResourceData rData = (ResourceData)
480                                      Gate.getCreoleRegister().get(type);
481                 if(rData != null) iconName = rData.getIcon();
482               }
483               break;
484             }//if(params[i].getName().equals(value))
485           }//for(int i = 0; params.length; i++)
486 
487           setIcon(MainFrame.getIcon(iconName));
488           return this;
489         }
490       };//class CustomRenderer extends JLabel implements ListCellRenderer
491       combo.setRenderer(new CustomRenderer());
492       combo.addActionListener(new ActionListener() {
493         public void actionPerformed(ActionEvent e) {
494           stopCellEditing();
495         }
496       });
497     }// public ParameterDisjunctionEditor()
498 
499     public Component getTableCellEditorComponent(JTable table,
500                                              Object value,
501                                              boolean isSelected,
502                                              int row,
503                                              int column){
504      pDisj = (ParameterDisjunction)value;
505      combo.setModel(new DefaultComboBoxModel(pDisj.getNames()));
506      return combo;
507     }// public Component getTableCellEditorComponent
508 
509     public Object getCellEditorValue(){
510       return new Integer(combo.getSelectedIndex());
511     }
512 
513     public boolean stopCellEditing(){
514       combo.hidePopup();
515       return super.stopCellEditing();
516     }
517 
518     JComboBox combo;
519     ParameterDisjunction pDisj;
520   }// class ParameterDisjunctionEditor extends DefaultCellEditor
521 
522   class ParameterValueEditor extends AbstractCellEditor
523                              implements TableCellEditor{
524     ParameterValueEditor(){
525       combo = new JComboBox();
526       combo.setRenderer(new ResourceRenderer());
527       combo.setEditable(false);
528 
529       textField = new JTextField();
530 
531       fileChooser = MainFrame.getFileChooser();
532       fileButton = new JButton(MainFrame.getIcon("loadFile.gif"));
533       fileButton.setToolTipText("Set from file...");
534       fileButton.addActionListener(new ActionListener() {
535         public void actionPerformed(ActionEvent e) {
536           fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
537           fileChooser.setDialogTitle("Select a file");
538           int res = fileChooser.showOpenDialog(ResourceParametersEditor.this);
539           if(res == fileChooser.APPROVE_OPTION){
540             try {
541               textField.setText(fileChooser.getSelectedFile().
542                                 toURL().toExternalForm());
543             } catch(IOException ioe){}
544             fireEditingStopped();
545           }else{
546             fireEditingCanceled();
547           }
548         }
549       });
550 
551       listButton = new JButton(MainFrame.getIcon("editList.gif"));
552       listButton.setToolTipText("Edit the list");
553       listButton.addActionListener(new ActionListener() {
554         public void actionPerformed(ActionEvent e) {
555           List returnedList = listEditor.showDialog();
556           if(returnedList != null){
557             listValue = returnedList;
558             fireEditingStopped();
559           }else{
560             fireEditingCanceled();
561           }
562         }
563       });
564 
565       textButtonBox = new JPanel();
566       textButtonBox.setLayout(new BoxLayout(textButtonBox, BoxLayout.X_AXIS));
567       textButtonBox.setOpaque(false);
568       label = new JLabel(){
569         public boolean isFocusTraversable(){
570           return true;
571         }
572       };
573       label.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
574       label.addMouseListener(new MouseAdapter() {
575         public void mouseClicked(MouseEvent e) {
576           Boolean value = new Boolean(label.getText());
577           value = new Boolean(!value.booleanValue());
578           label.setText(value.toString());
579         }
580       });
581       label.addKeyListener(new KeyAdapter() {
582         public void keyTyped(KeyEvent e) {
583           Boolean value = new Boolean(label.getText());
584           value = new Boolean(!value.booleanValue());
585           label.setText(value.toString());
586         }
587       });
588     }//ParameterValueEditor()
589 
590     public Component getTableCellEditorComponent(JTable table,
591                                                  Object value,
592                                                  boolean isSelected,
593                                                  int row,
594                                                  int column){
595       comboUsed = false;
596       listUsed = false;
597       ParameterDisjunction pDisj = (ParameterDisjunction)
598                                    table.getValueAt(row, 0);
599       type = pDisj.getType();
600 //      ResourceData rData = (ResourceData)Gate.getCreoleRegister().get(type);
601 
602       if(Gate.isGateType(type)){
603         //Gate type
604         comboUsed = true;
605         ArrayList values = new ArrayList();
606         try{
607           values.addAll(Gate.getCreoleRegister().
608                         getAllInstances(type));
609         }catch(GateException ge){
610           ge.printStackTrace(Err.getPrintWriter());
611         }
612         values.add(0, "<none>");
613         combo.setModel(new DefaultComboBoxModel(values.toArray()));
614         combo.setSelectedItem(value == null ? "<none>" : value);
615         return combo;
616       }else{
617         //non Gate type
618         Class typeClass = null;
619         try{
620           typeClass = Class.forName(type);
621         }catch(ClassNotFoundException cnfe){
622         }
623 
624         textField.setText((value == null) ? "" : value.toString());
625         if(type.equals("java.net.URL")){
626           //clean up all filters
627           fileChooser.resetChoosableFileFilters();
628           fileChooser.setAcceptAllFileFilterUsed(true);
629           fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter());
630           Parameter param = pDisj.getParameter();
631           Set sufixes = param.getSuffixes();
632           if(sufixes != null){
633             ExtensionFileFilter fileFilter = new ExtensionFileFilter();
634             Iterator sufIter = sufixes.iterator();
635             while(sufIter.hasNext()){
636               fileFilter.addExtension((String)sufIter.next());
637             }
638             fileFilter.setDescription("Known file types " + sufixes.toString());
639             fileChooser.addChoosableFileFilter(fileFilter);
640             fileChooser.setFileFilter(fileFilter);
641           }
642 
643           textField.setEditable(true);
644           textButtonBox.removeAll();
645           textButtonBox.add(textField);
646           textButtonBox.add(Box.createHorizontalStrut(5));
647           textButtonBox.add(fileButton);
648           return textButtonBox;
649         }else if(type.equals("java.lang.Boolean")){
650           label.setText(value.toString());
651           return label;
652         }else if(typeClass != null &&
653                       List.class.isAssignableFrom(typeClass)){
654           //List value
655           listUsed = true;
656           Parameter param = pDisj.getParameter();
657           Set sufixes = param.getSuffixes();
658 
659           listValue = (List)value;
660           listEditor = new ListEditorDialog(ResourceParametersEditor.this,
661                                             (List)value,
662                                             param.getItemClassName());
663 
664           textField.setEditable(false);
665           textField.setText(textForList((List)value));
666           textButtonBox.removeAll();
667           textButtonBox.add(textField);
668           textButtonBox.add(Box.createHorizontalStrut(5));
669           textButtonBox.add(listButton);
670           return textButtonBox;
671         }else{
672           textField.setEditable(true);
673           return textField;
674         }
675       }
676     }//getTableCellEditorComponent
677 
678     /**
679      * Gets a string representation for a list value
680      */
681     protected String textForList(List list){
682       if(list == null) return "[]";
683       StringBuffer res = new StringBuffer("[");
684       Iterator elemIter = list.iterator();
685       while(elemIter.hasNext()){
686         Object elem = elemIter.next();
687         res.append( ((elem instanceof NameBearer) ?
688                     ((NameBearer)elem).getName() :
689                     elem.toString()) + ", ");
690       }
691       res.delete(res.length() - 2, res.length() - 1);
692       res.append("]");
693       return res.toString();
694     }
695 
696     public Object getCellEditorValue(){
697       if(comboUsed){
698         Object value = combo.getSelectedItem();
699          return value == "<none>" ? null : value;
700       }
701       else if(listUsed){
702         return listValue;
703       }else{
704         if(type.equals("java.lang.Boolean")){
705           //get the value from the label
706           return new Boolean(label.getText());
707         }else{
708           //get the value from the text field
709           return ((textField.getText().equals("")) ? null :
710                                                      textField.getText());
711         }
712       }
713     }//public Object getCellEditorValue()
714 
715     /**
716      * The type of the value currently being edited
717      */
718     String type;
719 
720     /**
721      * Combobox use as editor for Gate objects (chooses between instances)
722      */
723     JComboBox combo;
724 
725     /**
726      * Editor used for boolean values
727      */
728     JLabel label;
729 
730     /**
731      * Generic editor for all types that are not treated special
732      */
733     JTextField textField;
734 
735     /**
736      * A pointer to the filechooser from MainFrame;
737      */
738     JFileChooser fileChooser;
739 
740     ListEditorDialog listEditor = null;
741     List listValue;
742 
743     boolean comboUsed;
744     boolean listUsed;
745     JButton fileButton;
746     JButton listButton;
747     JPanel textButtonBox;
748   }//class ParameterValueEditor
749 
750 
751 
752 }//class NewResourceDialog