KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > form > FormProperty


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.form;
21
22 import java.beans.*;
23 import java.lang.reflect.*;
24 import org.openide.nodes.Node;
25
26 /**
27  * This class provides basic implementation of properties used in form module
28  * which are generated in the java code. FormProperty can use multiple property
29  * editors (via FormPropertyEditor) and special "design values" (holding some
30  * additional data - FormDesignValue implementations).
31  *
32  * FormProperty is an "interface" object that provides general access to one
33  * property of some other object (called "target object"). To make it work,
34  * only some connection to the target object must be implemented. There are
35  * two (abstract) methods for this purpose in FormProperty class:
36  * public Object getTargetValue();
37  * public void setTargetValue(Object value);
38  *
39  * NOTE: Binding to target object can be switched off for reading or writing
40  * by setting access type of property to DETACHED_READ or DETACHED_WRITE.
41  *
42  * There are some further methods (potentially suitable) for custom
43  * implementation (overriding the default implementation):
44  * public boolean supportsDefaultValue();
45  * public Object getDefaultValue();
46  * public PropertyEditor getExpliciteEditor();
47  *
48  * NOTE: Properties are created for nodes and presented in property sheet.
49  * Node object that owns properties should listen to the CURRENT_EDITOR
50  * property change on each property and call firePropertySetsChange(...)
51  * to notify the sheet about changing current property editor of a property.
52  *
53  * @author Tomas Pavek
54  */

