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 16/10/2001
10   *
11   *  $Id: ListEditorDialog.java,v 1.4 2001/11/12 18:06:08 valyt Exp $
12   *
13   */
14  
15  package gate.gui;
16  
17  import java.awt.Component;
18  import java.awt.event.*;
19  import javax.swing.*;
20  
21  import java.util.*;
22  
23  
24  import gate.*;
25  import gate.util.*;
26  import gate.creole.*;
27  
28  /**
29   * A simple editor for List values.
30   */
31  public class ListEditorDialog extends JDialog {
32  
33    /**
34     * Contructs a new ListEditorDialog.
35     * @param owner the component this dialog will be centred on.
36     * @param data a list with the initial values. This list will not be changed,
37     * its values will be cached and if the user selects the OK option a new list
38     * with the updated contents will be returned.
39     * @param itemType the type of the elements in the list in the form of a
40     * fully qualified class name
41     */
42    public ListEditorDialog(Component owner, List data, String itemType) {
43      this.itemType = itemType == null ? "java.lang.String" : itemType;
44      setLocationRelativeTo(owner);
45      initLocalData(data);
46      initGuiComponents();
47      initListeners();
48    }
49  
50    protected void initLocalData(List data){
51      listModel = new DefaultListModel();
52      if(data != null){
53        Iterator elemIter = data.iterator();
54        while(elemIter.hasNext()){
55          listModel.addElement(elemIter.next());
56        }
57      }
58  
59      try{
60        ResourceData rData = (ResourceData)Gate.getCreoleRegister().get(itemType);
61        itemTypeClass = rData == null ? Class.forName(itemType) :
62                        rData.getResourceClass();
63      }catch(ClassNotFoundException cnfe){
64        throw new GateRuntimeException(cnfe.toString());
65      }
66  
67      finiteType = Gate.isGateType(itemType);
68  
69      ResourceData rData = (ResourceData)Gate.getCreoleRegister().get(itemType);
70      setTitle("List of " + ((rData== null) ? itemType :rData.getName()));
71  
72      addAction = new AddAction();
73      removeAction = new RemoveAction();
74    }
75  
76    protected void initGuiComponents(){
77      getContentPane().setLayout(new BoxLayout(getContentPane(),
78                                               BoxLayout.Y_AXIS));
79  
80      //the editor component
81      JComponent editComp = null;
82      if(finiteType){
83        editComp = combo = new JComboBox(new ResourceComboModel());
84        combo.setRenderer(new ResourceRenderer());
85        if(combo.getModel().getSize() > 0){
86          combo.getModel().setSelectedItem(combo.getModel().getElementAt(0));
87        }
88      }else{
89        editComp = textField = new JTextField(20);
90      }
91  
92      getContentPane().add(editComp);
93      getContentPane().add(Box.createVerticalStrut(5));
94  
95      //the buttons box
96      Box buttonsBox = Box.createHorizontalBox();
97      addBtn = new JButton(addAction);
98      removeBtn = new JButton(removeAction);
99      buttonsBox.add(Box.createHorizontalGlue());
100     buttonsBox.add(addBtn);
101     buttonsBox.add(Box.createHorizontalStrut(5));
102     buttonsBox.add(removeBtn);
103     buttonsBox.add(Box.createHorizontalGlue());
104     getContentPane().add(buttonsBox);
105     getContentPane().add(Box.createVerticalStrut(5));
106 
107     //the list component
108     Box horBox = Box.createHorizontalBox();
109     listComponent = new JList(listModel);
110     listComponent.setSelectionMode(ListSelectionModel.
111                                    MULTIPLE_INTERVAL_SELECTION);
112     listComponent.setCellRenderer(new ResourceRenderer());
113     horBox.add(new JScrollPane(listComponent));
114     //up down buttons
115     Box verBox = Box.createVerticalBox();
116     verBox.add(Box.createVerticalGlue());
117     moveUpBtn = new JButton(MainFrame.getIcon("moveup.gif"));
118     verBox.add(moveUpBtn);
119     verBox.add(Box.createVerticalStrut(5));
120     moveDownBtn = new JButton(MainFrame.getIcon("movedown.gif"));
121     verBox.add(moveDownBtn);
122     verBox.add(Box.createVerticalGlue());
123     horBox.add(Box.createHorizontalStrut(3));
124     horBox.add(verBox);
125     horBox.add(Box.createHorizontalStrut(3));
126     getContentPane().add(horBox);
127     getContentPane().add(Box.createVerticalStrut(5));
128 
129     //the bottom buttons
130     buttonsBox = Box.createHorizontalBox();
131     buttonsBox.add(Box.createHorizontalGlue());
132     okButton = new JButton("OK");
133     buttonsBox.add(okButton);
134     buttonsBox.add(Box.createHorizontalStrut(5));
135     cancelButton = new JButton("Cancel");
136     buttonsBox.add(cancelButton);
137     buttonsBox.add(Box.createHorizontalGlue());
138     getContentPane().add(buttonsBox);
139   }
140 
141   protected void initListeners(){
142     okButton.addActionListener(new ActionListener() {
143       public void actionPerformed(ActionEvent e) {
144         userCancelled = false;
145         hide();
146       }
147     });
148 
149     cancelButton.addActionListener(new ActionListener() {
150       public void actionPerformed(ActionEvent e) {
151         userCancelled = true;
152         hide();
153       }
154     });
155 
156 
157     moveUpBtn.addActionListener(new ActionListener() {
158       public void actionPerformed(ActionEvent e) {
159         int rows[] = listComponent.getSelectedIndices();
160         if(rows == null || rows.length == 0){
161           JOptionPane.showMessageDialog(
162               ListEditorDialog.this,
163               "Please select some items to be moved ",
164               "Gate", JOptionPane.ERROR_MESSAGE);
165         }else{
166           //we need to make sure the rows are sorted
167           Arrays.sort(rows);
168           //get the list of items
169           for(int i = 0; i < rows.length; i++){
170             int row = rows[i];
171             if(row > 0){
172               //move it up
173               Object value = listModel.remove(row);
174               listModel.add(row - 1, value);
175             }
176           }
177           //restore selection
178           for(int i = 0; i < rows.length; i++){
179             int newRow = -1;
180             if(rows[i] > 0) newRow = rows[i] - 1;
181             else newRow = rows[i];
182             listComponent.addSelectionInterval(newRow, newRow);
183           }
184         }
185 
186       }//public void actionPerformed(ActionEvent e)
187     });
188 
189 
190     moveDownBtn.addActionListener(new ActionListener() {
191       public void actionPerformed(ActionEvent e) {
192         int rows[] = listComponent.getSelectedIndices();
193         if(rows == null || rows.length == 0){
194           JOptionPane.showMessageDialog(
195               ListEditorDialog.this,
196               "Please select some items to be moved ",
197               "Gate", JOptionPane.ERROR_MESSAGE);
198         } else {
199           //we need to make sure the rows are sorted
200           Arrays.sort(rows);
201           //get the list of items
202           for(int i = rows.length - 1; i >= 0; i--){
203             int row = rows[i];
204             if(row < listModel.size() -1){
205               //move it down
206               Object value = listModel.remove(row);
207               listModel.add(row + 1, value);
208             }
209           }
210           //restore selection
211           for(int i = 0; i < rows.length; i++){
212             int newRow = -1;
213             if(rows[i] < listModel.size() - 1) newRow = rows[i] + 1;
214             else newRow = rows[i];
215             listComponent.addSelectionInterval(newRow, newRow);
216           }
217         }
218 
219       }//public void actionPerformed(ActionEvent e)
220     });
221 
222   }
223 
224   /**
225    * Make this dialog visible allowing the editing of the list.
226    * If the user selects the <b>OK</b> option a new list with the updated
227    * contents will be returned; it the <b>Cancel</b> option is selected this
228    * method return <tt>null</tt>.
229    */
230   public List showDialog(){
231     pack();
232     userCancelled = true;
233     setModal(true);
234     super.show();
235     return userCancelled ? null : Arrays.asList(listModel.toArray());
236   }
237 
238   /**
239    * test code
240    */
241   public static void main(String[] args){
242     try{
243       Gate.init();
244     }catch(Exception e){
245       e.printStackTrace();
246     }
247     JFrame frame = new JFrame("Foo frame");
248 
249     ListEditorDialog dialog = new ListEditorDialog(frame,
250                                                    new ArrayList(),
251                                                    "java.lang.Integer");
252 
253     frame.setSize(300, 300);
254     frame.setVisible(true);
255     System.out.println(dialog.showDialog());
256   }
257 
258   /**
259    * Adds an element to the list from the editing component located at the top
260    * of this dialog.
261    */
262   protected class AddAction extends AbstractAction{
263     AddAction(){
264       super("Add");
265       putValue(SHORT_DESCRIPTION, "Add the edited value to the list");
266     }
267     public void actionPerformed(ActionEvent e){
268       if(finiteType){
269         listModel.addElement(combo.getSelectedItem());
270       }else{
271         Object value = null;
272         //convert the value to the proper type
273         String stringValue = textField.getText();
274         if(stringValue == null || stringValue.length() == 0) stringValue = null;
275 
276         if(itemTypeClass.isAssignableFrom(String.class)){
277           //no conversion necessary
278           value = stringValue;
279         }else{
280           //try conversion
281           try{
282             value = itemTypeClass.getConstructor(new Class[]{String.class}).
283                                   newInstance( new Object[]{stringValue} );
284           }catch(Exception ex){
285             JOptionPane.showMessageDialog(
286                 ListEditorDialog.this,
287                 "Invalid value!\nIs it the right type?",
288                 "Gate", JOptionPane.ERROR_MESSAGE);
289             return;
290           }
291         }
292         listModel.addElement(value);
293         textField.setText("");
294       }
295     }
296   }
297 
298   /**
299    * Removes the selected element(s) from the list
300    */
301   protected class RemoveAction extends AbstractAction{
302     RemoveAction(){
303       super("Remove");
304       putValue(SHORT_DESCRIPTION, "Remove the selected value(s) from the list");
305     }
306 
307     public void actionPerformed(ActionEvent e){
308       int[] indices = listComponent.getSelectedIndices();
309       Arrays.sort(indices);
310       for(int i = indices.length -1; i >= 0; i--){
311         listModel.remove(indices[i]);
312       }
313     }
314   }
315 
316 
317   /**
318    * A model for a combobox containing the loaded corpora in the system
319    */
320   protected class ResourceComboModel extends AbstractListModel
321                                   implements ComboBoxModel{
322 
323     public int getSize(){
324       //get all corpora regardless of their actual type
325       java.util.List loadedResources = null;
326       try{
327         loadedResources = Gate.getCreoleRegister().
328                                getAllInstances(itemType);
329       }catch(GateException ge){
330         ge.printStackTrace(Err.getPrintWriter());
331       }
332 
333       return loadedResources == null ? 0 : loadedResources.size();
334     }
335 
336     public Object getElementAt(int index){
337       //get all corpora regardless of their actual type
338       java.util.List loadedResources = null;
339       try{
340         loadedResources = Gate.getCreoleRegister().
341                                getAllInstances(itemType);
342       }catch(GateException ge){
343         ge.printStackTrace(Err.getPrintWriter());
344       }
345       return loadedResources == null? null : loadedResources.get(index);
346     }
347 
348     public void setSelectedItem(Object anItem){
349       if(anItem == null) selectedItem = null;
350       else selectedItem = anItem;
351     }
352 
353     public Object getSelectedItem(){
354       return selectedItem;
355     }
356 
357     void fireDataChanged(){
358       fireContentsChanged(this, 0, getSize());
359     }
360 
361     Object selectedItem = null;
362   }
363 
364   /**
365    * The type of the elements in the list
366    */
367   String itemType;
368 
369   /**
370    * The Class for the elements in the list
371    */
372   Class itemTypeClass;
373 
374   /**
375    * The GUI compoenent used to display the list
376    */
377   JList listComponent;
378 
379   /**
380    * Comobox used to select among values for GATE types
381    */
382   JComboBox combo;
383 
384   /**
385    * Text field used to input new arbitrary values
386    */
387   JTextField textField;
388 
389   /**
390    * Used to remove the selected element in the list;
391    */
392   JButton removeBtn;
393 
394   /**
395    * Used to add a new value to the list
396    */
397   JButton addBtn;
398 
399   /**
400    * Moves up one or more items in the list
401    */
402   JButton moveUpBtn;
403 
404   /**
405    * Moves down one or more items in the list
406    */
407   JButton moveDownBtn;
408 
409   /**
410    * The model used by the {@link listComponent}
411    */
412   DefaultListModel listModel;
413 
414   /**
415    * Does the item type have a finite range (i.e. should we use the combo)?
416    */
417   boolean finiteType;
418 
419   /**
420    * An action that adds the item being edited to the list
421    */
422   Action addAction;
423 
424   /**
425    * An action that removes the item(s) currently selected from the list
426    */
427   Action removeAction;
428 
429   /**
430    * The OK button for this dialog
431    */
432   JButton okButton;
433 
434   /**
435    * The cancel button for this dialog
436    */
437   JButton cancelButton;
438 
439   /**
440    * Did the user press the cancel button?
441    */
442   boolean userCancelled;
443 }