controlp5/src/controlP5/ControllerAutomator.java

355 lines
11 KiB
Java
Executable File

package controlP5;
/**
* controlP5 is a processing gui library.
*
* 2006-2015 by Andreas Schlegel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*
* @author Andreas Schlegel (http://www.sojamo.de)
* @modified ##date##
* @version ##version##
*
*/
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* Used to convert Annotations into individual controllers this method of creating controllers is
* derived from cp5magic by Karsten Schmidt http://hg.postspectacular.com/cp5magic/wiki/Home
*/
class ControllerAutomator {
static Map< Set< Class< ? >> , Class< ? extends Controller< ? >>> mapping = new HashMap< Set< Class< ? >> , Class< ? extends Controller< ? >>>( );
static {
mapping.put( makeKey( boolean.class ) , Toggle.class );
mapping.put( makeKey( int.class ) , Slider.class );
mapping.put( makeKey( float.class ) , Slider.class );
mapping.put( makeKey( String.class ) , Textfield.class );
}
static Map< String , Class< ? extends ControllerInterface< ? >>> types = new HashMap< String , Class< ? extends ControllerInterface< ? >>>( );
static {
types.put( "slider" , Slider.class );
types.put( "knob" , Knob.class );
types.put( "numberbox" , Numberbox.class );
types.put( "toggle" , Toggle.class );
types.put( "bang" , Bang.class );
types.put( "toggle" , Toggle.class );
types.put( "textfield" , Textfield.class );
types.put( "label" , Textlabel.class );
types.put( "textlabel" , Textlabel.class );
types.put( "list" , ListBox.class );
types.put( "dropdown" , DropdownList.class );
types.put( "scrollable" , ScrollableList.class );
}
static Set< Class< ? >> makeKey( Class< ? > ... cs ) {
Set< Class< ? >> set = new HashSet< Class< ? >>( );
for ( Class< ? > c : cs ) {
set.add( c );
}
return set;
}
private ControlP5 cp5;
ControllerAutomator( ControlP5 c ) {
cp5 = c;
}
private Object[] getParameters( Class< ? >[] cs , String v ) {
if ( cs[ 0 ] == int.class ) {
return new Object[] { i( v , 0 ) };
} else if ( cs[ 0 ] == float.class ) {
return new Object[] { Float.parseFloat( v ) };
} else if ( cs[ 0 ] == String.class ) {
return new Object[] { v };
} else if ( cs[ 0 ] == boolean.class ) {
return new Object[] { Boolean.parseBoolean( v ) };
}
return new Object[ 0 ];
}
/**
* analyzes an object and adds fields with ControlElement annotations to controlP5.
*
*/
void addControllersFor( final String theAddressSpace , final Object t ) {
System.out.println("OKOK");
if ( t instanceof List< ? > ) {
return;
}
Class< ? > c = t.getClass( );
Field[] fs = c.getFields( );
Method[] ms = c.getMethods( );
Map< ControllerInterface , Integer > controllersIndexed = new HashMap< ControllerInterface , Integer >( );
for ( Method m : ms ) {
int zindex = 0;
if ( m.isAnnotationPresent( ControlElement.class ) ) {
ControlElement ce = m.getAnnotation( ControlElement.class );
Map< String , String > params = new HashMap< String , String >( );
Class< ? extends ControllerInterface< ? >> type = null;
for ( String s : ce.properties( ) ) {
String[] a = s.split( "=" );
if ( a[ 0 ].startsWith( "type" ) ) {
type = types.get( a[ 1 ].toLowerCase( ) );
} else if ( a[ 0 ].equals( "z-index" ) ) {
zindex = i( a[ 1 ] , 0 );
} else {
params.put( "set" + capitalize( a[ 0 ] ) , a[ 1 ] );
}
}
if ( type == null ) {
type = mapping.get( makeKey( m.getParameterTypes( ) ) );
}
if ( type != null ) {
ControllerInterface< ? > cntr = null;
if ( params.containsKey( "setItems" ) ) {
if ( type.equals( ListBox.class ) ) {
cntr = cp5.addScrollableList( t , theAddressSpace , m.getName( ) , ce.x( ) , ce.y( ) , 100 , 100 );
( ( ScrollableList ) cntr ).addItems( params.get( "setItems" ).split( "," ) );
( ( ScrollableList ) cntr ).setOpen( true );
( ( ScrollableList ) cntr ).setType(ScrollableList.LIST);
} else if ( type.equals( DropdownList.class ) ) {
cntr = cp5.addScrollableList( t , theAddressSpace , m.getName( ) , ce.x( ) , ce.y( ) , 100 , 100 );
( ( ScrollableList ) cntr ).addItems( params.get( "setItems" ).split( "," ) );
( ( ScrollableList ) cntr ).setOpen( false );
( ( ScrollableList ) cntr ).setType(ScrollableList.DROPDOWN);
} else if ( type.equals( ScrollableList.class ) ) {
cntr = cp5.addScrollableList( t , theAddressSpace , m.getName( ) , ce.x( ) , ce.y( ) , 100 , 100 );
( ( ScrollableList ) cntr ).addItems( params.get( "setItems" ).split( "," ) );
}
} else {
cntr = cp5.addController( t , theAddressSpace , m.getName( ) , type , ce.x( ) , ce.y( ) );
}
controllersIndexed.put( cntr , zindex );
if ( ce.label( ).length( ) > 0 ) {
cntr.setCaptionLabel( ce.label( ) );
}
for ( Iterator< String > i = params.keySet( ).iterator( ) ; i.hasNext( ) ; ) {
String k = ( String ) i.next( );
String v = ( String ) params.get( k );
for ( Method method : cntr.getClass( ).getMethods( ) ) {
if ( method.getName( ).equals( k ) ) {
try {
Object[] os = getParameters( method.getParameterTypes( ) , v );
method.setAccessible( true );
method.invoke( cntr , os );
} catch ( Exception e ) {
/* TODO is thrown when running ControlP5annotation example */
// ControlP5.logger.severe( e.toString( ) );
}
}
}
}
}
}
}
for ( Field f : fs ) {
int zindex = 0;
if ( f.isAnnotationPresent( ControlElement.class ) ) {
ControlElement ce = f.getAnnotation( ControlElement.class );
Map< String , String > params = new HashMap< String , String >( );
Class< ? extends ControllerInterface< ? >> type = null;
for ( String s : ce.properties( ) ) {
String[] a = s.split( "=" );
if ( a[ 0 ].startsWith( "type" ) ) {
type = types.get( a[ 1 ].toLowerCase( ) );
} else if ( a[ 0 ].equals( "z-index" ) ) {
zindex = i( a[ 1 ] , 0 );
} else {
params.put( "set" + capitalize( a[ 0 ] ) , a[ 1 ] );
}
}
ControllerInterface< ? > cntr = null;
f.setAccessible( true );
if ( f.getType( ) == float.class || f.getType( ) == int.class ) {
if ( type == Knob.class ) {
cntr = cp5.addKnob( t , theAddressSpace , f.getName( ) );
} else if ( type == Numberbox.class ) {
cntr = cp5.addNumberbox( t , theAddressSpace , f.getName( ) );
} else {
cntr = cp5.addSlider( t , theAddressSpace , f.getName( ) );
}
try {
if ( f.getType( ) == float.class ) {
cntr.setValue( f.getFloat( t ) );
} else {
cntr.setValue( f.getInt( t ) );
}
} catch ( Exception e ) {
ControlP5.logger.severe( e.toString( ) );
}
} else if ( f.getType( ) == String.class ) {
if ( type == Textlabel.class ) {
String s = "";
try {
s = "" + f.get( t );
if ( f.get( t ) == null ) {
s = ce.label( );
}
} catch ( Exception e ) {
}
cntr = cp5.addTextlabel( t , theAddressSpace , f.getName( ) , s );
} else {
cntr = cp5.addTextfield( t , theAddressSpace , f.getName( ) );
}
} else if ( f.getType( ) == boolean.class ) {
cntr = cp5.addToggle( t , theAddressSpace , f.getName( ) );
try {
cntr.setValue( f.getBoolean( t ) ? 1 : 0 );
} catch ( Exception e ) {
ControlP5.logger.severe( e.toString( ) );
}
}
if ( cntr != null ) {
controllersIndexed.put( cntr , zindex );
if ( ce.label( ).length( ) > 0 ) {
cntr.setCaptionLabel( ce.label( ) );
}
cntr.setPosition( ce.x( ) , ce.y( ) );
for ( Iterator< String > i = params.keySet( ).iterator( ) ; i.hasNext( ) ; ) {
String k = ( String ) i.next( );
String v = ( String ) params.get( k );
for ( Method method : cntr.getClass( ).getMethods( ) ) {
if ( method.getName( ).equals( k ) ) {
try {
Object[] os = getParameters( method.getParameterTypes( ) , v );
method.setAccessible( true );
method.invoke( cntr , os );
} catch ( Exception e ) {
ControlP5.logger.severe( e.toString( ) );
}
}
}
}
}
}
}
/* */
for ( Entry< ControllerInterface , Integer > entry : entriesSortedByValues( controllersIndexed ) ) {
entry.getKey( ).bringToFront( );
}
}
private static < K , V extends Comparable< ? super V >> List< Entry< K , V >> entriesSortedByValues( Map< K , V > map ) {
List< Entry< K , V >> sortedEntries = new ArrayList< Entry< K , V >>( map.entrySet( ) );
Collections.sort( sortedEntries , new Comparator< Entry< K , V >>( ) {
@Override
public int compare( Entry< K , V > e1 , Entry< K , V > e2 ) {
return e1.getValue( ).compareTo( e2.getValue( ) );
}
} );
return sortedEntries;
}
/**
* capitalizes a string.
*
* @param theString
* @return String
*/
static String capitalize( String theString ) {
final StringBuilder result = new StringBuilder( theString.length( ) );
String[] words = theString.split( "\\s" );
for ( int i = 0 , l = words.length ; i < l ; ++i ) {
if ( i > 0 )
result.append( " " );
result.append( Character.toUpperCase( words[ i ].charAt( 0 ) ) ).append( words[ i ].substring( 1 ) );
}
return result.toString( );
}
private int i( String o , int theDefault ) {
return isNumeric( o ) ? Integer.parseInt( o ) : isHex( o ) ? o.length( ) == 6 ? ( int ) Long.parseLong( "FF" + o , 16 ) : ( int ) Long.parseLong( o , 16 ) : theDefault;
}
private boolean isNumeric( String str ) {
return str.matches( "(-|\\+)?\\d+(\\.\\d+)?" );
}
private boolean isHex( String str ) {
// (?:0[xX])?[0-9a-fA-F]+ (This will match with or without 0x prefix)
// System.out.println( "isHex? " + str + " " + str.matches( "[\\dA-Fa-f]+" ) );
return str.matches( "[\\dA-Fa-f]+" );
}
}