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