2014-07-22 08:12:30 +02:00
package controlP5 ;
/ * *
* controlP5 is a processing gui library .
2014-09-08 09:30:57 +02:00
*
* 2006 - 2012 by Andreas Schlegel
*
2014-07-22 08:12:30 +02:00
* 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 .
2014-09-08 09:30:57 +02:00
*
2014-07-22 08:12:30 +02:00
* 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
2014-09-08 09:30:57 +02:00
*
* @author Andreas Schlegel ( http : //www.sojamo.de)
* @modified # # date # #
* @version # # version # #
*
2014-07-22 08:12:30 +02:00
* /
import java.lang.reflect.Field ;
import java.lang.reflect.InvocationTargetException ;
import java.lang.reflect.Method ;
import java.util.AbstractMap.SimpleEntry ;
import java.util.ArrayList ;
import java.util.HashMap ;
import java.util.HashSet ;
import java.util.Map ;
import java.util.Map.Entry ;
import java.util.Set ;
/ * *
* The ControlBroadcaster handles all controller value changes and distributes them accordingly to
* its listeners . The ControlBroadcaster is primarily for internal use only but can be accessed
* through an instance of the ControlP5 class . Instead of accessing the ControlBroadcaster directly ,
* use the convenience methods available from the ControlP5 class .
*
* @see controlP5 . ControlP5 # getControlBroadcaster ( )
* /
public class ControlBroadcaster {
private int _myControlEventType = ControlP5Constants . INVALID ;
private ControllerPlug _myControlEventPlug = null ;
private ControllerPlug _myControllerCallbackEventPlug = null ;
private ControlP5 cp5 ;
private String _myEventMethod = " controlEvent " ;
private String _myControllerCallbackEventMethod = " controlEvent " ;
private ArrayList < ControlListener > _myControlListeners ;
private Set < Entry < CallbackListener , Controller < ? > > > _myControllerCallbackListeners ;
private static boolean setPrintStackTrace = true ;
private static boolean ignoreErrorMessage = false ;
private static Map < Class < ? > , Field [ ] > fieldcache = new HashMap < Class < ? > , Field [ ] > ( ) ;
private static Map < Class < ? > , Method [ ] > methodcache = new HashMap < Class < ? > , Method [ ] > ( ) ;
boolean broadcast = true ;
protected ControlBroadcaster ( ControlP5 theControlP5 ) {
cp5 = theControlP5 ;
_myControlListeners = new ArrayList < ControlListener > ( ) ;
_myControllerCallbackListeners = new HashSet < Entry < CallbackListener , Controller < ? > > > ( ) ;
_myControlEventPlug = checkObject ( cp5 . papplet , getEventMethod ( ) , new Class [ ] { ControlEvent . class } ) ;
_myControllerCallbackEventPlug = checkObject ( cp5 . papplet , _myControllerCallbackEventMethod , new Class [ ] { CallbackEvent . class } ) ;
if ( _myControlEventPlug ! = null ) {
_myControlEventType = ControlP5Constants . METHOD ;
}
}
public ControlBroadcaster addListener ( ControlListener . . . theListeners ) {
for ( ControlListener l : theListeners ) {
_myControlListeners . add ( l ) ;
}
return this ;
}
public ControlBroadcaster removeListener ( ControlListener . . . theListeners ) {
for ( ControlListener l : theListeners ) {
_myControlListeners . remove ( l ) ;
}
return this ;
}
/ * *
* Returns a ControlListener by index
*
* @param theIndex
* @return
* /
public ControlListener getListener ( int theIndex ) {
if ( theIndex < 0 | | theIndex > = _myControlListeners . size ( ) ) {
return null ;
}
return _myControlListeners . get ( theIndex ) ;
}
/ * *
* Returns the size of the ControlListener list
*
* @return
* /
public int listenerSize ( ) {
return _myControlListeners . size ( ) ;
}
public ControlBroadcaster addCallback ( CallbackListener . . . theListeners ) {
for ( CallbackListener l : theListeners ) {
_myControllerCallbackListeners . add ( new SimpleEntry < CallbackListener , Controller < ? > > ( l , new EmptyController ( ) ) ) ;
}
return this ;
}
public ControlBroadcaster addCallback ( CallbackListener theListener ) {
_myControllerCallbackListeners . add ( new SimpleEntry < CallbackListener , Controller < ? > > ( theListener , new EmptyController ( ) ) ) ;
return this ;
}
/ * *
* Adds a CallbackListener for a list of controllers .
*
* @param theListener
* @param theController
* /
public void addCallback ( CallbackListener theListener , Controller < ? > . . . theController ) {
for ( Controller < ? > c : theController ) {
_myControllerCallbackListeners . add ( new SimpleEntry < CallbackListener , Controller < ? > > ( theListener , c ) ) ;
}
}
public ControlBroadcaster removeCallback ( CallbackListener . . . theListeners ) {
for ( CallbackListener c : theListeners ) {
_myControllerCallbackListeners . remove ( c ) ;
}
return this ;
}
public ControlBroadcaster removeCallback ( CallbackListener theListener ) {
_myControllerCallbackListeners . remove ( theListener ) ;
return this ;
}
/ * *
* Removes a CallbackListener for a particular controller
*
* @param theController
* /
public ControlBroadcaster removeCallback ( Controller < ? > . . . theControllers ) {
for ( Controller < ? > c : theControllers ) {
for ( Entry < CallbackListener , Controller < ? > > entry : _myControllerCallbackListeners ) {
if ( c ! = null & & entry . getValue ( ) . equals ( c ) ) {
_myControllerCallbackListeners . remove ( entry ) ;
}
}
}
return this ;
}
public ControlBroadcaster plug ( Object theObject , final String theControllerName , final String theTargetMethod ) {
plug ( theObject , cp5 . getController ( theControllerName ) , theTargetMethod ) ;
return this ;
}
public ControlBroadcaster plug ( Object theObject , final Controller < ? > theController , final String theTargetMethod ) {
if ( theController ! = null ) {
ControllerPlug myControllerPlug = checkObject ( theObject , theTargetMethod , ControlP5Constants . acceptClassList ) ;
if ( myControllerPlug = = null ) {
return this ;
} else {
if ( theController . checkControllerPlug ( myControllerPlug ) = = false ) {
theController . addControllerPlug ( myControllerPlug ) ;
}
return this ;
}
}
return this ;
}
static Field [ ] getFieldsFor ( Class < ? > theClass ) {
if ( ! fieldcache . containsKey ( theClass ) ) {
fieldcache . put ( theClass , theClass . getDeclaredFields ( ) ) ;
}
return fieldcache . get ( theClass ) ;
}
static Method [ ] getMethodFor ( Class < ? > theClass ) {
if ( ! methodcache . containsKey ( theClass ) ) {
methodcache . put ( theClass , theClass . getMethods ( ) ) ;
}
return methodcache . get ( theClass ) ;
}
protected static ControllerPlug checkObject ( final Object theObject , final String theTargetName , final Class < ? > [ ] theAcceptClassList ) {
Class < ? > myClass = theObject . getClass ( ) ;
Method [ ] myMethods = getMethodFor ( myClass ) ;
for ( int i = 0 ; i < myMethods . length ; i + + ) {
if ( ( myMethods [ i ] . getName ( ) ) . equals ( theTargetName ) ) {
if ( myMethods [ i ] . getParameterTypes ( ) . length = = 1 ) {
// hack to detect controlEvent(CallbackEvent) which is otherwise
// overwritten by controlEvent(ControlEvent)
if ( theAcceptClassList . length = = 1 ) {
if ( theAcceptClassList [ 0 ] = = CallbackEvent . class ) {
ControllerPlug cp = new ControllerPlug ( CallbackEvent . class , theObject , theTargetName , ControlP5Constants . EVENT , - 1 ) ;
if ( cp . getMethod ( ) = = null ) {
return null ;
}
return cp ;
}
}
if ( myMethods [ i ] . getParameterTypes ( ) [ 0 ] = = ControlP5Constants . controlEventClass ) {
return new ControllerPlug ( ControlEvent . class , theObject , theTargetName , ControlP5Constants . EVENT , - 1 ) ;
}
for ( int j = 0 ; j < theAcceptClassList . length ; j + + ) {
if ( myMethods [ i ] . getParameterTypes ( ) [ 0 ] = = theAcceptClassList [ j ] ) {
return new ControllerPlug ( theObject , theTargetName , ControlP5Constants . METHOD , j , theAcceptClassList ) ;
}
}
} else if ( myMethods [ i ] . getParameterTypes ( ) . length = = 0 ) {
return new ControllerPlug ( theObject , theTargetName , ControlP5Constants . METHOD , - 1 , theAcceptClassList ) ;
}
break ;
}
}
Field [ ] myFields = getFieldsFor ( myClass ) ;
for ( int i = 0 ; i < myFields . length ; i + + ) {
if ( ( myFields [ i ] . getName ( ) ) . equals ( theTargetName ) ) {
for ( int j = 0 ; j < theAcceptClassList . length ; j + + ) {
if ( myFields [ i ] . getType ( ) = = theAcceptClassList [ j ] ) {
return new ControllerPlug ( theObject , theTargetName , ControlP5Constants . FIELD , j , theAcceptClassList ) ;
}
}
break ;
}
}
return null ;
}
public ControlBroadcaster broadcast ( final ControlEvent theControlEvent , final int theType ) {
if ( broadcast ) {
for ( ControlListener cl : _myControlListeners ) {
cl . controlEvent ( theControlEvent ) ;
}
if ( ! theControlEvent . isTab ( ) & & ! theControlEvent . isGroup ( ) ) {
if ( theControlEvent . getController ( ) . getControllerPlugList ( ) . size ( ) > 0 ) {
if ( theType = = ControlP5Constants . STRING ) {
for ( ControllerPlug cp : theControlEvent . getController ( ) . getControllerPlugList ( ) ) {
callTarget ( cp , theControlEvent . getStringValue ( ) ) ;
}
} else if ( theType = = ControlP5Constants . ARRAY ) {
2014-09-08 09:30:57 +02:00
} else if ( theType = = ControlP5Constants . BOOLEAN ) {
for ( ControllerPlug cp : theControlEvent . getController ( ) . getControllerPlugList ( ) ) {
Controller controller = theControlEvent . getController ( ) ;
if ( controller instanceof Icon ) {
callTarget ( cp , ( ( Icon ) controller ) . getBooleanValue ( ) ) ;
} else if ( controller instanceof Button ) {
callTarget ( cp , ( ( Button ) controller ) . getBooleanValue ( ) ) ;
} else if ( controller instanceof Toggle ) {
callTarget ( cp , ( ( Toggle ) controller ) . getBooleanValue ( ) ) ;
}
}
2014-07-22 08:12:30 +02:00
} else {
for ( ControllerPlug cp : theControlEvent . getController ( ) . getControllerPlugList ( ) ) {
if ( cp . checkType ( ControlP5Constants . EVENT ) ) {
invokeMethod ( cp . getObject ( ) , cp . getMethod ( ) , new Object [ ] { theControlEvent } ) ;
} else {
callTarget ( cp , theControlEvent . getValue ( ) ) ;
}
}
}
}
}
if ( _myControlEventType = = ControlP5Constants . METHOD ) {
invokeMethod ( _myControlEventPlug . getObject ( ) , _myControlEventPlug . getMethod ( ) , new Object [ ] { theControlEvent } ) ;
}
}
return this ;
}
protected void callTarget ( final ControllerPlug thePlug , final float theValue ) {
if ( thePlug . checkType ( ControlP5Constants . METHOD ) ) {
invokeMethod ( thePlug . getObject ( ) , thePlug . getMethod ( ) , thePlug . getMethodParameter ( theValue ) ) ;
} else if ( thePlug . checkType ( ControlP5Constants . FIELD ) ) {
invokeField ( thePlug . getObject ( ) , thePlug . getField ( ) , thePlug . getFieldParameter ( theValue ) ) ;
}
}
protected void callTarget ( final ControllerPlug thePlug , final String theValue ) {
if ( thePlug . checkType ( ControlP5Constants . METHOD ) ) {
invokeMethod ( thePlug . getObject ( ) , thePlug . getMethod ( ) , new Object [ ] { theValue } ) ;
} else if ( thePlug . checkType ( ControlP5Constants . FIELD ) ) {
invokeField ( thePlug . getObject ( ) , thePlug . getField ( ) , theValue ) ;
}
}
2014-09-08 09:30:57 +02:00
protected void callTarget ( final ControllerPlug thePlug , final boolean theValue ) {
if ( thePlug . checkType ( ControlP5Constants . METHOD ) ) {
invokeMethod ( thePlug . getObject ( ) , thePlug . getMethod ( ) , new Object [ ] { theValue } ) ;
} else if ( thePlug . checkType ( ControlP5Constants . FIELD ) ) {
invokeField ( thePlug . getObject ( ) , thePlug . getField ( ) , theValue ) ;
}
}
2014-07-22 08:12:30 +02:00
private void invokeField ( final Object theObject , final Field theField , final Object theParam ) {
try {
theField . set ( theObject , theParam ) ;
} catch ( IllegalAccessException e ) {
ControlP5 . logger ( ) . warning ( e . toString ( ) ) ;
}
}
private void invokeMethod ( final Object theObject , final Method theMethod , final Object [ ] theParam ) {
try {
if ( theParam [ 0 ] = = null ) {
theMethod . invoke ( theObject , new Object [ 0 ] ) ;
} else {
theMethod . invoke ( theObject , theParam ) ;
}
} catch ( IllegalArgumentException e ) {
ControlP5 . logger ( ) . warning ( e . toString ( ) ) ;
/ * *
* TODO thrown when plugging a String method / field .
* /
} catch ( IllegalAccessException e ) {
printMethodError ( theMethod , e ) ;
} catch ( InvocationTargetException e ) {
printMethodError ( theMethod , e ) ;
} catch ( NullPointerException e ) {
printMethodError ( theMethod , e ) ;
}
}
protected String getEventMethod ( ) {
return _myEventMethod ;
}
protected void invokeAction ( CallbackEvent theEvent ) {
boolean invoke ;
for ( Entry < CallbackListener , Controller < ? > > entry : _myControllerCallbackListeners ) {
invoke = ( entry . getValue ( ) . getClass ( ) . equals ( EmptyController . class ) ) ? true : ( entry . getValue ( ) . equals ( theEvent . getController ( ) ) ) ? true : false ;
if ( invoke ) {
entry . getKey ( ) . controlEvent ( theEvent ) ;
}
}
if ( _myControllerCallbackEventPlug ! = null ) {
invokeMethod ( cp5 . papplet , _myControllerCallbackEventPlug . getMethod ( ) , new Object [ ] { theEvent } ) ;
}
}
private void printMethodError ( Method theMethod , Exception theException ) {
if ( ! ignoreErrorMessage ) {
ControlP5 . logger ( ) . severe ( " An error occured while forwarding a Controller event, please check your code at " + theMethod . getName ( ) + ( ! setPrintStackTrace ? " " + " exception: " + theException : " " ) ) ;
if ( setPrintStackTrace ) {
theException . printStackTrace ( ) ;
}
}
}
public static void ignoreErrorMessage ( boolean theFlag ) {
ignoreErrorMessage = theFlag ;
}
public static void setPrintStackTrace ( boolean theFlag ) {
setPrintStackTrace = theFlag ;
}
private class EmptyController extends Controller < EmptyController > {
protected EmptyController ( ) {
this ( 0 , 0 ) ;
}
protected EmptyController ( int theX , int theY ) {
super ( " empty " + ( ( int ) ( Math . random ( ) * 1000000 ) ) , theX , theY ) ;
// TODO Auto-generated constructor stub
}
2014-09-08 09:30:57 +02:00
@Override public EmptyController setValue ( float theValue ) {
2014-07-22 08:12:30 +02:00
// TODO Auto-generated method stub
return this ;
}
}
/ * *
* @exclude
* /
2014-09-08 09:30:57 +02:00
@Deprecated public void plug ( final String theControllerName , final String theTargetMethod ) {
2014-07-22 08:12:30 +02:00
plug ( cp5 . papplet , theControllerName , theTargetMethod ) ;
}
}