VariableType.java :  » UnTagged » preflect » com » ryanm » preflect » Android Open Source

Android Open Source » UnTagged » preflect 
preflect » com » ryanm » preflect » VariableType.java

package com.ryanm.preflect;

import java.util.HashMap;
import java.util.Map;

import org.json.JSONException;

import android.content.Context;
import android.preference.DialogPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.ryanm.preflect.PreflectActivity.Variable;
import com.ryanm.preflect.imp.BooleanType;
import com.ryanm.preflect.imp.ColorType;
import com.ryanm.preflect.imp.EnumType;
import com.ryanm.preflect.imp.FloatType;
import com.ryanm.preflect.imp.IntType;
import com.ryanm.preflect.imp.PointType;
import com.ryanm.preflect.imp.StringType;
import com.ryanm.preflect.imp.VoidType;

/**
 * Extend this to define new variable types. You'll need code to
 * encode an decode a value to and from strings, construct an
 * appropriate {@link Preference}, and optionally to validate/format
 * user input. Remember to {@link #register(VariableType)} your new
 * variable type or it won't be used
 * 
 * @author ryanm
 * @param <T>
 *           Type of variable to handle
 */
public abstract class VariableType<T>
{
  /**
   * Variable type
   */
  public final Class<? extends T> type;

  /**
   * @param type
   */
  protected VariableType( Class<? extends T> type )
  {
    this.type = type;
  }

  /**
   * Encodes the value of a given object
   * 
   * @param value
   *           The value to encode
   * @return The String encoding for the value, or null if encoding
   *         was not possible
   */
  public abstract String encode( T value );

  /**
   * Decodes the encoded string into a value object
   * 
   * @param encoded
   *           The encoded string
   * @param runtimeType
   *           The desired type of the object
   * @return The value of the encoded string
   * @throws ParseException
   *            If there is a problem parsing the encoded string
   */
  public abstract T decode( String encoded, Class runtimeType ) throws ParseException;

  /**
   * Gets a widget to control the supplied variable
   * 
   * @param context
   * @param var
   * @return An appropriate {@link View}
   */
  final Preference getPreference( final Context context, final Variable var )
  {
    String value = var.json.optString( Util.VALUE );
    Preference p = buildPreference( context, var.type, value );
    p.setTitle( var.name );
    p.setSummary( var.description );
    p.setOrder( var.order );
    p.setEnabled( !var.readonly );

    // we store our values in the JSON, no need for the
    // sharedPrefs
    p.setPersistent( false );

    if( p instanceof DialogPreference )
    {
      DialogPreference dp = ( DialogPreference ) p;
      dp.setDialogTitle( var.name );

      if( var.readonly )
      {
        p.setSummary( value );
      }
    }

    p.setOnPreferenceChangeListener( new OnPreferenceChangeListener() {
      @Override
      public boolean onPreferenceChange( Preference preference, Object newValue )
      {
        try
        {
          var.json.put( Util.VALUE, formatInput( newValue ) );
          return true;
        }
        catch( JSONException e )
        {
          Log.e( Preflect.LOG_TAG, "shouldn't happen", e );
        }
        catch( Exception e )
        {
          Toast.makeText( context, e.getMessage(), Toast.LENGTH_SHORT ).show();

          Log.e( Preflect.LOG_TAG, "Problem setting value", e );
        }

        return false;
      }
    } );

    return p;
  }

  /**
   * Build a widget to control the supplied variable. Variable title,
   * summary, order and a default input formatting action are handled
   * for you.
   * 
   * @see VariableType#formatInput(Object)
   * @param context
   *           Well who'd have thought it! A context!
   * @param type
   *           runtime type of the variable. Needed to get enum
   *           values, not much use otherwise
   * @param value
   *           The current value of the variable
   * @return An appropriate {@link View}
   */
  protected abstract Preference buildPreference( Context context, Class type,
      final String value );

  /**
   * Default format behaviour, just does toString(). Override if that
   * doesn't work for you. Throw an exception to indicate trouble,
   * the exception message will be {@link Toast}ed at the user
   * 
   * @param input
   *           The user input, fresh from the {@link Preference}
   *           created in
   *           {@link #buildPreference(Context, Class, String)}
   * @return A properly-formatted value that won't cause trouble on
   *         the other end
   */
  protected String formatInput( Object input )
  {
    return input.toString();
  }

  private static final Map<Class, VariableType> types =
      new HashMap<Class, VariableType>();

  static
  {
    register( new BooleanType() );
    register( new EnumType() );
    register( new FloatType() );
    register( new IntType() );
    register( new StringType() );
    register( new VoidType() );
    register( new ColorType() );
    register( new PointType() );
  }

  /**
   * Call this to register your {@link VariableType}s
   * 
   * @param varType
   */
  public static void register( VariableType varType )
  {
    types.put( varType.type, varType );
  }

  /**
   * @param type
   * @return A factory for the type
   */
  static VariableType get( Class type )
  {
    VariableType t = types.get( type );

    while( t == null && type != null )
    {
      type = type.getSuperclass();
      t = types.get( type );
    }

    return t;
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.