Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/progeeks/meta/swing/editor/ListEditor.java


1   /*
2    * $Id: ListEditor.java,v 1.10 2003/09/24 07:16:01 pspeed Exp $
3    *
4    * Copyright (c) 2001-2002, Paul Speed
5    * All rights reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * 1) Redistributions of source code must retain the above copyright notice,
12   *    this list of conditions and the following disclaimer.
13   * 2) Redistributions in binary form must reproduce the above copyright
14   *    notice, this list of conditions and the following disclaimer in the
15   *    documentation and/or other materials provided with the distribution.
16   * 3) Neither the names "Progeeks", "Meta-JB", nor the names of its contributors
17   *    may be used to endorse or promote products derived from this software
18   *    without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   */
32  
33  package org.progeeks.meta.swing.editor;
34  
35  import java.awt.*;
36  import java.awt.event.*;
37  import java.beans.*;
38  import javax.swing.*;
39  import javax.swing.border.*;
40  import javax.swing.event.*;
41  
42  import org.progeeks.meta.*;
43  import org.progeeks.meta.format.*;
44  import org.progeeks.meta.swing.*;
45  import org.progeeks.util.beans.*;
46  
47  /**
48   *  An editor implementation for a List of values otherwise editable
49   *  with another registered editor.
50   *
51   *  @version   $Revision: 1.10 $
52   *  @author    Paul Speed
53   */
54  public class ListEditor extends AbstractPropertyEditor
55                          implements MetaPropertyRenderer
56  {
57      private FactoryRegistry  factories;
58  
59      private EditorDialog     popup;
60      private JPanel           component;
61      private JList            list;
62      private JScrollPane      scrollPane;
63      private JButton          add;
64      private JButton          edit;
65      private JButton          remove;
66      private ListMutator      listMutator;
67      private ListModelAdapter model;
68      private PropertyType     elementType;
69      private PropertyFormat   elementFormat;
70      private EditorListener   editListener = new EditorListener();
71      private boolean          readOnly = false;
72  
73      public ListEditor( FactoryRegistry factories )
74      {
75          this( factories, false );
76      }
77  
78      public ListEditor( FactoryRegistry factories, boolean readOnly )
79      {
80          this.factories = factories;
81          this.readOnly = readOnly;
82  
83          model = new ListModelAdapter();
84          list = new JList( model ); //new String[] { "test 1", "test 2" } );
85          list.setCellRenderer( new ItemRenderer() );
86          scrollPane = new JScrollPane( list );
87          list.setVisibleRowCount( 5 );
88          list.addListSelectionListener( editListener );
89  
90          add = new JButton( "Add" );
91          add.addActionListener( editListener );
92          edit = new JButton( "Edit" );
93          edit.addActionListener( editListener );
94          remove = new JButton( "Remove" );
95          remove.addActionListener( editListener );
96  
97          component = new JPanel( new GridBagLayout() );
98          GridBagConstraints gbc = new GridBagConstraints();
99          gbc.gridx = 0;
100         gbc.gridy = 0;
101         gbc.weightx = 1.0;
102         gbc.weighty = 1.0;
103         gbc.gridwidth = 3;
104         gbc.fill = GridBagConstraints.BOTH;
105 
106         component.add( scrollPane, gbc );
107 
108         gbc.gridy = 1;
109         gbc.weightx = 1.0;
110         gbc.weighty = 0;
111         gbc.gridwidth = 1;
112         component.add( add, gbc );
113 
114         gbc.gridx++;
115         component.add( edit, gbc );
116 
117         gbc.gridx++;
118         component.add( remove, gbc );
119     }
120 
121     /**
122      *  Returns true if the dialog should have an edit button
123      *  if the property mutator supports it.  This allows subclasses
124      *  to specifically override.
125      */
126     public boolean hasEditButton()
127     {
128         return( true );
129     }
130 
131     /**
132      *  Returns true if the dialog should have a remove button
133      *  if the property mutator supports it.  This allows subclasses
134      *  to specifically override.
135      */
136     public boolean hasRemoveButton()
137     {
138         return( true );
139     }
140 
141     /**
142      *  Returns true if the dialog should have an add button
143      *  if the property mutator supports it.  This allows subclasses
144      *  to specifically override.
145      */
146     public boolean hasAddButton()
147     {
148         return( true );
149     }
150 
151     /**
152      *  Intercepted to configure the list panel to most appropriately
153      *  modify the list.
154      */
155     public void setPropertyMutator( PropertyMutator mutator )
156     {
157         super.setPropertyMutator( mutator );
158 
159         listMutator = (ListMutator)mutator;
160         ContainerPropertyInfo info = (ContainerPropertyInfo)listMutator.getPropertyInfo();
161         ListPropertyType type = (ListPropertyType)info.getPropertyType();
162         elementType = type.getValueType();
163         elementFormat = factories.getFormatRegistry().getFormat( elementType );
164 
165         if( readOnly )
166             {
167             edit.setVisible( false );
168             add.setVisible( false );
169             remove.setVisible( false );
170             }
171         else
172             {
173             edit.setVisible( info.isMutable() && hasEditButton() );
174             add.setVisible( info.isResizable() && hasAddButton() );
175             remove.setVisible( info.isResizable() && hasRemoveButton() );
176             }
177 
178         edit.setEnabled( false );
179         remove.setEnabled( false );
180 
181         model.setListMutator( listMutator );
182     }
183 
184     /**
185      *  Returns false since lists should be full-width controls.
186      */
187     public boolean isSingleColumn()
188     {
189         return( false );
190     }
191 
192     /**
193      *  Returns the component that allows modification of the
194      *  associated property mutator.
195      */
196     public Component getUIComponent()
197     {
198         return( component );
199     }
200 
201     /**
202      *  Implemented by subclasses to release any component-related
203      *  resources.
204      */
205     protected void releaseComponent()
206     {
207         list.removeListSelectionListener( editListener );
208         add.removeActionListener( editListener );
209         edit.removeActionListener( editListener );
210         remove.removeActionListener( editListener );
211     }
212 
213     /**
214      *  Called to set the current value displayed in the component.
215      */
216     protected void setComponentValue( Object value )
217     {
218         // Only called for a full list change.
219 
220         // FIXME  implement this or verify that it's not needed
221     }
222 
223     /**
224      *  Called to set the component value to a default state.
225      *  The default implementation calls setComponentValue(null).
226      */
227     protected void resetComponentValue()
228     {
229         // FIXME  Implement this
230     }
231 
232     /**
233      *  Called when the value contained in the mutator changes.
234      *  The default implementation ignores property changes if
235      *  the value is the same as the current cached value either
236      *  by reference or by .equals().
237      */
238     protected void propertyChanged( PropertyChangeEvent event )
239     {
240         if( !(event instanceof ListPropertyChangeEvent) )
241             {
242             // Cause a full list update
243             model.setListMutator( listMutator );
244             return;
245             }
246 
247         ListPropertyChangeEvent listEvent = (ListPropertyChangeEvent)event;
248         switch( listEvent.getType() )
249             {
250             case ListPropertyChangeEvent.INSERT:
251                 model.intervalAdded( listEvent.getFirstIndex(), listEvent.getLastIndex() );
252                 break;
253             case ListPropertyChangeEvent.UPDATE:
254                 model.intervalChanged( listEvent.getFirstIndex(), listEvent.getLastIndex() );
255                 break;
256             case ListPropertyChangeEvent.DELETE:
257                 model.intervalRemoved( listEvent.getFirstIndex(), listEvent.getLastIndex() );
258                 break;
259             }
260     }
261 
262     protected void addItem()
263     {
264         if( popup == null )
265             popup = new EditorDialog();
266         popup.setLocationRelativeTo( component );
267 
268         Object newValue = null;
269         if( elementType instanceof MetaClassPropertyType )
270             {
271             MetaClass metaClass = ((MetaClassPropertyType)elementType).getMetaClass();
272             MetaObjectFactory factory = listMutator.getParentObject().getMetaKit().getMetaObjectFactory();
273             newValue = factory.createMetaObject( metaClass );
274             }
275         else
276             {
277             // We hope that the editor knows what to
278             // do with null values.
279             }
280         // Create a new value by popping up an editor with
281         // a fake PropertyMutator containing the appropriate
282         // type info.
283         popup.popupEdit( "Add List Value", "New Value", newValue, elementType, factories );
284 
285         if( !popup.isCanceled()
286             && (popup.hasChanged() || newValue != null) ) // A hack until EditorDialog detects changes
287                                                           // to meta-objects.
288             {
289             Object value = popup.getValue();
290             if( value != null )
291                 listMutator.add( value );
292 
293             // FIXME: This is a hack because normal beans don't know
294             //        when their values have changed.  I need to think
295             //        about this some more because it's a fairly serious
296             //        issue.  It may be that they only get an opportunity
297             //        to receive notifications if they implement add/remove/set
298             //        methods.
299             listMutator.setValue( listMutator.getValue() );
300             }
301     }
302 
303     protected void editItem( int i )
304     {
305         if( popup == null )
306             popup = new EditorDialog();
307         popup.setLocationRelativeTo( component );
308 
309         popup.popupEdit( "Edit List Value", "Value", listMutator.get(i), elementType, factories );
310 
311         if( popup.hasChanged() )
312             {
313             Object value = popup.getValue();
314             listMutator.set( i, value );
315 
316             // FIXME: This is a hack because normal beans don't know
317             //        when their values have changed.  I need to think
318             //        about this some more because it's a fairly serious
319             //        issue.  It may be that they only get an opportunity
320             //        to receive notifications if they implement add/remove/set
321             //        methods.
322             listMutator.setValue( listMutator.getValue() );
323             }
324     }
325 
326     protected void removeItem( int i )
327     {
328         listMutator.remove( i );
329 
330         // FIXME: This is a hack because normal beans don't know
331         //        when their values have changed.  I need to think
332         //        about this some more because it's a fairly serious
333         //        issue.  It may be that they only get an opportunity
334         //        to receive notifications if they implement add/remove/set
335         //        methods.
336         listMutator.setValue( listMutator.getValue() );
337     }
338 
339     private class ItemRenderer extends DefaultListCellRenderer
340     {
341         public Component getListCellRendererComponent( JList list,
342                                                        Object value,
343                                                        int index,
344                                                        boolean isSelected,
345                                                        boolean cellHasFocus )
346         {
347             // Format the value as needed
348             value = elementFormat.format( value );
349             return( super.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus ) );
350         }
351     }
352 
353     private class EditorListener implements ActionListener, ListSelectionListener
354     {
355         public void valueChanged( ListSelectionEvent event )
356         {
357             edit.setEnabled( true );
358             remove.setEnabled( true );
359         }
360 
361         public void actionPerformed( ActionEvent event )
362         {
363             if( event.getSource() == add )
364                 {
365                 addItem();
366                 }
367             else if( event.getSource() == edit )
368                 {
369                 int i = list.getLeadSelectionIndex();
370                 if( i < 0 )
371                     i = listMutator.size();
372 
373                 editItem( i );
374                 }
375             else if( event.getSource() == remove )
376                 {
377                 removeItem( list.getLeadSelectionIndex() );
378                 }
379         }
380     }
381 
382 }
383 
384