55
56 public abstract class FormProperty extends Node.Property {
57
58     // --------------------
59
// constants
60

61     public static final String JavaDoc PROP_VALUE = "propertyValue"; // NOI18N
62
public static final String JavaDoc CURRENT_EDITOR = "currentEditor"; // NOI18N
63
public static final String JavaDoc PROP_VALUE_AND_EDITOR = "propertyValueAndEditor"; // NOI18N
64
public static final String JavaDoc PROP_PRE_CODE = "preCode"; // NOI18N
65
public static final String JavaDoc PROP_POST_CODE = "postCode"; // NOI18N
66

67     // "Access type" of the property (in relation to the target object).
68
// There are three levels of restriction possible:
69
// NORMAL_RW - no restriction on both property and target object
70
// DETACHED_READ, DETACHED_WRITE - no reading or writing on the target
71
// object (it is "detached"; the value is cached by the property)
72
// NO_READ, NO_WRITE - it is not possible to perform read or write on
73
// the property (so neither on the target object)
74
public static final int NORMAL_RW = 0;
75
76     public static final int DETACHED_READ = 1; // no reading from target (bit 0)
77
public static final int DETACHED_WRITE = 2; // no writing to target (bit 1)
78

79     private static final int NO_READ_PROP = 4; // bit 2
80
private static final int NO_WRITE_PROP = 8; // bit 3
81
public static final int NO_READ = DETACHED_READ | NO_READ_PROP; // no reading from property (bits 0,2)
82
public static final int NO_WRITE = DETACHED_WRITE | NO_WRITE_PROP; // no writing to property (bits 1,3)
83

84
85     // ------------------------
86
// variables
87
protected int propType = NORMAL_RW;
88
89     FormPropertyContext propertyContext;
90
91     protected Object JavaDoc propertyValue; // cached value of the property
92
protected boolean valueSet = false; // propertyValue validity
93
boolean valueChanged = false; // i.e. non-default
94

95     private boolean externalChangeMonitoring = true;
96     private Object JavaDoc lastRealValue; // for detecting external change of the property value
97

98     String JavaDoc preCode;
99     String JavaDoc postCode;
100
101     FormPropertyEditor formPropertyEditor;
102     PropertyEditor currentEditor;
103
104     private PropertyChangeSupport changeSupport;
105     private VetoableChangeSupport vetoableChangeSupport;
106     private boolean fireChanges = true;
107
108     private java.util.List JavaDoc<ValueConvertor> convertors;
109
110 // private DesignValueListener designValueListener = null;
111

112     // ---------------------------
113
// constructors
114

115     protected FormProperty(FormPropertyContext propertyContext,
116                            String JavaDoc name, Class JavaDoc type,
117                            String JavaDoc displayName, String JavaDoc shortDescription)
118     {
119         super(type);
120         setValue("changeImmediate", Boolean.FALSE); // NOI18N
121
setName(name);
122         setDisplayName(displayName);
123         setShortDescription(getDescriptionWithType(shortDescription));
124
125         this.propertyContext = FormPropertyContext.EmptyImpl.getInstance();
126         setPropertyContext(propertyContext);
127     }
128
129     protected FormProperty(FormPropertyContext propertyContext, Class JavaDoc type) {
130         super(type);
131         setValue("changeImmediate", Boolean.FALSE); // NOI18N
132

133         this.propertyContext = FormPropertyContext.EmptyImpl.getInstance();
134         setPropertyContext(propertyContext);
135     }
136
137     // constructor of property without PropertyContext
138
// setPropertyContext(...) should be called explicitly then
139
protected FormProperty(String JavaDoc name, Class JavaDoc type,
140                            String JavaDoc displayName, String JavaDoc shortDescription)
141     {
142         super(type);
143         setValue("changeImmediate", Boolean.FALSE); // NOI18N
144
setName(name);
145         setDisplayName(displayName);
146         setShortDescription(getDescriptionWithType(shortDescription));
147
148         this.propertyContext = FormPropertyContext.EmptyImpl.getInstance();
149     }
150
151     // constructor of property without PropertyContext;
152
// setPropertyContext(...) must be called explicitly before the property
153
// is used first time
154
protected FormProperty(Class JavaDoc type) {
155         super(type);
156         setValue("changeImmediate", Boolean.FALSE); // NOI18N
157

158         this.propertyContext = FormPropertyContext.EmptyImpl.getInstance();
159     }
160
161     private String JavaDoc getDescriptionWithType(String JavaDoc description) {
162         String JavaDoc type = org.openide.util.Utilities.getClassName(getValueType());
163         return description == null ?
164             FormUtils.getFormattedBundleString("HINT_PropertyType", // NOI18N
165
new Object JavaDoc[] { type }) :
166             FormUtils.getFormattedBundleString("HINT_PropertyTypeWithDescription", // NOI18N
167
new Object JavaDoc[] { type, description });
168     }
169
170     // ----------------------------------------
171
// getter, setter & related methods
172

173     public String JavaDoc getHtmlDisplayName() {
174         if (isChanged()) {
175             return "<b>" + getDisplayName(); // NOI18N
176
} else {
177             return null;
178         }
179     }
180
181     /** Gets the real value of this property directly from the target object.
182      */

183     public abstract Object JavaDoc getTargetValue() throws IllegalAccessException JavaDoc,
184                                                    InvocationTargetException;
185
186     /** Sets the real property value directly to the target object.
187      */

188     public abstract void setTargetValue(Object JavaDoc value) throws IllegalAccessException JavaDoc,
189                                                       IllegalArgumentException JavaDoc,
190                                                       InvocationTargetException;
191
192     /** Gets the value of the property.
193      */

194     public Object JavaDoc getValue() throws IllegalAccessException JavaDoc,
195                                     InvocationTargetException {
196 // if (!canRead())
197
// throw new IllegalAccessException("Not a readable property: "+getName());
198
Object JavaDoc value = checkCurrentValue();
199
200         if (valueSet || (propType & DETACHED_READ) == 0)
201             return value;
202
203         return getDefaultValue();
204     }
205
206     /** Sets the property value.
207      */

208     public void setValue(Object JavaDoc value) throws IllegalAccessException JavaDoc,
209                                               IllegalArgumentException JavaDoc,
210                                               InvocationTargetException
211     {
212 // if (!canWrite())
213
// throw new IllegalAccessException("Not a writeable property: "+getName());
214
// let the registered converters do something with the value (e.g. i18n)
215
if (fireChanges)
216             value = convertValue(value);
217
218         Object JavaDoc oldValue;
219         if (canRead()) {
220             try { // get the old value (still the current)
221
oldValue = getValue();
222             }
223             catch (Exception JavaDoc e) { // no problem -> keep null
224
oldValue = BeanSupport.NO_VALUE;
225             }
226         }
227         else oldValue = BeanSupport.NO_VALUE;
228         
229         if (value instanceof ValueWithEditor) {
230             // changing value and property editor at once
231
ValueWithEditor vwpe = (ValueWithEditor) value;
232             value = vwpe.getValue();
233             PropertyEditor newEditor = vwpe.getPropertyEditor(this);
234             PropertyEditor oldEditor = currentEditor;
235
236             if (newEditor != oldEditor) {
237                 // turn off change firing as we fire the two changes as one
238
boolean fire = fireChanges;
239                 fireChanges = false;
240                 setCurrentEditor(newEditor);
241                 setValue(value);
242                 fireChanges = fire;
243
244                 if (oldValue == BeanSupport.NO_VALUE)
245                     oldValue = null; // [should not BeanSupport.NO_VALUE remain??]
246

247                 propertyValueAndEditorChanged(
248                     new ValueWithEditor(oldValue, oldEditor),
249                     new ValueWithEditor(value, newEditor));
250
251                 return;
252             }
253             // othrewise continue setting only the value itself
254
}
255
256         if (oldValue != BeanSupport.NO_VALUE) {
257             // check whether the new value is different
258
if (!(value instanceof FormDesignValue) && equals(value, oldValue))
259                 return; // no change
260
}
261         else oldValue = null; // [should not BeanSupport.NO_VALUE remain??]
262

263         if (value == BeanSupport.NO_VALUE) {
264             // special value to be set - reset the change flag
265
setChanged(false);
266             propertyValue = value;
267             lastRealValue = null;
268             propertyValueChanged(oldValue, value);
269             return;
270         }
271
272         Object JavaDoc defValue = supportsDefaultValue() ?
273                             getDefaultValue() : BeanSupport.NO_VALUE;
274
275         if (canWriteToTarget()) {
276             // derive real value
277
Object JavaDoc realValue = getRealValue(value);
278
279             // set the real value to the target object
280
if (realValue != FormDesignValue.IGNORED_VALUE) {
281                 setTargetValue(realValue);
282             }
283             else if (valueSet && defValue != BeanSupport.NO_VALUE) {
284                 setTargetValue(defValue);
285             }
286
287             if (canReadFromTarget()) {
288                 lastRealValue = getTargetValue();
289 // if (value == realValue)
290
// value = lastRealValue;
291

292 /*
293   Some bad properties of bad beans return another value than the one just set.
294   So which one should be then used as the valid property value (displayed,
295   generated in code, etc) - the one just set, or that got in turn from getter?
296   (1) When the value just set is taken, then e.g. NONE_OPTION (-1) set to
297   debugGraphicsOption of JComponent will be used and code generated, altough it
298   is converted to 0 which is the default value, so no code should be generated.
299   (2) When oppositely the value from getter after performing setter is taken,
300   then e.g. setting "text/xml" to contentType of JEditorPane may fail at design
301   time (editor kit is not found), so the value reverts to "text/plain" (default)
302   and no code is generated, however it could work at runtime, so the code
303   should be generated.
304   [See also bug 12413.]
305 */

306             }
307         }
308
309         propertyValue = value; // cache the value for later...
310
valueSet = true;
311
312         // "changed" == property is readable and writeable and the new value
313
// is not equal to the default value (or default value doesn't exist).
314
setChanged((propType & (NO_READ_PROP|NO_WRITE_PROP)) == 0
315                    && (defValue == BeanSupport.NO_VALUE
316                        || !equals(value, defValue)));
317
318 // settleDesignValueListener(oldValue, value);
319
propertyValueChanged(oldValue, value);
320     }
321
322     /** This method gets the real value of the property. This is a support
323      * for special "design values" that hold additional information besides
324      * the real value that can be set directly to target object.
325      */

326     public final Object JavaDoc getRealValue() throws IllegalAccessException JavaDoc,
327                                               InvocationTargetException {
328         return getRealValue(getValue());
329     }
330
331     /** This method "extracts" the real value from the given object.
332      * FormDesignValue is recognized by default. Subclasses may override
333      * this method to provide additional conversions.
334      */

335     protected Object JavaDoc getRealValue(Object JavaDoc value) {
336         return value instanceof FormDesignValue ?
337                  ((FormDesignValue)value).getDesignValue() : value;
338     }
339
340     /** Returns whether this property has a default value (false by default).
341      * If any subclass provides default value, it should override this
342      * and getDefaultValue() methods.
343      * @return true if there is a default value, false otherwise
344      */

345     public boolean supportsDefaultValue () {
346         return false;
347     }
348     
349     public boolean isDefaultValue() {
350         return supportsDefaultValue() ? !isChanged() : true;
351     }
352
353     /** Returns a default value of this property.
354      * If any subclass provides default value, it should override this
355      * and supportsDefaultValue() methods.
356      * @return the default value (null by default :)
357      */

358     public Object JavaDoc getDefaultValue() {
359         return null;
360     }
361
362     /** Restores the property to its default value.
363      */

364     public void restoreDefaultValue() throws IllegalAccessException JavaDoc,
365                                              InvocationTargetException {
366 // if (!canWrite()) return;
367
setChanged(false);
368
369         Object JavaDoc oldValue = null;
370         Object JavaDoc defValue = getDefaultValue();
371
372         if (canRead()) {
373             try { // get the old value (still the current)
374
oldValue = getValue();
375                 if (!(defValue instanceof FormDesignValue)
376                         && equals(defValue, oldValue))
377                     return; // no change
378
}
379             catch (Exception JavaDoc e) {} // no problem -> keep null
380
}
381
382         if (canWriteToTarget()) {
383             // derive real value (from the default value)
384
Object JavaDoc realValue = getRealValue(defValue);
385
386             try {
387                 // set the default real value to the target
388
if (realValue != FormDesignValue.IGNORED_VALUE) {
389                     setTargetValue(realValue);
390 // lastRealValue = realValue;
391
}
392                 else if (defValue != BeanSupport.NO_VALUE) {
393                     setTargetValue(defValue);
394 // lastRealValue = defValue;
395
}
396 // else if (isExternalChangeMonitoring())
397
// lastRealValue = getTargetValue();
398

399                 lastRealValue = getTargetValue();
400             }
401             catch (IllegalArgumentException JavaDoc e) {} // should not happen
402
}
403
404         propertyValue = defValue;
405         valueSet = true;
406
407         // set default property editor as current
408
PropertyEditor prEd = findDefaultEditor();
409         if (prEd != null)
410             setCurrentEditor(prEd);
411
412 // settleDesignValueListener(oldValue, defValue);
413
propertyValueChanged(oldValue, defValue);
414     }
415
416     /** This method re-sets cached value of the property to the target object.
417      * (If there is no cached value here, nothing is set to target object.)
418      * This may be useful when target object was re-created and needs to be
419      * initialized in accordance with current properties.
420      */

421     public void reinstateTarget() throws IllegalAccessException JavaDoc,
422                                          InvocationTargetException {
423         if (valueSet && canWriteToTarget())
424             try {
425                 // re-set the real value of the property of the target object
426
Object JavaDoc realValue = getRealValue(propertyValue);
427
428                 if (realValue != FormDesignValue.IGNORED_VALUE) {
429                     setTargetValue(realValue);
430                     lastRealValue = realValue;
431                 }
432                 else if (isExternalChangeMonitoring())
433                     lastRealValue = getTargetValue();
434             }
435             catch (IllegalArgumentException JavaDoc e) { // should not happen
436
}
437     }
438
439     /** This method updates state of the property according to the target
440      * object. This may be useful when property needs to be initialized
441      * with existing target object. But this approach doesn't work well with
442      * bound and derived properties...
443      */

444     public void reinstateProperty() throws IllegalAccessException JavaDoc,
445                                            InvocationTargetException {
446         boolean mayChanged = canReadFromTarget()
447                              && (propType & (NO_READ_PROP|NO_WRITE_PROP)) == 0;
448             
449         if (mayChanged) {
450             Object JavaDoc value = getTargetValue();
451             if (supportsDefaultValue()) {
452                 Object JavaDoc defValue = getDefaultValue();
453                 mayChanged = !equals(value, defValue);
454             }
455             if (mayChanged) {
456                 propertyValue = value;
457                 lastRealValue = value;
458             }
459         }
460         
461         valueSet = mayChanged;
462         setChanged(mayChanged);
463     }
464
465     // ------------------------------
466
// boolean flags
467

468     /** Tests whether the property is readable.
469      */

470     public boolean canRead() {
471         return (propType & NO_READ_PROP) == 0;
472     }
473
474     /** Tests whether the property is writable.
475      */

476     public boolean canWrite() {
477         return (propType & NO_WRITE_PROP) == 0;
478     }
479
480     public final boolean canReadFromTarget() {
481         return /*canRead() &&*/ (propType & DETACHED_READ) == 0;
482     }
483
484     public final boolean canWriteToTarget() {
485         return /*canWrite() &&*/ (propType & DETACHED_WRITE) == 0;
486     }
487
488     /** Tests whether this property is marked as "changed". This method returns
489      * true if the value of the property is different from the default value
490      * and if it is accessible and replicable (readable and writeable property).
491      */

492     public boolean isChanged() {
493         if (valueChanged && valueSet) { // update the changed flag
494
try {
495                 checkCurrentValue();
496             }
497             catch (Exception JavaDoc ex) {
498             }
499         }
500         return valueChanged;
501     }
502
503     /** Sets explicitly the flag indicating changed property.
504      */

505     public void setChanged(boolean changed) {
506         valueChanged = changed;
507     }
508
509     // --------------------------------
510
// property editors
511

512     /** Gets a property editor for this property. This method implements
513      * Node.Property.getPropertyEditor() and need not be further overriden.
514      * It enables using of multiple individual editors by constructing
515      * FormPropertyEditor class. There are other methods for controling the
516      * FormPropertyEditor class here - see: getCurrentEditor(),
517      * setCurrentEditor(...) and getExpliciteEditor().
518      */

519     public PropertyEditor getPropertyEditor() {
520         PropertyEditor prEd;
521
522         if (formPropertyEditor == null) {
523             if (propertyContext.useMultipleEditors()) {
524                 formPropertyEditor = new FormPropertyEditor(this);
525                 prEd = formPropertyEditor;
526             }
527             else prEd = getCurrentEditor();
528         }
529         else prEd = formPropertyEditor;
530
531         return prEd;
532     }
533
534     /** Gets the currently selected property editor (from multiple editors
535      * managed by FormPropertyEditor).
536      */

537     public final PropertyEditor getCurrentEditor() {
538         if (currentEditor == null) {
539             currentEditor = findDefaultEditor();
540             if (currentEditor != null)
541                 propertyContext.initPropertyEditor(currentEditor);
542         }
543         return currentEditor;
544     }
545
546     /** Sets the current property editor that will be used for this property
547      * by FormPropertyEditor.
548      */

549     public final void setCurrentEditor(PropertyEditor newEditor) {
550         if (newEditor != currentEditor) {
551             if (newEditor != null)
552                 propertyContext.initPropertyEditor(newEditor);
553
554             if (formPropertyEditor != null) {
555                 if (currentEditor != null)
556                     currentEditor.removePropertyChangeListener(formPropertyEditor);
557                 if (newEditor != null)
558                     newEditor.addPropertyChangeListener(formPropertyEditor);
559             }
560
561             PropertyEditor old = currentEditor;
562             currentEditor = newEditor;
563             currentEditorChanged(old, newEditor);
564         }
565     }
566
567     /** Gets the property editor explicitly designated for this property.
568      * This editor is taken as default by FormPropertyEditor.
569      * Subclasses should override this method if they provide a special
570      * editor for this property.
571      */

572     public PropertyEditor getExpliciteEditor() {
573         return null;
574     }
575
576     // ------------------------------
577
// code generation
578

579     /** Gets the java code initializing the property value. It is obtained from
580      * current property editor. Example: "Button 1"
581      */

582     public String JavaDoc getJavaInitializationString() {
583         try {
584             Object JavaDoc value = getValue();
585             if (value == null)
586                 return "null"; // NOI18N
587

588             if (value == BeanSupport.NO_VALUE)
589                 return null;
590
591             PropertyEditor ed = getCurrentEditor();
592             if (ed == null)
593                 return null;
594
595             // should we create a new instance of editor?
596
// if (ed instanceof RADConnectionPropertyEditor)
597
// ed = new RADConnectionPropertyEditor(getValueType());
598
// else
599
// ed = (PropertyEditor)ed.getClass().newInstance();
600
// propertyContext.initPropertyEditor(ed);
601

602             if (ed.getValue() != value)
603                 ed.setValue(value);
604             return ed.getJavaInitializationString();
605         }
606         catch (Exception JavaDoc e) {
607             e.printStackTrace();
608         }
609         return null;
610     }
611
612     /** Gets the java code for setting the property value (without the object
613      * on which the property is set, and without semicolon at the end).
614      * This method is optional. Example: setText("Button 1")
615      */

616     String JavaDoc getPartialSetterCode(String JavaDoc javaInitStr) {
617         if (javaInitStr == null)
618             return null;
619
620         Method writeMethod = getWriteMethod();
621         if (writeMethod == null)
622             return null;
623
624         return writeMethod.getName() + "(" + javaInitStr + ")"; // NOI18N
625
}
626
627     /** Gets the complete java code for setting the property, including the
628      * semicolon at the end of the line. This method is optional.
629      * Example: jButton1.setText("Button 1");
630      */

631     String JavaDoc getWholeSetterCode(String JavaDoc javaInitStr) {
632         return null;
633     }
634
635     /**
636      * Gets the write method setting the property.
637      * Used by {@link JavaCodeGenerator}.
638      *
639      */

640     protected Method getWriteMethod() {
641     return null;
642     }
643     
644     /** Gets the code to be generated before the property setter code
645      * (on separate line).
646      */

647     public String JavaDoc getPreCode() {
648         return preCode;
649     }
650
651     /** Gets the code to be generated after the property setter code
652      * (on separate line).
653      */

654     public String JavaDoc getPostCode() {
655         return postCode;
656     }
657
658     /** Sets the code to be generated before the property setter code
659      * (on separate line).
660      */

661     public void setPreCode(String JavaDoc value) {
662         preCode = value;
663     }
664
665     /** Sets the code to be generated after the property setter code
666      * (on separate line).
667      */

668     public void setPostCode(String JavaDoc value) {
669         postCode = value;
670     }
671
672     // ------------------------
673

674     public FormPropertyContext getPropertyContext() {
675         return propertyContext;
676     }
677
678     public void setPropertyContext(FormPropertyContext newContext) {
679         if (newContext == null)
680             newContext = FormPropertyContext.EmptyImpl.getInstance();
681         if (propertyContext != null
682             && formPropertyEditor != null
683             && propertyContext.useMultipleEditors()
684                  != newContext.useMultipleEditors())
685         {
686             if (currentEditor != null)
687                 currentEditor.removePropertyChangeListener(formPropertyEditor);
688             formPropertyEditor = null;
689         }
690
691         propertyContext = newContext;
692
693         if (currentEditor != null)
694             propertyContext.initPropertyEditor(currentEditor);
695     }
696
697     public int getAccessType() {
698         return propType;
699     }
700
701     public void setAccessType(int type) {
702         if (type >= 0)
703             propType = type;
704     }
705
706     public boolean isExternalChangeMonitoring() {
707         return externalChangeMonitoring && propType == NORMAL_RW;
708     }
709
710     public void setExternalChangeMonitoring(boolean val) {
711         externalChangeMonitoring = val;
712     }
713
714     // ----------------------------
715

716     public void addPropertyChangeListener(PropertyChangeListener l) {
717         synchronized (this) {
718             if (changeSupport == null)
719                 changeSupport = new PropertyChangeSupport(this);
720         }
721         changeSupport.addPropertyChangeListener(l);
722     }
723
724     public void removePropertyChangeListener(PropertyChangeListener l) {
725         if (changeSupport != null)
726             changeSupport.removePropertyChangeListener(l);
727     }
728
729     public void addVetoableChangeListener(VetoableChangeListener l) {
730         synchronized (this) {
731             if (vetoableChangeSupport == null)
732                 vetoableChangeSupport = new VetoableChangeSupport(this);
733         }
734         vetoableChangeSupport.addVetoableChangeListener(l);
735     }
736
737     public void removeVetoableChangeListener(VetoableChangeListener l) {
738         if (vetoableChangeSupport != null)
739             vetoableChangeSupport.removeVetoableChangeListener(l);
740     }
741
742     public boolean isChangeFiring() {
743         return fireChanges;
744     }
745
746     public void setChangeFiring(boolean fire) {
747         fireChanges = fire;
748     }
749
750     protected void propertyValueChanged(Object JavaDoc old, Object JavaDoc current) {
751         if (fireChanges) {
752             try {
753                 firePropertyChange(PROP_VALUE, old, current);
754             }
755             catch (PropertyVetoException ex) {
756                 boolean fire = fireChanges;
757                 fireChanges = false;
758                 try {
759                     setValue(old);
760                 }
761                 catch (Exception JavaDoc ex2) {} // ignore
762
fireChanges = fire;
763             }
764         }
765     }
766
767     protected void currentEditorChanged(PropertyEditor old,
768                                         PropertyEditor current)
769     {
770         if (fireChanges) {
771             try {
772                 firePropertyChange(CURRENT_EDITOR, old, current);
773             }
774             catch (PropertyVetoException ex) {} // won't happen
775
}
776     }
777
778     protected void propertyValueAndEditorChanged(ValueWithEditor old,
779                                                  ValueWithEditor current)
780     {
781         if (fireChanges) {
782             try {
783                 firePropertyChange(PROP_VALUE_AND_EDITOR, old, current);
784             }
785             catch (PropertyVetoException ex) {
786                 boolean fire = fireChanges;
787                 fireChanges = false;
788                 try {
789                     setValue(old);
790                 }
791                 catch (Exception JavaDoc ex2) {} // ignore
792
fireChanges = fire;
793             }
794         }
795     }
796
797     private void firePropertyChange(String JavaDoc propName, Object JavaDoc old, Object JavaDoc current)
798         throws PropertyVetoException
799     {
800         if (vetoableChangeSupport != null && !CURRENT_EDITOR.equals(propName)) {
801             vetoableChangeSupport.fireVetoableChange(propName, old, current);
802         }
803         if (changeSupport != null) {
804             changeSupport.firePropertyChange(propName, old, current);
805         }
806     }
807
808     public void addValueConvertor(ValueConvertor conv) {
809         synchronized (this) {
810             if (convertors == null)
811                 convertors = new java.util.LinkedList JavaDoc<ValueConvertor>();
812             else
813                 convertors.remove(conv);
814             convertors.add(conv);
815         }
816     }
817
818     public void removeValueConvertor(ValueConvertor conv) {
819         synchronized (this) {
820             if (convertors != null)
821                 convertors.remove(conv);
822         }
823     }
824
825     protected Object JavaDoc convertValue(Object JavaDoc value) {
826         if (convertors != null) {
827             for (ValueConvertor conv : convertors) {
828                 Object JavaDoc val = conv.convert(value, this);
829                 if (val != value)
830                     return val;
831             }
832         }
833         return value;
834     }
835
836     // ----------------------------
837
// private methods
838

839     private Object JavaDoc checkCurrentValue()
840         throws IllegalAccessException JavaDoc, InvocationTargetException
841     {
842         if (valueSet) {
843             Object JavaDoc value = null;
844
845             if (isExternalChangeMonitoring()) {
846                 value = getTargetValue();
847                 if (!equals(value, lastRealValue)
848                     && (value == null || propertyValue == null
849                         || value.getClass().isAssignableFrom(propertyValue.getClass())))
850                 { // the value is different from the one last set
851
valueSet = false;
852                     setChanged(false);
853 // if (value == null
854
// || ((value.getClass().isPrimitive() || value instanceof String)
855
// && !value.equals(lastRealValue)))
856
// { // the real value of the property was changed "externally"
857
// // e.g. like label of JButton is changed when text is set
858
// setChanged(false);
859
// }
860
lastRealValue = null;
861                     return value;
862                     // [fire property editor change - for refreshing property sheet??]
863
}
864             }
865             return propertyValue;
866         }
867         return (propType & DETACHED_READ) == 0 ? getTargetValue() : null;
868     }
869
870     PropertyEditor findDefaultEditor() {
871         PropertyEditor defaultEditor = getExpliciteEditor();
872         if (defaultEditor != null)
873             return defaultEditor;
874         return FormPropertyEditorManager.findEditor(this);
875     }
876
877     // --------
878

879     // [we could probably use org.openide.util.Utilities.compareObjects instead]
880
private static boolean equals(Object JavaDoc obj1, Object JavaDoc obj2) {
881         if (obj1 == obj2)
882             return true;
883
884         if (obj1 == null || obj2 == null)
885             return false;
886
887         Class JavaDoc cls1 = obj1.getClass();
888         Class JavaDoc cls2 = obj2.getClass();
889
890         if (!cls1.isArray() || !cls1.equals(cls2))
891             return obj1.equals(obj2);
892
893         // and this is what is special on this method - comparing arrays...
894
Class JavaDoc cType = cls1.getComponentType();
895         if (!cType.isPrimitive()) {
896             Object JavaDoc[] array1 = (Object JavaDoc[]) obj1;
897             Object JavaDoc[] array2 = (Object JavaDoc[]) obj2;
898             if (array1.length != array2.length)
899                 return false;
900             for (int i=0; i < array1.length; i++)
901                 if (!equals(array1[i], array2[i]))
902                     return false;
903             return true;
904         }
905
906         if (Integer.TYPE.equals(cType)) {
907             int[] array1 = (int[]) obj1;
908             int[] array2 = (int[]) obj2;
909             if (array1.length != array2.length)
910                 return false;
911             for (int i=0; i < array1.length; i++)
912                 if (array1[i] != array2[i])
913                     return false;
914             return true;
915         }
916
917         if (Boolean.TYPE.equals(cType)) {
918             boolean[] array1 = (boolean[]) obj1;
919             boolean[] array2 = (boolean[]) obj2;
920             if (array1.length != array2.length)
921                 return false;
922             for (int i=0; i < array1.length; i++)
923                 if (array1[i] != array2[i])
924                     return false;
925             return true;
926         }
927
928         if (Long.TYPE.equals(cType)) {
929             long[] array1 = (long[]) obj1;
930             long[] array2 = (long[]) obj2;
931             if (array1.length != array2.length)
932                 return false;
933             for (int i=0; i < array1.length; i++)
934                 if (array1[i] != array2[i])
935                     return false;
936             return true;
937         }
938
939         if (Double.TYPE.equals(cType)) {
940             double[] array1 = (double[]) obj1;
941             double[] array2 = (double[]) obj2;
942             if (array1.length != array2.length)
943                 return false;
944             for (int i=0; i < array1.length; i++)
945                 if (array1[i] != array2[i])
946                     return false;
947             return true;
948         }
949
950         if (Byte.TYPE.equals(cType)) {
951             byte[] array1 = (byte[]) obj1;
952             byte[] array2 = (byte[]) obj2;
953             if (array1.length != array2.length)
954                 return false;
955             for (int i=0; i < array1.length; i++)
956                 if (array1[i] != array2[i])
957                     return false;
958             return true;
959         }
960
961         if (Character.TYPE.equals(cType)) {
962             char[] array1 = (char[]) obj1;
963             char[] array2 = (char[]) obj2;
964             if (array1.length != array2.length)
965                 return false;
966             for (int i=0; i < array1.length; i++)
967                 if (array1[i] != array2[i])
968                     return false;
969             return true;
970         }
971
972         if (Float.TYPE.equals(cType)) {
973             float[] array1 = (float[]) obj1;
974             float[] array2 = (float[]) obj2;
975             if (array1.length != array2.length)
976                 return false;
977             for (int i=0; i < array1.length; i++)
978                 if (array1[i] != array2[i])
979                     return false;
980             return true;
981         }
982
983         if (Short.TYPE.equals(cType)) {
984             short[] array1 = (short[]) obj1;
985             short[] array2 = (short[]) obj2;
986             if (array1.length != array2.length)
987                 return false;
988             for (int i=0; i < array1.length; i++)
989                 if (array1[i] != array2[i])
990                     return false;
991             return true;
992         }
993
994         return false;
995     }
996
997 /* private void settleDesignValueListener(Object oldVal, Object newVal) {
998         if (oldVal == newVal) return;
999
1000        if (oldVal instanceof FormDesignValue.Listener && designValueListener != null)
1001            ((FormDesignValue.Listener)oldVal).removeChangeListener(designValueListener);
1002
1003        if (newVal instanceof FormDesignValue.Listener) {
1004            if (designValueListener == null)
1005                designValueListener = new DesignValueListener();
1006            ((FormDesignValue.Listener)newVal).addChangeListener(designValueListener);
1007        }
1008    }
1009
1010    class DesignValueListener implements javax.swing.event.ChangeListener {
1011        public void stateChanged(javax.swing.event.ChangeEvent e) {
1012            if (valueSet && propertyValue == e.getSource())
1013                try {
1014                    setValue(propertyValue);
1015                }
1016                catch (Exception ex) { // can't do nothing here
1017                }
1018        }
1019    } */

1020
1021    // -----
1022

1023    /**
1024     * Convertor can be registered on a property and change value comming to
1025     * setValue method to something else. Used for automatic i18n.
1026     */

1027    public interface ValueConvertor {
1028        public Object JavaDoc convert(Object JavaDoc value, FormProperty property);
1029    }
1030
1031    // ------------
1032

1033    public static final class ValueWithEditor {
1034        private Object JavaDoc value;
1035        private PropertyEditor propertyEditor;
1036        private int propertyEditorIndex;
1037
1038        ValueWithEditor(Object JavaDoc value, PropertyEditor propertyEditor) {
1039            this.value = value;
1040            this.propertyEditor = propertyEditor;
1041        }
1042
1043        ValueWithEditor(Object JavaDoc value, int propertyEditorIndex) {
1044            this.value = value;
1045            this.propertyEditorIndex = propertyEditorIndex;
1046        }
1047
1048        public Object JavaDoc getValue() {
1049            return value;
1050        }
1051
1052        public PropertyEditor getPropertyEditor() {
1053            return propertyEditor;
1054        }
1055
1056        PropertyEditor getPropertyEditor(FormProperty property) {
1057            if (propertyEditor != null)
1058                return propertyEditor;
1059            if (propertyEditorIndex < 0)
1060                return null;
1061
1062            PropertyEditor pe = property.getPropertyEditor();
1063            if (pe instanceof FormPropertyEditor) {
1064                FormPropertyEditor fpe = (FormPropertyEditor) pe;
1065                PropertyEditor[] allEds = fpe.getAllEditors();
1066                if (propertyEditorIndex < allEds.length)
1067                    return allEds[propertyEditorIndex];
1068            }
1069
1070            return null;
1071        }
1072    }
1073
1074    public static Object JavaDoc getEnclosedValue(Object JavaDoc value) {
1075        return value instanceof ValueWithEditor ? ((ValueWithEditor)value).getValue() : value;
1076    }
1077
1078    // ------------
1079

1080    public static interface Filter {
1081        public boolean accept(FormProperty property);
1082    }
1083
1084    public static final Filter CHANGED_PROPERTY_FILTER = new Filter() {
1085        public boolean accept(FormProperty property) {
1086            return property.isChanged();
1087        }
1088    };
1089}
1090
Popular Tags