/**
* This file Copyright (c) 2005-2008 Aptana, Inc. This program is
* dual-licensed under both the Aptana Public License and the GNU General
* Public license. You may elect to use one or the other of these licenses.
*
* This program is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. Redistribution, except as permitted by whichever of
* the GPL or APL you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or modify this
* program under the terms of the GNU General Public License,
* Version 3, as published by the Free Software Foundation. You should
* have received a copy of the GNU General Public License, Version 3 along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Aptana provides a special exception to allow redistribution of this file
* with certain other free and open source software ("FOSS") code and certain additional terms
* pursuant to Section 7 of the GPL. You may view the exception and these
* terms on the web at http://www.aptana.com/legal/gpl/.
*
* 2. For the Aptana Public License (APL), this program and the
* accompanying materials are made available under the terms of the APL
* v1.0 which accompanies this distribution, and is available at
* http://www.aptana.com/legal/apl/.
*
* You may view the GPL, Aptana's exception and additional terms, and the
* APL in the file titled license.html at the root of the corresponding
* plugin containing this source file.
*
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.ide.editors.views.outline.propertyManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.ArrayList;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.ui.views.properties.PropertyDescriptor;
/**
* @author Dan Phifer The ReadableProperty class provides read-only support for Properties. It is used in conjuction
* with the PropertyManager class which allows easy integration with the built-in Eclipse Properties View.
*
* <pre>
* + ReadableProperty // read-only support
* +--+ EditableProperty // Text editable
* +--+--- EditableBooleanProperty
* +--- EditableComboProperty // Drop down box
* +--- EditableIntegerProperty (INumericProperty) // Integer Editable
* +--- EditableFloatProperty (INumericProperty) // Float Editable
* </pre>
*/
public class ReadableProperty implements Serializable
{
/**
* serialVersionUID
*/
private static final long serialVersionUID = 1L;
/**
* A unique ID for this property
*/
private String ID;
/**
* A human-readable String to be shown to the user
*/
private String name;
/**
* The underlying default value. The underlying value is passed between the PropertyManager and the Properties View,
* while the value is passed between the PropertiesManager and the client. This avoids rewriting code that
* translates the String value needed by the Properties view and the value needed by the client. For instance, if
* the client wants to expose a Float property, the client class should not have to worry about translating from
* String to Float and vice versa. Therefore, the EditableFloatProperty handles this translation behind the scenes,
* and the client can be ignorant of any translation that needs to take place.
*/
protected Object defaultValue;
/**
* the current underlying value
*/
protected Object value;
/**
* The category of this property. Categories can be used to organize properties in the PropertiesView if sorting
* them alphabetically is not managable
*/
private String category;
private LabelProvider labelProvider = null;
private PropertyManager subProperites = null;
private ArrayList propertyChangeListeners;
private PropertyChangeListener subPropertyListener;
/**
* @param ID
* The unique ID to be used for this property.
* @param name
* The name to be displayed to the user
*/
public ReadableProperty(String ID, String name)
{
this.ID = ID;
this.name = name;
propertyChangeListeners = new ArrayList();
}
/**
* @return By default, the default underlying value is returned.
*/
public Object getDefaultValue()
{
return getUnderlyingDefaultValue();
}
/**
* @return The underlying default value. This is the value that should be ultimately returned to the properties
* view.
*/
public Object getUnderlyingDefaultValue()
{
return defaultValue;
}
/**
* Sets the value of the EditableProperty and fires the PropertyChange event
*
* @param newValue
* The new PropertyValue
*/
public void setUnderlyingValue(Object newValue)
{
value = newValue;
}
/**
* setValue
*
* @param newValue
*/
public void setValue(Object newValue)
{
setUnderlyingValue(newValue);
}
/**
* Unless overidden by a subclass, this is equivalent to the setUnderlyingDefaultValue. Subclasses may overide this
* method if they need to proprocess (or translate) the value before setting the underlying default value, which the
* Properties view will ultimately work with.
*
* @param defaultValue
* The new default value.
*/
public void setDefaultValue(Object defaultValue)
{
setUnderlyingDefaultValue(defaultValue);
}
/**
* Sets the underlying default value. No translation occurs before setting the value
*
* @see #setDefaultValue(Object defaultValue)
* @param defaultValue
* The new underlying default value
*/
public void setUnderlyingDefaultValue(Object defaultValue)
{
this.defaultValue = defaultValue;
}
/**
* @return the unique ID of the object.
*/
public String getID()
{
return ID;
}
/**
* @return The name of the object. The name is displayed to the user
*/
public String getName()
{
return name;
}
/**
* @return By default, the ReadableProperty class returns the underlying value
*/
public Object getValue()
{
return getUnderlyingValue();
}
/**
* @return The underlying value. For readable properties, the underlying value is the same as the value. However,
* when dealing with Custom types, it is more convenient for the getValue function to return an object of
* the correct type, rather than a string which must be parsed. Or, in the case of a combo property, the
* value associated with the item selected, instead of the index of the item (which is what the Properties
* view returns).
*/
protected Object getUnderlyingValue()
{
if (value != null)
{
return value;
}
else
{
return getUnderlyingDefaultValue();
}
}
/**
* Sets the category of this property. In the properties view, the user can choose to see the properties by
* category, or alphabetically.
*
* @param category
* The category ID (and description)
*/
public void setCategory(String category)
{
this.category = category;
}
/**
* Sets the lable provider for this property. This allows for a custom text be shown in the properties view
*
* @param provider
*/
public void setLabelProvider(LabelProvider provider)
{
this.labelProvider = provider;
}
/**
* @return true if the value is anything other than null
*/
public boolean hasValue()
{
return value != null;
}
/**
* @return true if the defaultValue is anything other than null
*/
public boolean hasDefaultValue()
{
return defaultValue != null;
}
/**
* @return the property descriptor to be used by this property. This method cannot be overidden. Instead, overide
* the hook method getCustomPropertyDescriptor
*/
public final PropertyDescriptor getPropertyDescriptor()
{
PropertyDescriptor propertyDescriptor = getCustomPropertyDescriptor();
if (this.category != null)
{
propertyDescriptor.setCategory(this.category);
}
if (this.labelProvider != null)
{
propertyDescriptor.setLabelProvider(labelProvider);
}
return propertyDescriptor;
}
/**
* This method can be overridden by suclasses. The default implementation returns a read-only PropertyDescriptor.
*
* @return the property descriptor to be used for this property
*/
public PropertyDescriptor getCustomPropertyDescriptor()
{
return getReadOnlyPropertyDescriptor();
}
/**
* @return A PropertyDescriptor that allows the user to see the value, but not edit it. Subclasses of
* PropertyDescriptor allow editing.
*/
private PropertyDescriptor getReadOnlyPropertyDescriptor()
{
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(getID(), getName());
return propertyDescriptor;
}
/**
* @return true if the property descriptor can change. Mainly, this is for combo property object, so that the items
* in the list can be dynamic. Other types of descriptors do not contain information that is data dependent
*/
public boolean hasDynamicPropertyDescriptor()
{
return false;
}
/**
* hasSubProperties
*
* @return boolean
*/
public boolean hasSubProperties()
{
return subProperites != null;
}
/**
* getSubPropertyManager
*
* @return Object
*/
public Object getSubPropertyManager()
{
return subProperites;
}
/**
* @param propertyManager
*/
public void setSubPropertyManager(PropertyManager propertyManager)
{
if (subProperites != null)
{
subProperites.removePropertyChangeListener(getSubPropertyListener());
}
subProperites = propertyManager;
if (subProperites != null)
{
subProperites.addPropertyChangeListener(getSubPropertyListener());
}
}
/**
* @return A property change listener that will simply pass events up to the higher level property manager
*/
private PropertyChangeListener getSubPropertyListener()
{
if (subPropertyListener == null)
{
subPropertyListener = new SubPropertyChangeListener()
{
private static final long serialVersionUID = -3330992827410094475L;
public void propertyChange(PropertyChangeEvent evt)
{
notifyPropertyChangeListeners(evt);
}
};
}
return subPropertyListener;
}
/**
* addPropertyChangeListener
*
* @param listener
*/
public void addPropertyChangeListener(PropertyChangeListener listener)
{
propertyChangeListeners.add(listener);
}
/**
* removePropertyChangeListener
*
* @param listener
*/
public void removePropertyChangeListener(PropertyChangeListener listener)
{
propertyChangeListeners.remove(listener);
}
/**
* Notify the propertChangeListeners that this property has changed
*
* @param event
*/
protected void notifyPropertyChangeListeners(PropertyChangeEvent event)
{
PropertyChangeListener l;
for (int i = 0; i < propertyChangeListeners.size(); i++)
{
l = (PropertyChangeListener) propertyChangeListeners.get(i);
l.propertyChange(event);
}
}
/**
* SubPropertyChangeListener
*
* @author Ingo Muschenetz
*/
class SubPropertyChangeListener implements PropertyChangeListener, Serializable
{
/**
* serialVersionUID
*/
private static final long serialVersionUID = -351877929766054322L;
/**
* @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent evt)
{
notifyPropertyChangeListeners(evt);
}
}
}