Source code: org/progeeks/meta/swing/MetaPanel.java
1 /*
2 * $Id: MetaPanel.java,v 1.2 2003/08/27 03:47:09 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;
34
35 import java.awt.*;
36 import java.util.*;
37 import javax.swing.*;
38
39 import org.progeeks.meta.*;
40 import org.progeeks.meta.format.*;
41 import org.progeeks.util.log.*;
42
43 /**
44 * A JPanel implementation that provides additional container
45 * methods for adding MetaObjects and PropertyMutators as if they
46 * were actual UI components.
47 *
48 * @version $Revision: 1.2 $
49 * @author Paul Speed
50 */
51 public class MetaPanel extends JPanel
52 {
53 static Log log = Log.getLog( MetaPanel.class );
54
55 private FactoryRegistry factories;
56 private boolean editable;
57
58 private ArrayList mutators = new ArrayList();
59 private ArrayList uis = new ArrayList();
60
61 /**
62 * Creates aa MetaPanel with a default factory registry and layout manager.
63 */
64 public MetaPanel()
65 {
66 this( new FactoryRegistry(), new BorderLayout(), true );
67 }
68
69 /**
70 * Creates an empty MetaColumnPanel with a default layout manager.
71 */
72 public MetaPanel( FactoryRegistry factories )
73 {
74 this( factories, new BorderLayout(), true );
75 }
76
77 /**
78 * Creates a meta-panel with the specified factory and layout manager.
79 */
80 public MetaPanel( FactoryRegistry factories, LayoutManager layout )
81 {
82 this( factories, layout, true );
83 }
84
85 /**
86 * Creates a meta-panel with the specified factory and layout manager.
87 */
88 public MetaPanel( FactoryRegistry factories, LayoutManager layout, boolean editable )
89 {
90 super( layout );
91 this.factories = factories;
92 this.editable = editable;
93 }
94
95 /**
96 * Creates a meta-property UI for the specified mutator
97 * and added the UI to the appropriate data structures.
98 */
99 protected MetaPropertyUI createUI( PropertyMutator mutator, int index )
100 {
101 PropertyInfo info = mutator.getPropertyInfo();
102 MetaPropertyUI ui = null;
103 if( info.isWritable() && editable )
104 {
105 ui = factories.createPropertyEditor( info.getPropertyType() );
106 }
107 else
108 {
109 ui = factories.createPropertyRenderer( info.getPropertyType() );
110 }
111 ui.setPropertyMutator( mutator );
112 if( index >= 0 )
113 {
114 mutators.add( index, mutator );
115 uis.add( index, ui );
116 }
117 else
118 {
119 mutators.add( mutator );
120 uis.add( ui );
121 }
122
123 return( ui );
124 }
125
126 /**
127 * Inserts an empty space into the data structures that
128 * map mutators to components. This helps keep the mutator
129 * list in synch with the container's component list.
130 */
131 protected void addBlank( int index )
132 {
133 if( index >= 0 )
134 {
135 mutators.add( index, null );
136 uis.add( index, null );
137 }
138 else
139 {
140 mutators.add( null );
141 uis.add( null );
142 }
143 }
144
145 /**
146 * Releases a meta-property UI and removes it from the
147 * appropriate data structures.
148 */
149 protected void removeSlot( int index )
150 {
151 mutators.remove( index );
152 uis.remove( index );
153 }
154
155 /**
156 * Returns the index of the specified component.
157 */
158 protected int getComponentIndex( Component comp )
159 {
160 int count = getComponentCount();
161 for( int i = 0; i < count; i++ )
162 {
163 if( comp.equals( getComponent(i) ) )
164 return( i );
165 }
166 return( -1 );
167 }
168
169 /**
170 * Adds the specified PropertyMutator to this container by
171 * creating a component as appropriate for its type.
172 *
173 * @param the mutator for which a component will be created.
174 */
175 public MetaPropertyUI add( PropertyMutator mutator )
176 {
177 return( add( mutator, null, -1 ) );
178 }
179
180 /**
181 * Adds the specified PropertyMutator to this container by
182 * creating a component as appropriate for its type.
183 *
184 * @param the mutator for which a component will be created.
185 * @param an object expressing layout contraints for the mutator's UI component
186 * @param the position at which to insert the mutator, or -1 to
187 * append the mutator to the end
188 */
189 public MetaPropertyUI add( PropertyMutator mutator, int index )
190 {
191 return( add( mutator, null, index ) );
192 }
193
194 /**
195 * Adds the specified PropertyMutator to this container by
196 * creating a component as appropriate for its type. The
197 * constraints are passed when the component is added and
198 * are specific to the type of layout manager being used.
199 *
200 * @param The mutator for which a component will be created.
201 * @param an object expressing layout contraints for the mutator's UI component
202 */
203 public MetaPropertyUI add( PropertyMutator mutator, Object constraints )
204 {
205 return( add( mutator, constraints, -1 ) );
206 }
207
208 /**
209 * Adds the specified PropertyMutator to this container by
210 * creating a component as appropriate for its type. The
211 * constraints are passed when the component is added and
212 * are specific to the type of layout manager being used.
213 *
214 * @param The mutator for which a component will be created.
215 * @param the position at which to insert the mutator, or -1 to
216 * append the mutator to the end
217 */
218 public MetaPropertyUI add( PropertyMutator mutator, Object constraints, int index )
219 {
220 MetaPropertyUI ui = createUI( mutator, index );
221 super.add( ui.getUIComponent(), constraints, index );
222 return( ui );
223 }
224
225 public void add( Component comp, Object constraints, int index )
226 {
227 // Overridden so that we can keep track of the empty spaces
228 super.add( comp, constraints, index );
229 addBlank( index );
230 }
231
232 /**
233 * Returns the mutator at the specified index or null if no
234 * mutator exists at the specified position, ie: it's a component
235 * that was added manually.
236 */
237 public PropertyMutator getMutator( int index )
238 {
239 return( (PropertyMutator)mutators.get( index ) );
240 }
241
242 /**
243 * Could have a method that would replace a meta-object. It
244 * could do this by finding all mutators associated with a
245 * specified object and replacing them with like mutators from
246 * a new object. Useful?
247 */
248
249 /**
250 * Returns the meta-property UI for the specified index or null
251 * if no meta-property UI exists at the specified position.
252 */
253 public MetaPropertyUI getMetaPropertyUI( int index )
254 {
255 return( (MetaPropertyUI)uis.get( index ) );
256 }
257
258 /**
259 * Removes the first component associated with the specified mutator.
260 */
261 public void remove( PropertyMutator mutator )
262 {
263 // The mutator may exist more than once in the panel.
264 // We need to find the right one. We grab the first.
265 int index = mutators.indexOf( mutator );
266 if( index < 0 )
267 throw new RuntimeException( "Mutator not found." ); // probably a bit harsh
268 remove( index );
269 }
270
271 /**
272 * Removes the component and mutator at the specified index.
273 */
274 public void remove( int index )
275 {
276 super.remove( index );
277
278 MetaPropertyUI ui = (MetaPropertyUI)uis.get( index );
279
280 // Remove the UI component associated with the mutator.
281 super.remove( ui.getUIComponent() );
282
283 removeSlot( index );
284
285 // Release any listeners associatd with the UI
286 ui.release();
287 }
288
289 /**
290 * Removes all components and mutators from this container.
291 */
292 public void removeAll()
293 {
294 super.removeAll();
295
296 // Release all of the UIs
297 for( Iterator i = uis.iterator(); i.hasNext(); )
298 {
299 Object obj = i.next();
300 if( obj instanceof MetaPropertyUI )
301 {
302 ((MetaPropertyUI)obj).release();
303 }
304 }
305
306 // Clear the lists
307 mutators.clear();
308 uis.clear();
309 }
310 }
311