1 /*
   2  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.beans;
  27 
  28 import java.beans.*;
  29 
  30 /**
  31  * This is a support class to help build property editors.
  32  * <p>
  33  * It can be used either as a base class or as a delegate.
  34  *
  35  * @since 1.1
  36  */
  37 
  38 public class PropertyEditorSupport implements PropertyEditor {
  39 
  40     /**
  41      * Constructs a <code>PropertyEditorSupport</code> object.
  42      *
  43      * @since 1.5
  44      */
  45     public PropertyEditorSupport() {
  46         setSource(this);
  47     }
  48 
  49     /**
  50      * Constructs a <code>PropertyEditorSupport</code> object.
  51      *
  52      * @param source the source used for event firing
  53      * @since 1.5
  54      */
  55     public PropertyEditorSupport(Object source) {
  56         if (source == null) {
  57            throw new NullPointerException();
  58         }
  59         setSource(source);
  60     }
  61 
  62     /**
  63      * Returns the bean that is used as the
  64      * source of events. If the source has not
  65      * been explicitly set then this instance of
  66      * <code>PropertyEditorSupport</code> is returned.
  67      *
  68      * @return the source object or this instance
  69      * @since 1.5
  70      */
  71     public Object getSource() {
  72         return source;
  73     }
  74 
  75     /**
  76      * Sets the source bean.
  77      * <p>
  78      * The source bean is used as the source of events
  79      * for the property changes. This source should be used for information
  80      * purposes only and should not be modified by the PropertyEditor.
  81      *
  82      * @param source source object to be used for events
  83      * @since 1.5
  84      */
  85     public void setSource(Object source) {
  86         this.source = source;
  87     }
  88 
  89     /**
  90      * Set (or change) the object that is to be edited.
  91      *
  92      * @param value The new target object to be edited.  Note that this
  93      *     object should not be modified by the PropertyEditor, rather
  94      *     the PropertyEditor should create a new object to hold any
  95      *     modified value.
  96      */
  97     public void setValue(Object value) {
  98         this.value = value;
  99         firePropertyChange();
 100     }
 101 
 102     /**
 103      * Gets the value of the property.
 104      *
 105      * @return The value of the property.
 106      */
 107     public Object getValue() {
 108         return value;
 109     }
 110 
 111     //----------------------------------------------------------------------
 112 
 113     /**
 114      * Determines whether the class will honor the paintValue method.
 115      *
 116      * @return  True if the class will honor the paintValue method.
 117      */
 118 
 119     public boolean isPaintable() {
 120         return false;
 121     }
 122 
 123     /**
 124      * Paint a representation of the value into a given area of screen
 125      * real estate.  Note that the propertyEditor is responsible for doing
 126      * its own clipping so that it fits into the given rectangle.
 127      * <p>
 128      * If the PropertyEditor doesn't honor paint requests (see isPaintable)
 129      * this method should be a silent noop.
 130      *
 131      * @param gfx  Graphics object to paint into.
 132      * @param box  Rectangle within graphics object into which we should paint.
 133      */
 134     public void paintValue(java.awt.Graphics gfx, java.awt.Rectangle box) {
 135     }
 136 
 137     //----------------------------------------------------------------------
 138 
 139     /**
 140      * This method is intended for use when generating Java code to set
 141      * the value of the property.  It should return a fragment of Java code
 142      * that can be used to initialize a variable with the current property
 143      * value.
 144      * <p>
 145      * Example results are "2", "new Color(127,127,34)", "Color.orange", etc.
 146      *
 147      * @return A fragment of Java code representing an initializer for the
 148      *          current value.
 149      */
 150     public String getJavaInitializationString() {
 151         return "???";
 152     }
 153 
 154     //----------------------------------------------------------------------
 155 
 156     /**
 157      * Gets the property value as a string suitable for presentation
 158      * to a human to edit.
 159      *
 160      * @return The property value as a string suitable for presentation
 161      *       to a human to edit.
 162      * <p>   Returns null if the value can't be expressed as a string.
 163      * <p>   If a non-null value is returned, then the PropertyEditor should
 164      *       be prepared to parse that string back in setAsText().
 165      */
 166     public String getAsText() {
 167         return (this.value != null)
 168                 ? this.value.toString()
 169                 : null;
 170     }
 171 
 172     /**
 173      * Sets the property value by parsing a given String.  May raise
 174      * java.lang.IllegalArgumentException if either the String is
 175      * badly formatted or if this kind of property can't be expressed
 176      * as text.
 177      *
 178      * @param text  The string to be parsed.
 179      */
 180     public void setAsText(String text) throws java.lang.IllegalArgumentException {
 181         if (value instanceof String) {
 182             setValue(text);
 183             return;
 184         }
 185         throw new java.lang.IllegalArgumentException(text);
 186     }
 187 
 188     //----------------------------------------------------------------------
 189 
 190     /**
 191      * If the property value must be one of a set of known tagged values,
 192      * then this method should return an array of the tag values.  This can
 193      * be used to represent (for example) enum values.  If a PropertyEditor
 194      * supports tags, then it should support the use of setAsText with
 195      * a tag value as a way of setting the value.
 196      *
 197      * @return The tag values for this property.  May be null if this
 198      *   property cannot be represented as a tagged value.
 199      *
 200      */
 201     public String[] getTags() {
 202         return null;
 203     }
 204 
 205     //----------------------------------------------------------------------
 206 
 207     /**
 208      * A PropertyEditor may chose to make available a full custom Component
 209      * that edits its property value.  It is the responsibility of the
 210      * PropertyEditor to hook itself up to its editor Component itself and
 211      * to report property value changes by firing a PropertyChange event.
 212      * <P>
 213      * The higher-level code that calls getCustomEditor may either embed
 214      * the Component in some larger property sheet, or it may put it in
 215      * its own individual dialog, or ...
 216      *
 217      * @return A java.awt.Component that will allow a human to directly
 218      *      edit the current property value.  May be null if this is
 219      *      not supported.
 220      */
 221 
 222     public java.awt.Component getCustomEditor() {
 223         return null;
 224     }
 225 
 226     /**
 227      * Determines whether the propertyEditor can provide a custom editor.
 228      *
 229      * @return  True if the propertyEditor can provide a custom editor.
 230      */
 231     public boolean supportsCustomEditor() {
 232         return false;
 233     }
 234 
 235     //----------------------------------------------------------------------
 236 
 237     /**
 238      * Adds a listener for the value change.
 239      * When the property editor changes its value
 240      * it should fire a {@link PropertyChangeEvent}
 241      * on all registered {@link PropertyChangeListener}s,
 242      * specifying the {@code null} value for the property name.
 243      * If the source property is set,
 244      * it should be used as the source of the event.
 245      * <p>
 246      * The same listener object may be added more than once,
 247      * and will be called as many times as it is added.
 248      * If {@code listener} is {@code null},
 249      * no exception is thrown and no action is taken.
 250      *
 251      * @param listener  the {@link PropertyChangeListener} to add
 252      */
 253     public synchronized void addPropertyChangeListener(
 254                                 PropertyChangeListener listener) {
 255         if (listeners == null) {
 256             listeners = new java.util.Vector<>();
 257         }
 258         listeners.addElement(listener);
 259     }
 260 
 261     /**
 262      * Removes a listener for the value change.
 263      * <p>
 264      * If the same listener was added more than once,
 265      * it will be notified one less time after being removed.
 266      * If {@code listener} is {@code null}, or was never added,
 267      * no exception is thrown and no action is taken.
 268      *
 269      * @param listener  the {@link PropertyChangeListener} to remove
 270      */
 271     public synchronized void removePropertyChangeListener(
 272                                 PropertyChangeListener listener) {
 273         if (listeners == null) {
 274             return;
 275         }
 276         listeners.removeElement(listener);
 277     }
 278 
 279     /**
 280      * Report that we have been modified to any interested listeners.
 281      */
 282     public void firePropertyChange() {
 283         java.util.Vector<PropertyChangeListener> targets;
 284         synchronized (this) {
 285             if (listeners == null) {
 286                 return;
 287             }
 288             targets = unsafeClone(listeners);
 289         }
 290         // Tell our listeners that "everything" has changed.
 291         PropertyChangeEvent evt = new PropertyChangeEvent(source, null, null, null);
 292 
 293         for (int i = 0; i < targets.size(); i++) {
 294             PropertyChangeListener target = targets.elementAt(i);
 295             target.propertyChange(evt);
 296         }
 297     }
 298 
 299     @SuppressWarnings("unchecked")
 300     private <T> java.util.Vector<T> unsafeClone(java.util.Vector<T> v) {
 301         return (java.util.Vector<T>)v.clone();
 302     }
 303 
 304     //----------------------------------------------------------------------
 305 
 306     private Object value;
 307     private Object source;
 308     private java.util.Vector<PropertyChangeListener> listeners;
 309 }