All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codename1.properties.PropertyBase Maven / Gradle / Ivy

There is a newer version: 7.0.164
Show newest version
/*
 * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Codename One designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *  
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 * 
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 * Please contact Codename One through http://www.codenameone.com/ if you 
 * need additional information or have any questions.
 */

package com.codename1.properties;

import java.util.ArrayList;
import java.util.List;

/**
 * Base class for property types
 *
 * @author Shai Almog
 */
public class PropertyBase {
    private final String name;
    private Class genericType;
    private ArrayList> listeners;
    PropertyIndex parent;
    private static PropertyChangeListener lastChangeListener;

    /**
     * Used internally to detect if a property was read by a user
     */
    static PropertyChangeListener onGlobalGetProperty;

    /**
     * Used internally to detect if a property was modified by a user
     */
    static PropertyChangeListener onGlobalSetProperty;

    /**
     * All properties must have a name
     * @param name the name of the property
     */
    protected PropertyBase(String name) {
        this.name = name;
    }

    
    /**
     * Provides the internal list of listeners
     * @return internal list of listeners
     */
    List> getListeners() {
        return listeners;
    }

    void internalGet() {
        if(onGlobalGetProperty != null) {
            onGlobalGetProperty.propertyChanged(this);
        }
    }

    void internalSet() {
        if(onGlobalSetProperty != null) {
            onGlobalSetProperty.propertyChanged(this);
        }
    }


    /**
     * Binds an event callback for set calls and property mutation
     * @param listener will be invoked whenever any mutable property is changed
     * @throws RuntimeException if a set listener is already bound, there can be only one per application
     * @deprecated Usage of this method isn't recommended, it's designed for internal use
     */
    public static void bindGlobalSetListener(PropertyChangeListener listener) {
        if (onGlobalSetProperty != null && listener != null) {
            throw new RuntimeException("Set Listener already bound");
        }
        onGlobalSetProperty = listener;
    }

    /**
     * Binds an event callback for get calls and property reads
     * @param listener will be invoked whenever any property is read
     * @throws RuntimeException if a get listener is already bound, there can be only one per application
     * @deprecated Usage of this method isn't recommended, it's designed for internal use
     */
    public static void bindGlobalGetListener(PropertyChangeListener listener) {
        if (onGlobalGetProperty != null && listener != null) {
            throw new RuntimeException("Get Listener already bound");
        }
        onGlobalGetProperty = listener;
    }

    /**
     * All properties must have a name, a generic type is helpful
     * @param name the name of the property
     * @param genericType the property type to workaround issues with erasure
     */
    protected PropertyBase(String name, Class genericType) {
        this.name = name;
        this.genericType = genericType;
    }
        
    /**
     * The property name is immutable and can't be changed after creation it should match the parent field name by convention
     * @return the property name;
     */
    public String getName() {
        return name;
    }

    /**
     * Delivers the property change event to listeners if applicable
     */
    protected void firePropertyChanged() {
        if(listeners != null) {
            for(PropertyChangeListener pl : listeners) {
                lastChangeListener = pl;
                pl.propertyChanged(this);
                lastChangeListener = null;
            }
        }
    }

    /**
     * This method will work when invoked from a propertyChanged callback and should be similar to 
     * {@code removePropertyChangeListener(this)}. It's useful for lambda's where {@code this} 
     * means the base class and not the listener so {@code removePropertyChangeListener(this)} 
     * won't do what we want unless we convert to an inner class
     */
    public void stopListening() {
        removeChangeListener(lastChangeListener);
    }
    
    /**
     * Fires a notification that a property value changed to the given listener
     * @param pl the listener
     */
    public void addChangeListener(PropertyChangeListener pl) {
        if(listeners == null) {
            listeners = new ArrayList>();
        }
        listeners.add(pl);
    }
    
    /**
     * Removes the property change listener from the list of listeners
     * @param pl the change listener
     */
    public void removeChangeListener(PropertyChangeListener pl) {
        if(listeners != null) {
            listeners.remove(pl);
            if(listeners.size() == 0) {
                listeners = null;
            }
        }
    }

    /**
     * Places a property that will apply statically to all instances of this property
     * @param key the key to put
     * @param o the value object
     */
    public void putClientProperty(String key, Object o) {
        parent.putMetaDataOfClass("cn1$field" + name + "-" + key, o);
    }
    
    /**
     * Returns the client property set to this property name
     * @param key the key of the property
     * @return the value that was previously placed with put client property
     */
    public Object getClientProperty(String key) {
        return parent.getMetaDataOfClass("cn1$field" + name + "-" + key);
    }

    /**
     * Compares this property to another property
     * @param obj the other property
     * @return true if they are equal in name and value
     */
    @Override
    public boolean equals(Object obj) {
        if(obj != null && obj.getClass() == getClass()) {
            PropertyBase other = (PropertyBase)obj;
            if(other.getName().equals(name)) {
                return true;
            }
        }
        return false;
    }

    T get() {
        return null;
    }
    
    void setImpl(Object val) {
    }
    
    /**
     * Default toString that provides easier debug information
     * @return a formatted representation of the property for debugging
     */
    public String toString() {
        T o = get();
        if(o == null) {
            return getName() + " = null";
        }
        return getName() + " = '" + o + "' : " +o.getClass().getName();
    }
    
    /**
     * Returns the generic type of this property if it is known or null
     * @return the generic type
     */
    public Class getGenericType() {
        return genericType;
    }
    
    /**
     * The label of the property defaults to its name but can be changed to anything, it can be used
     * when binding a property to UI elements
     * @param label the new label value
     */
    public void setLabel(String label) {
        putClientProperty("cn1PropertyLabel", label);
    }
    
    /**
     * The label of the property defaults to its name but can be changed to anything
     * 
     * @return the label for the property
     */
    public String getLabel() {
        String l = (String)getClientProperty("cn1PropertyLabel");
        if(l == null) {
            return getName();
        }
        return l;
    }

    /**
     * Validates that the collection type is valid and throws an exception otherwise
     * @param elementType the generic type of the collection
     */
    protected final void validateCollectionType(Class elementType) {
        if(elementType == null || !PropertyBusinessObject.class.isAssignableFrom(elementType)) {
            if(elementType == String.class || elementType == Integer.class ||
                elementType == Long.class  || elementType == Double.class ||
                elementType == Byte.class  || elementType == Float.class ||
                elementType == Boolean.class  || elementType == Character.class) {
                return;
            }
            throw new IllegalArgumentException(
                    "the element type class needs to be a subclass of PropertyBusinessObject");
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy