001: /*--
002:
003: Copyright (C) 2002-2005 Adrian Price.
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009:
010: 1. Redistributions of source code must retain the above copyright
011: notice, this list of conditions, and the following disclaimer.
012:
013: 2. Redistributions in binary form must reproduce the above copyright
014: notice, this list of conditions, and the disclaimer that follows
015: these conditions in the documentation and/or other materials
016: provided with the distribution.
017:
018: 3. The names "OBE" and "Open Business Engine" must not be used to
019: endorse or promote products derived from this software without prior
020: written permission. For written permission, please contact
021: adrianprice@sourceforge.net.
022:
023: 4. Products derived from this software may not be called "OBE" or
024: "Open Business Engine", nor may "OBE" or "Open Business Engine"
025: appear in their name, without prior written permission from
026: Adrian Price (adrianprice@users.sourceforge.net).
027:
028: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
029: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
030: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
031: DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
032: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
033: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
034: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
035: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
036: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
037: IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
038: POSSIBILITY OF SUCH DAMAGE.
039:
040: For more information on OBE, please see
041: <http://obe.sourceforge.net/>.
042:
043: */
044:
045: package org.obe.util;
046:
047: import javax.swing.*;
048: import java.beans.*;
049: import java.beans.beancontext.BeanContext;
050: import java.beans.beancontext.BeanContextChild;
051: import java.io.Serializable;
052: import java.lang.reflect.Array;
053: import java.util.HashMap;
054: import java.util.Map;
055:
056: /**
057: * An abstract bean class that supports events and array reallocation. The
058: * methods in this class are not thread-safe and require external
059: * synchronization if called in a multi-threaded context.
060: *
061: * @author Adrian Price
062: */
063: public abstract class AbstractBean implements BeanContextChild,
064: Serializable {
065: private static final long serialVersionUID = -1832793880243105246L;
066:
067: private BeanContext _beanContext;
068: private final IndexedPropertySupport[] _indexedPropertySupport;
069: private final Map _indexedPropertySupportByName;
070: private transient PropertyChangeSupport _pcs;
071: private transient VetoableChangeSupport _vcs;
072:
073: protected AbstractBean() {
074: _indexedPropertySupport = null;
075: _indexedPropertySupportByName = null;
076: }
077:
078: /**
079: * Constructor
080: *
081: * @param propertyNames
082: * @param initalValues
083: */
084: protected AbstractBean(String[] propertyNames, Object[] initalValues) {
085: // Set up support for each indexed property.
086: int arrayCount = propertyNames.length;
087: _indexedPropertySupport = new IndexedPropertySupport[arrayCount];
088: _indexedPropertySupportByName = new HashMap(arrayCount);
089: for (int i = 0; i < arrayCount; i++) {
090: String propertyName = propertyNames[i];
091: IndexedPropertySupport support = new IndexedPropertySupport(
092: propertyName, initalValues[i]);
093: _indexedPropertySupport[i] = support;
094: _indexedPropertySupportByName.put(propertyName, support);
095: }
096: }
097:
098: final class IndexedPropertySupport implements Serializable {
099: private static final long serialVersionUID = 44248828826928167L;
100: private final String _propertyName;
101: private Object _value;
102: private transient InternalListModel _model;
103:
104: private IndexedPropertySupport(String propertyName, Object value) {
105: _propertyName = propertyName;
106: _value = value;
107: }
108:
109: private final class InternalListModel extends AbstractListModel {
110: public Object getElementAt(int index) {
111: return Array.get(_value, index);
112: }
113:
114: public int getSize() {
115: return Array.getLength(_value);
116: }
117:
118: private void fireContentsChanged(int index0, int index1) {
119: fireContentsChanged(this , index0, index1);
120: }
121:
122: private void fireIntervalAdded(int index0, int index1) {
123: fireIntervalAdded(this , index0, index1);
124: }
125:
126: private void fireIntervalRemoved(int index0, int index1) {
127: fireIntervalRemoved(this , index0, index1);
128: }
129: }
130:
131: public ListModel getListModel() {
132: if (_model == null)
133: _model = new InternalListModel();
134: return _model;
135: }
136:
137: public Object get() {
138: // If it's design time, clone the array; otherwise, no need.
139: Object newArray;
140: if (_beanContext != null && _beanContext.isDesignTime()) {
141: if (_value == null) {
142: newArray = null;
143: } else {
144: int length = Array.getLength(_value);
145: newArray = Array.newInstance(_value.getClass()
146: .getComponentType(), length);
147: System.arraycopy(_value, 0, newArray, 0, length);
148: }
149: } else {
150: newArray = _value;
151: }
152: return newArray;
153: }
154:
155: public Object get(int i) {
156: return Array.get(_value, i);
157: }
158:
159: public void set(Object array) throws PropertyVetoException {
160: fireVetoableChange(_propertyName, _value, array);
161: _value = array;
162: firePropertyChange(_propertyName, _value, array);
163: if (_model != null)
164: _model.fireContentsChanged(0, Array.getLength(array));
165: }
166:
167: public void set(int i, Object newValue)
168: throws PropertyVetoException {
169: // Check with Vetoable change listeners.
170: PropertyChangeEvent evt = null;
171: if (hasVetoListeners(_propertyName)
172: || hasChangeListeners(_propertyName)) {
173:
174: evt = new IndexedPropertyChangeEvent(AbstractBean.this ,
175: _propertyName, Array.get(_value, i), newValue,
176: i);
177: }
178: fireVetoableChange(evt);
179:
180: Array.set(_value, i, newValue);
181:
182: // Inform property change and list model listeners.
183: firePropertyChange(evt);
184: if (_model != null)
185: _model.fireContentsChanged(i, i);
186: }
187:
188: /**
189: * Clears the array.
190: *
191: * @throws PropertyVetoException
192: */
193: public void clear() throws PropertyVetoException {
194: Object newArray = Array.newInstance(_value.getClass()
195: .getComponentType(), 0);
196: // Check with Vetoable change listeners.
197: PropertyChangeEvent evt = null;
198: if (hasVetoListeners(_propertyName)
199: || hasChangeListeners(_propertyName)) {
200:
201: evt = new PropertyChangeEvent(AbstractBean.this ,
202: _propertyName, _value, newArray);
203: }
204: fireVetoableChange(evt);
205:
206: // Update the property value.
207: _value = newArray;
208:
209: // Inform property change and list model listeners.
210: firePropertyChange(evt);
211: if (_model != null)
212: _model.fireContentsChanged(0, 0);
213: }
214:
215: /**
216: * Appends an element to an array.
217: *
218: * @param newValue The element to append (must not be null).
219: * @return The reallocated array, of the same component type as the
220: * original, or the type of the added element if the original
221: * was null.
222: * @throws IllegalArgumentException if <code>elem</code> is
223: * <code>null</code>.
224: */
225: public Object add(Object newValue) throws PropertyVetoException {
226: if (newValue == null)
227: throw new IllegalArgumentException();
228:
229: // Create the new property value.
230: Object newArray;
231: int index;
232: if (_value == null) {
233: index = 0;
234: newArray = Array.newInstance(newValue.getClass(),
235: index + 1);
236: } else {
237: index = Array.getLength(_value);
238: newArray = Array.newInstance(_value.getClass()
239: .getComponentType(), index + 1);
240: System.arraycopy(_value, 0, newArray, 0, index);
241: }
242: Array.set(newArray, index, newValue);
243:
244: // Check with Vetoable change listeners.
245: PropertyChangeEvent evt = null;
246: if (hasVetoListeners(_propertyName)
247: || hasChangeListeners(_propertyName)) {
248:
249: evt = new PropertyChangeEvent(AbstractBean.this ,
250: _propertyName, _value, newArray);
251: }
252: fireVetoableChange(evt);
253:
254: // Update the property value.
255: _value = newArray;
256:
257: // Inform property change and list model listeners.
258: firePropertyChange(evt);
259: if (_model != null)
260: _model.fireIntervalAdded(index, index);
261:
262: return newArray;
263: }
264:
265: /**
266: * Removes the first matching array element. The first element in
267: * <code>array</code> to match <code>elem</code> (as determined by
268: * <code>Object.equals(Object)</code>), is removed from the array, which
269: * is shortened by one.
270: *
271: * @param elem The element to remove.
272: * @return The reallocated array with the specified element removed, or
273: * the original array if it did not contain a matching element.
274: * @throws IllegalArgumentException if <code>elem</code> is
275: * <code>null</code>.
276: */
277: public Object remove(Object elem) throws PropertyVetoException {
278: if (_value == null)
279: return null;
280: if (elem == null)
281: throw new IllegalArgumentException();
282:
283: Object newArray = _value;
284: for (int index = 0, length = Array.getLength(_value); index < length; index++) {
285:
286: if (Array.get(_value, index).equals(elem)) {
287: newArray = Array.newInstance(_value.getClass()
288: .getComponentType(), length - 1);
289: System.arraycopy(_value, 0, newArray, 0, index);
290: System.arraycopy(_value, index + 1, newArray,
291: index, length - index - 1);
292:
293: // Check with Vetoable change listeners.
294: PropertyChangeEvent evt = null;
295: if (hasVetoListeners(_propertyName)
296: || hasChangeListeners(_propertyName)) {
297:
298: evt = new PropertyChangeEvent(
299: AbstractBean.this , _propertyName,
300: _value, newArray);
301: }
302: fireVetoableChange(evt);
303:
304: _value = newArray;
305:
306: // Inform property change and list model listeners.
307: firePropertyChange(evt);
308: if (_model != null)
309: _model.fireIntervalRemoved(index, index);
310: break;
311: }
312: }
313: return newArray;
314: }
315: }
316:
317: private IndexedPropertySupport getIndexedPropertySupport(
318: String propertyName) {
319: IndexedPropertySupport support = _indexedPropertySupportByName == null ? null
320: : (IndexedPropertySupport) _indexedPropertySupportByName
321: .get(propertyName);
322: if (support == null) {
323: throw new IllegalArgumentException(
324: "No such indexed property: " + propertyName);
325: }
326: return support;
327: }
328:
329: protected final Object get(int propertyIndex) {
330: return _indexedPropertySupport[propertyIndex].get();
331: }
332:
333: protected final Object get(int propertyIndex, int index) {
334: return _indexedPropertySupport[propertyIndex].get(index);
335: }
336:
337: protected final void set(int propertyIndex, Object array)
338: throws PropertyVetoException {
339:
340: _indexedPropertySupport[propertyIndex].set(array);
341: }
342:
343: protected final void set(int propertyIndex, int index,
344: Object newValue) throws PropertyVetoException {
345:
346: _indexedPropertySupport[propertyIndex].set(index, newValue);
347: }
348:
349: protected final Object add(int propertyIndex, Object newValue)
350: throws PropertyVetoException {
351:
352: return _indexedPropertySupport[propertyIndex].add(newValue);
353: }
354:
355: protected final Object remove(int propertyIndex, Object elem)
356: throws PropertyVetoException {
357:
358: return _indexedPropertySupport[propertyIndex].remove(elem);
359: }
360:
361: public final ListModel getListModel(String propertyName) {
362: return getIndexedPropertySupport(propertyName).getListModel();
363: }
364:
365: public final void clear(String propertyName)
366: throws PropertyVetoException {
367: getIndexedPropertySupport(propertyName).clear();
368: }
369:
370: public final void setBeanContext(BeanContext bc)
371: throws PropertyVetoException {
372: _beanContext = bc;
373: }
374:
375: public final BeanContext getBeanContext() {
376: return _beanContext;
377: }
378:
379: public final void addPropertyChangeListener(
380: PropertyChangeListener listener) {
381:
382: if (_pcs == null)
383: _pcs = new PropertyChangeSupport(this );
384: _pcs.addPropertyChangeListener(listener);
385: }
386:
387: public final void addPropertyChangeListener(String name,
388: PropertyChangeListener pcl) {
389:
390: if (_pcs == null)
391: _pcs = new PropertyChangeSupport(this );
392: _pcs.addPropertyChangeListener(name, pcl);
393: }
394:
395: public final void addVetoableChangeListener(
396: VetoableChangeListener listener) {
397:
398: if (_vcs == null)
399: _vcs = new VetoableChangeSupport(this );
400: _vcs.addVetoableChangeListener(listener);
401: }
402:
403: public final void addVetoableChangeListener(String name,
404: VetoableChangeListener vcl) {
405:
406: if (_vcs == null)
407: _vcs = new VetoableChangeSupport(this );
408: _vcs.addVetoableChangeListener(name, vcl);
409: }
410:
411: protected final void firePropertyChange(PropertyChangeEvent evt) {
412: if (_pcs != null)
413: _pcs.firePropertyChange(evt);
414: }
415:
416: protected final void firePropertyChange(String propertyName,
417: Object oldValue, Object newValue) {
418:
419: if (_pcs != null)
420: _pcs.firePropertyChange(propertyName, oldValue, newValue);
421: }
422:
423: protected final void firePropertyChange(String propertyName,
424: int oldValue, int newValue) {
425:
426: if (_pcs != null)
427: _pcs.firePropertyChange(propertyName, oldValue, newValue);
428: }
429:
430: protected final void firePropertyChange(String propertyName,
431: boolean oldValue, boolean newValue) {
432:
433: if (_pcs != null)
434: _pcs.firePropertyChange(propertyName, oldValue, newValue);
435: }
436:
437: protected final void fireVetoableChange(PropertyChangeEvent evt)
438: throws PropertyVetoException {
439:
440: if (_vcs != null)
441: _vcs.fireVetoableChange(evt);
442: }
443:
444: protected final void fireVetoableChange(String propertyName,
445: Object oldValue, Object newValue)
446: throws PropertyVetoException {
447:
448: if (_vcs != null)
449: _vcs.fireVetoableChange(propertyName, oldValue, newValue);
450: }
451:
452: protected final void fireVetoableChange(String propertyName,
453: int oldValue, int newValue) throws PropertyVetoException {
454:
455: if (_vcs != null)
456: _vcs.fireVetoableChange(propertyName, oldValue, newValue);
457: }
458:
459: protected final void fireVetoableChange(String propertyName,
460: boolean oldValue, boolean newValue)
461: throws PropertyVetoException {
462:
463: if (_vcs != null)
464: _vcs.fireVetoableChange(propertyName, oldValue, newValue);
465: }
466:
467: protected final boolean hasChangeListeners(String propertyName) {
468: return _pcs != null && _pcs.hasListeners(propertyName);
469: }
470:
471: protected final boolean hasVetoListeners(String propertyName) {
472: return _vcs != null && _vcs.hasListeners(propertyName);
473: }
474:
475: public final void removePropertyChangeListener(
476: PropertyChangeListener listener) {
477:
478: if (_pcs != null)
479: _pcs.removePropertyChangeListener(listener);
480: }
481:
482: public final void removePropertyChangeListener(String name,
483: PropertyChangeListener pcl) {
484:
485: if (_pcs != null)
486: _pcs.removePropertyChangeListener(name, pcl);
487: }
488:
489: public final void removeVetoableChangeListener(
490: VetoableChangeListener vcl) {
491: if (_vcs != null)
492: _vcs.removeVetoableChangeListener(vcl);
493: }
494:
495: public final void removeVetoableChangeListener(String name,
496: VetoableChangeListener vcl) {
497:
498: if (_vcs != null)
499: _vcs.removeVetoableChangeListener(name, vcl);
500: }
501: }
|