001: /*
002: * Copyright (c) 2004 JETA Software, Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without modification,
005: * are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JETA Software nor the names of its contributors may
015: * be used to endorse or promote products derived from this software without
016: * specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
021: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
022: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
023: * INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
024: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
025: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026: * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: */
029:
030: package com.jeta.forms.store.properties;
031:
032: import java.io.IOException;
033: import java.util.Collection;
034: import java.util.Iterator;
035:
036: import com.jeta.forms.components.panel.FormPanel;
037: import com.jeta.forms.gui.beans.JETABean;
038: import com.jeta.forms.store.AbstractJETAPersistable;
039: import com.jeta.forms.store.JETAObjectInput;
040: import com.jeta.forms.store.JETAObjectOutput;
041: import com.jeta.forms.store.jml.JMLObjectOutput;
042:
043: /**
044: * A <code>JETAProperty</code> is the base class for all <i>custom</i>
045: * properties for a Java bean. A custom property does more than simply hold a
046: * value. They allow a JETABean to add additional properties to a Java bean that
047: * are not defined in the BeanInfo. JETAProperties can also have custom logic
048: * for setting the value on a bean as well as versionable serialization. For
049: * example, some Swing components such as JTree and JList are generally
050: * contained in a JScrollPane. So a <i>scrollable</i> custom property was
051: * created that allows the user to simply check or uncheck the scrollable
052: * behavior for these components in the designer. This is much easier than
053: * having to create a JScrollPane instance on a form and manually adding a child
054: * component. The scrollable property has the logic necessary to create the
055: * JScrollPane at runtime and add the underlying Java bean.
056: *
057: * The following methods are invoked when a JETAProperty value is set on a bean:
058: * 1. setValue this updates this property with a new value if necessary. The
059: * property has the option of updating the bean here as well. 2. updateBean If
060: * needed, updates the associated bean with current property values. This is
061: * needed during initialization. Not all properties need to implement this
062: * method. See: {@link com.jeta.forms.gui.beans.JETABean}
063: *
064: * @author Jeff Tassin
065: */
066: public abstract class JETAProperty extends AbstractJETAPersistable {
067: static final long serialVersionUID = -7709719636185198546L;
068:
069: /**
070: * The current version number of this class
071: */
072: public static final int VERSION = 1;
073:
074: /**
075: * The name for this property
076: */
077: private String m_name;
078:
079: /**
080: * The type for this property. This type should match the type of the value.
081: *
082: * @deprecated no longer required.
083: */
084: private Class m_type;
085:
086: /**
087: * Flag that indicates if this property is preferred.
088: */
089: private transient boolean m_preferred = true;
090:
091: /**
092: * Creates an unitialized <code>JETAProperty</code> instance.
093: */
094: public JETAProperty() {
095: this (null);
096: }
097:
098: /**
099: * Creates a <code>JETAProperty</code> with specified name
100: *
101: * @param name
102: * the name for this property
103: */
104: public JETAProperty(String name) {
105: m_name = name;
106: }
107:
108: /**
109: * Object equals implementation.
110: */
111: public boolean equals(Object object) {
112: if (object instanceof JETAProperty) {
113: JETAProperty jp = (JETAProperty) object;
114: return (super .equals(object) && isEqual(m_name, jp.m_name)
115: && isEqual(m_type, jp.m_type) && m_preferred == jp.m_preferred);
116: } else {
117: return false;
118: }
119: }
120:
121: /**
122: * Returns the name of this property.
123: *
124: * @return the name of this property
125: */
126: public String getName() {
127: return m_name;
128: }
129:
130: /**
131: * Returns true if both collections have equal size and each object in the
132: * collection equals the corresponding object in the same position in the
133: * other collection. If both collections are null, true is returned.
134: */
135: protected static boolean isCollectionsEqual(Collection c1,
136: Collection c2) {
137: if (c1 != null) {
138: if (c2 == null || c1.size() != c2.size())
139: return false;
140:
141: Iterator i1 = c1.iterator();
142: Iterator i2 = c2.iterator();
143: while (i1.hasNext()) {
144: if (!(i1.next().equals(i2.next())))
145: return false;
146: }
147: return true;
148: } else {
149: return (c2 == null);
150: }
151: }
152:
153: /**
154: * Tests if two objects are equal. If both are null, true is returned.
155: */
156: protected static boolean isEqual(Object o1, Object o2) {
157: if (o1 instanceof Collection && o2 instanceof Collection)
158: return isCollectionsEqual((Collection) o1, (Collection) o2);
159: if (o1 != null) {
160: return o1.equals(o2);
161: } else {
162: return (o2 == null);
163: }
164: }
165:
166: /**
167: * Returns the flag that indicates if this property is preferred. A
168: * preferred property is shown in the Basic tab in the properties panel in
169: * the designer.
170: *
171: * @return the flag that indicates if this property is preferred
172: */
173: public boolean isPreferred() {
174: return m_preferred;
175: }
176:
177: /**
178: * Returns true if this property is not serializable.
179: *
180: * @return true if this object is not serializable
181: */
182: public boolean isTransient() {
183: return false;
184: }
185:
186: /**
187: * PostInitialize is called once after all components in a form have been
188: * instantiated at runtime (not design time). This gives each property a
189: * chance to do some last minute initializations that might depend on the
190: * top level parent. An example of this is button groups for radio buttons.
191: * Button groups are global to the top-level parent and not to the nested
192: * form that might contain the radio button.
193: *
194: * @param panel
195: * the top level parent that contains the form.
196: * @param jbean
197: * the JETABean associated with this property
198: */
199: public void postInitialize(FormPanel panel, JETABean jbean) {
200: // no op here. Most properties don't need this call.
201: }
202:
203: /**
204: * Sets the flag that indicates if this property is preferred. A preferred
205: * property is shown in the Basic tab in the properties panel in the
206: * designer.
207: *
208: * @param pref
209: * the flag that indicates if this property is preferred
210: */
211: public void setPreferred(boolean pref) {
212: m_preferred = pref;
213: }
214:
215: /**
216: * Sets this property to that of another property.
217: */
218: public abstract void setValue(Object obj);
219:
220: /**
221: * Updates the specified bean with the current values of this property.
222: *
223: * @param jbean
224: * the jetabean to update.
225: */
226: public abstract void updateBean(JETABean jbean);
227:
228: /**
229: * Externalizable Implementation
230: */
231: public void read(JETAObjectInput in) throws ClassNotFoundException,
232: IOException {
233: int version = in.readVersion();
234: m_name = in.readString("name");
235: /** type is deprecated */
236: Class type = (Class) in.readObject("type");
237: }
238:
239: /**
240: * Externalizable Implementation
241: */
242: public void write(JETAObjectOutput out) throws IOException {
243: /** this is a hack to prevent too much noise when writing to XML */
244: if (!(out instanceof JMLObjectOutput))
245: out.writeVersion(VERSION);
246:
247: out.writeObject("name", m_name);
248:
249: /** this is a hack to prevent too much noise when writing to XML */
250: if (!(out instanceof JMLObjectOutput))
251: out.writeObject("type", m_type);
252: }
253:
254: }
|