/**
* Copyright (C) 2009-2014 Cars and Tracks Development Project (CTDP).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package net.ctdp.rfdynhud.properties;
import java.net.URL;
import net.ctdp.rfdynhud.util.RFDHLog;
import net.ctdp.rfdynhud.util.__UtilHelper;
import org.jagatoo.util.strings.StringUtils;
/**
* The {@link Property} serves as a general data container and adapter.
* You can use it to put data into a GUI component and live update it.
*
* @author Marvin Froehlich (CTDP)
*/
public abstract class Property
{
private static DisplayNameGenerator displayNameGenerator = null;
private PropertiesKeeper keeper = null;
private final String name;
private final String nameForDisplay;
private final String nameForDisplay2;
private final boolean readonly;
private final PropertyEditorType editorType;
private final String buttonText;
private final String buttonTooltip;
Object cellRenderer = null;
Object cellEditor = null;
private static DisplayNameGenerator newDefaultDisplayNameGenerator()
{
return ( new SpacedCamelCaseDisplayNameGenerator() );
}
private static final DisplayNameGenerator getDisplayNameGenerator()
{
if ( displayNameGenerator == null )
{
String className = __UtilHelper.editorPropertyDisplayNameGeneratorClass;
if ( className == null )
{
displayNameGenerator = newDefaultDisplayNameGenerator();
return ( displayNameGenerator );
}
Class<?> clazz = null;
try
{
clazz = Class.forName( className );
}
catch ( ClassNotFoundException e )
{
displayNameGenerator = newDefaultDisplayNameGenerator();
RFDHLog.exception( "WARNING: Could not find DisplayNameGenerator Class " + className + ". Using default " + displayNameGenerator.getClass().getName() + "." );
return ( displayNameGenerator );
}
if ( !DisplayNameGenerator.class.isAssignableFrom( clazz ) )
{
displayNameGenerator = newDefaultDisplayNameGenerator();
RFDHLog.exception( "WARNING: Class defined for propertyDisplayNameGenrator in rfdynhud.ini does not implement net.ctdp.rfdynhud.properties.DisplayNameGenerator. Using default " + displayNameGenerator.getClass().getName() + "." );
return ( displayNameGenerator );
}
try
{
displayNameGenerator = (DisplayNameGenerator)clazz.newInstance();
}
catch ( InstantiationException e )
{
displayNameGenerator = newDefaultDisplayNameGenerator();
RFDHLog.exception( "WARNING: Couldn't instantiate class " + className + " through the empty constructor. Falling back to default " + displayNameGenerator.getClass().getName() + "." );
}
catch ( IllegalAccessException e )
{
displayNameGenerator = newDefaultDisplayNameGenerator();
RFDHLog.exception( "WARNING: Empty constructor is not accessible for class " + className + ". Falling back to default " + displayNameGenerator.getClass().getName() + "." );
}
}
return ( displayNameGenerator );
}
protected void onKeeperSet()
{
triggerKeepersOnPropertyChanged( null, getValue() );
}
boolean setKeeper( PropertiesKeeper keeper, boolean force )
{
if ( !force && ( keeper == this.keeper ) )
return ( false );
this.keeper = keeper;
onKeeperSet();
return ( true );
}
/**
* Gets the owner {@link PropertiesKeeper}.
*
* @return the owner {@link PropertiesKeeper}.
*/
public final PropertiesKeeper getKeeper()
{
return ( keeper );
}
/**
* Gets the property's technical name.
*
* @return the property's technical name.
*/
public final String getName()
{
return ( name );
}
/**
* Gets the property's name for editor display.
*
* @return the property's name for editor display.
*/
public String getNameForDisplay()
{
//return ( nameForDisplay );
return ( nameForDisplay2 );
}
/**
* Is read only property?
*
* @return whether this property is read only.
*/
public final boolean isReadOnly()
{
return ( readonly );
}
/**
* Gets the proeprty editor type.
*
* @return the proeprty editor type.
*/
public final PropertyEditorType getEditorType()
{
return ( editorType );
}
public String getButtonText()
{
return ( buttonText );
}
public String getButtonTooltip()
{
return ( buttonTooltip );
}
/**
* Sets the new value for this property.
*
* @param value the new value
*/
public abstract void setValue( Object value );
/**
* Gets the current value fo this property.
*
* @return the current value fo this property.
*/
public abstract Object getValue();
/**
* Gets the value to feed into the editor.
*
* @return the value to feed into the editor.
*/
public Object getValueForEditor()
{
return ( getValue() );
}
/**
* Gets the default (initial) value fo this property.
*
* @return the default value fo this property.
*/
public abstract Object getDefaultValue();
/**
* Gets, whether this property currently has its default (initial) value.
*
* @return whether this property currently has its default (initial) value.
*/
public boolean hasDefaultValue()
{
Object value = getValue();
Object defaultValue = getDefaultValue();
if ( value == null )
return ( defaultValue == null );
if ( defaultValue == null )
return ( false );
return ( value.equals( defaultValue ) );
}
void triggerKeepersOnPropertyChanged( Object oldValue, Object newValue )
{
if ( keeper != null )
keeper.onPropertyChanged( this, oldValue, newValue );
}
/**
*
* @param button the clicked button
*/
public void onButtonClicked( Object button )
{
}
/**
* Gets whether to quote this property's value in the config file (default is null, type dependent, numbers won't, others will).
*
* @return whether to quote this property's value in the config file.
*/
public Boolean quoteValueInConfigurationFile()
{
return ( null );
}
/**
* Gets the value prepared for the configuration file.
* This can be a String or some other primitive value.
*
* @return the value prepared for the configuration file.
*/
public Object getValueForConfigurationFile()
{
return ( getValue() );
}
/**
* Checks whether the given key (from the configuration file) belongs to this {@link Property}.
*
* @param key the probed property key
*
* @return whether the given key (from the configuration file) belongs to this {@link Property}.
*/
public boolean isMatchingKey( String key )
{
return ( key.equals( name ) );
}
/**
* Loads the value from the configuration file.
*
* @param loader the loader
* @param value the value to load
*/
public abstract void loadValue( PropertyLoader loader, String value );
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
Class<?> clazz = this.getClass();
//while ( clazz.getName().lastIndexOf( '$' ) >= 0 )
while ( clazz.getSimpleName().equals( "" ) )
clazz = clazz.getSuperclass();
return ( clazz.getSimpleName() + "( \"" + getName() + "\" = \"" + String.valueOf( getValue() ) + "\" )" );
}
private String getDocumentationSource( Class<?> clazz )
{
URL docURL = clazz.getClassLoader().getResource( clazz.getPackage().getName().replace( '.', '/' ) + "/doc/" + this.getName() + ".html" );
if ( docURL == null )
{
if ( ( clazz.getSuperclass() != null ) && ( clazz.getSuperclass() != Object.class ) )
return ( getDocumentationSource( clazz.getSuperclass() ) );
return ( "" );
}
return ( StringUtils.loadString( docURL ) );
}
/**
* Loads documentation for this {@link Property} from a "e;doc"e; folder under the keeper's package.
*
* @return the documentation.
*/
public String getDocumentationSource()
{
if ( keeper == null )
return ( "" );
return ( getDocumentationSource( keeper.getClass() ) );
}
/**
*
* @param name the property name
* @param nameForDisplay the name for editor display (<code>null</code> to use name)
* @param readonly read only property?
* @param editorType the property editor type
* @param buttonText the text for the button (may be <code>null</code>)
* @param buttonTooltip the tooltip for the button (ignored when button text is <code>null</code>)
*/
protected Property( String name, String nameForDisplay, boolean readonly, PropertyEditorType editorType, String buttonText, String buttonTooltip )
{
this.name = name;
this.nameForDisplay = ( nameForDisplay == null ) ? name : nameForDisplay;
this.nameForDisplay2 = getDisplayNameGenerator().generateNameForDisplay( this.nameForDisplay );
this.readonly = readonly;
this.editorType = editorType;
this.buttonText = buttonText;
this.buttonTooltip = buttonTooltip;
}
/**
*
* @param name the technical name used internally. See {@link #getName()}.
* @param nameForDisplay the name displayed in the editor. See {@link #getNameForDisplay()}. If <code>null</code> is passed, the value of the name parameter is used.
* @param readonly read only property?
* @param editorType the property editor type
*/
public Property( String name, String nameForDisplay, boolean readonly, PropertyEditorType editorType )
{
this( name, nameForDisplay, readonly, editorType, null, null );
}
/**
*
* @param name the technical name used internally. See {@link #getName()}.
* @param nameForDisplay the name displayed in the editor. See {@link #getNameForDisplay()}. If <code>null</code> is passed, the value of the name parameter is used.
* @param editorType the property editor type
*/
public Property( String name, String nameForDisplay, PropertyEditorType editorType )
{
this( name, nameForDisplay, false, editorType, null, null );
}
/**
*
* @param name the technical name used internally. See {@link #getName()}.
* @param readonly read only property?
* @param editorType the property editor type
* @param buttonText the text for the button (may be <code>null</code>)
* @param buttonTooltip the tooltip for the button (ignored when button text is <code>null</code>)
*/
public Property( String name, boolean readonly, PropertyEditorType editorType, String buttonText, String buttonTooltip )
{
this( name, null, readonly, editorType, buttonText, buttonTooltip );
}
/**
*
* @param name the technical name used internally. See {@link #getName()}.
* @param readonly read only property?
* @param editorType the property editor type
*/
public Property( String name, boolean readonly, PropertyEditorType editorType )
{
this( name, readonly, editorType, null, null );
}
/**
*
* @param name the technical name used internally. See {@link #getName()}.
* @param editorType the property editor type
*/
public Property( String name, PropertyEditorType editorType )
{
this( name, false, editorType, null, null );
}
}