diff options
Diffstat (limited to 'qtjava/javalib/org/trinitydesktop/qt/Invocation.java')
-rw-r--r-- | qtjava/javalib/org/trinitydesktop/qt/Invocation.java | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/qtjava/javalib/org/trinitydesktop/qt/Invocation.java b/qtjava/javalib/org/trinitydesktop/qt/Invocation.java new file mode 100644 index 00000000..022c67bd --- /dev/null +++ b/qtjava/javalib/org/trinitydesktop/qt/Invocation.java @@ -0,0 +1,527 @@ +/*************************************************************************** + Invocation.java - description + ------------------- + begin : Tue Oct 31 06:12:14 2000 + copyright : (C) 2000-2002 Lost Highway Ltd. All rights reserved. + email : Lost_Highway@tipitina.demon.co.uk + written by : Richard Dale. + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +package org.trinitydesktop.qt; + +import java.util.*; +import java.lang.reflect.*; + +/** A utility class for creating a closure to invoke later - when a Java + slot or event handler needs to be activated + + @author Richard Dale <Richard_Dale@tipitina.demon.co.uk> + */ +public class Invocation { + /** The target object */ + private Object onThis; + /** Arguments from an emitted signal to pass to the slot method */ + private Object[] arguments; + /** The Java method that implements the slot, (or emit() for a signal target) */ + private Method method; + /** An optional instance variable, used when the target is a signal, + rather than a slot. */ + private String signalName; + + /** Converts a type signature from a Qt signal or slot to an array of + Class objects corresponding to the Java types of the parameters */ + private static Class[] fromQtTypeSignature(String qtTypeSignature) { + ArrayList parameterTypes = new ArrayList(); + StringTokenizer tokenizer = new StringTokenizer(qtTypeSignature, ","); + + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + + if (token.equals("")) { + parameterTypes.add(null); + } else if (token.equals("boolean")) { + parameterTypes.add(boolean.class); + } else if (token.equals("char")) { + parameterTypes.add(char.class); + } else if (token.equals("long")) { + parameterTypes.add(long.class); + } else if (token.equals("int")) { + parameterTypes.add(int.class); + } else if (token.equals("short")) { + parameterTypes.add(short.class); + } else if (token.equals("float")) { + parameterTypes.add(float.class); + } else if (token.equals("double")) { + parameterTypes.add(double.class); + } else if (token.equals("int[]")) { + parameterTypes.add(int[].class); + } else if (token.equals("byte[]")) { + parameterTypes.add(byte[].class); + } else { + try { + parameterTypes.add(Class.forName(token)); + } catch (ClassNotFoundException e) { + Qt.tqWarning("TQObject.connect: No such argument type: " + token); + return null; + } + } + } + + return (Class[]) parameterTypes.toArray(new Class[0]); + } + + /** Contained in a C++ JavaSlot instance, allows the JavaSlot to act as a proxy for the Java method to be invoked. + The method name in the slot string is converted to a Java Method instance, and the arguments to a suitable + Class[] structure, as the corresponding argument type list. */ + Invocation(Object target, String receiverString) { + Method targetMethod = null; + Class targetClass = null; + String methodName; + Class[] parameterTypes; + + if (receiverString.startsWith("2")) { + // Target is a signal + methodName = "emit"; + parameterTypes = new Class[] {java.lang.String.class, Object[].class}; + signalName = receiverString; + } else { + // Target is a slot + methodName = receiverString.substring(1, receiverString.indexOf('(')); + parameterTypes = fromQtTypeSignature(receiverString.substring( receiverString.indexOf('(') + 1, + receiverString.indexOf(')') ) ); + if (parameterTypes == null) { + return; + } + signalName = null; + } + + // A slot can either be public or protected. However, it isn't possible + // to obtain inherited protected members using getMethod() or + // getDeclaredMethod(). Hence, the apparently over complicated loop here. + targetClass = target.getClass(); + + do { + try { + targetMethod = targetClass.getDeclaredMethod(methodName, parameterTypes); + } catch (NoSuchMethodException e1) { + try { + targetMethod = targetClass.getMethod(methodName, parameterTypes); + } catch (NoSuchMethodException e2) { + ; + } + } + + if (targetMethod != null) { + onThis = target; + arguments = null; + method = targetMethod; + method.setAccessible(true); + return; + } + + targetClass = targetClass.getSuperclass(); + } while (targetClass != null); + + System.out.print("TQObject.connect: No such slot " + methodName + "("); + for (int index = 0; index < parameterTypes.length; index++) { + System.out.print(parameterTypes[index].toString()); + + if (index + 1 < parameterTypes.length) { + System.out.print(","); + } + } + System.out.println(")"); + return; + } + + Invocation(Object target, Object[] args, Method aMethod) { + onThis = target; + arguments = args; + method = aMethod; + method.setAccessible(true); + } + + public void setArguments(Object[] args) { + arguments = args; + } + + /** Not used at present, here for completeness */ + public Object invoke() throws IllegalAccessException, InvocationTargetException { + try { + Object result = method.invoke(onThis, arguments); + } catch (InvocationTargetException e) { + return null; + } catch (IllegalAccessException e) { + return null; + } finally { + return null; + } + } + + /** Used for Java slot/signal targets, handles callbacks */ + public Object invoke(Object[] args) throws IllegalAccessException, InvocationTargetException { + if (signalName != null) { + // If the target is a signal, then there are two parameters needed for TQObject.emit(). + // A signal name, followed by an array of arguments to be emitted. + Object[] emitArgs = new Object[2]; + emitArgs[0] = signalName; + emitArgs[1] = args; + setArguments(emitArgs); + } else { + // If the target is a slot, then just pass on the arguments to the target slot + setArguments(args); + } + + try { + Object result = method.invoke(onThis, arguments); + } catch (InvocationTargetException e) { + Qt.tqWarning("Slot invocation failed"); + e.printStackTrace(); + return null; + } catch (IllegalAccessException e) { + Qt.tqWarning("Slot invocation failed"); + e.printStackTrace(); + return null; + } finally { + return null; + } + } + + /** Used for boolean slot handling callbacks */ + public Object invoke(boolean arg) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[1]; + arguments[0] = new Boolean(arg); + return invoke(arguments); + } + + /** Used for C++ sender to byte (ie unsigned char in C++) Java slot handling callbacks */ + public Object invoke(byte arg) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[1]; + arguments[0] = new Byte(arg); + return invoke(arguments); + } + + /** Used for C++ sender to char Java slot handling callbacks */ + public Object invoke(char arg) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[1]; + arguments[0] = new Character(arg); + return invoke(arguments); + } + + /** Used for C++ sender to short Java slot handling callbacks */ + public Object invoke(short arg) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[1]; + arguments[0] = new Short(arg); + return invoke(arguments); + } + + /** Used for C++ sender to int Java slot handling callbacks */ + public Object invoke(int arg) throws IllegalAccessException, InvocationTargetException{ + arguments = new Object[1]; + arguments[0] = new Integer(arg); + return invoke(arguments); + } + + /** Used for C++ sender to long Java slot handling callbacks */ + public Object invoke(long arg) throws IllegalAccessException, InvocationTargetException{ + arguments = new Object[1]; + arguments[0] = new Long(arg); + return invoke(arguments); + } + + /** Used for C++ sender float Java slot handling callbacks */ + public Object invoke(float arg) throws IllegalAccessException, InvocationTargetException{ + arguments = new Object[1]; + arguments[0] = new Float(arg); + return invoke(arguments); + } + + /** Used for C++ sender to double Java slot handling callbacks */ + public Object invoke(double arg) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[1]; + arguments[0] = new Double(arg); + return invoke(arguments); + } + + public Object invoke(Object arg) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[1]; + arguments[0] = arg; + return invoke(arguments); + } + + public Object invoke(Object arg1, byte[] arg2) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[2]; + arguments[0] = arg1; + arguments[1] = arg2; + return invoke(arguments); + } + + public Object invoke(Object arg1, Object arg2) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[2]; + arguments[0] = arg1; + arguments[1] = arg2; + return invoke(arguments); + } + + public Object invoke(Object arg1, Object arg2, Object arg3) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[3]; + arguments[0] = arg1; + arguments[1] = arg2; + arguments[2] = arg3; + return invoke(arguments); + } + + public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[4]; + arguments[0] = arg1; + arguments[1] = arg2; + arguments[2] = arg3; + arguments[3] = arg4; + return invoke(arguments); + } + + public Object invoke(Object arg1, boolean arg2) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[2]; + arguments[0] = arg1; + arguments[1] = new Boolean(arg2); + return invoke(arguments); + } + + public Object invoke(Object arg1, Object arg2, int arg3) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[3]; + arguments[0] = arg1; + arguments[1] = arg2; + arguments[2] = new Integer(arg3); + return invoke(arguments); + } + + public Object invoke(int arg1, Object arg2) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[2]; + arguments[0] = new Integer(arg1); + arguments[1] = arg2; + return invoke(arguments); + } + + public Object invoke(int arg1, Object arg2, Object arg3) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[3]; + arguments[0] = new Integer(arg1); + arguments[1] = arg2; + arguments[2] = arg3; + return invoke(arguments); + } + + public Object invoke(int arg1, Object arg2, Object arg3, int arg4) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[3]; + arguments[0] = new Integer(arg1); + arguments[1] = arg2; + arguments[2] = arg3; + arguments[3] = new Integer(arg4); + return invoke(arguments); + } + + public Object invoke(int arg1, boolean arg2) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[2]; + arguments[0] = new Integer(arg1); + arguments[1] = new Boolean(arg2); + return invoke(arguments); + } + + public Object invoke(int arg1, int arg2) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[2]; + arguments[0] = new Integer(arg1); + arguments[1] = new Integer(arg2); + return invoke(arguments); + } + + public Object invoke(int arg1, int arg2, int arg3) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[3]; + arguments[0] = new Integer(arg1); + arguments[1] = new Integer(arg2); + arguments[2] = new Integer(arg3); + return invoke(arguments); + } + + public Object invoke(int arg1, int arg2, int arg3, Object arg4) throws IllegalAccessException, InvocationTargetException { + arguments = new Object[4]; + arguments[0] = new Integer(arg1); + arguments[1] = new Integer(arg2); + arguments[2] = new Integer(arg3); + arguments[2] = arg4; + return invoke(arguments); + } + + /** Invoke the named void method on the target object with no arguments. Returns true + if the target method was successfully invoked. */ + public static boolean invoke(long target, String className, String methodName) throws NoSuchMethodException, ClassNotFoundException { + Method method; + Object onThis = qtjava.objectForQtKey(target, className, false); + + try { + method = onThis.getClass().getMethod(methodName, (Class[]) null); + } catch (NoSuchMethodException e1) { + try { + method = onThis.getClass().getDeclaredMethod(methodName, (Class[]) null); + } catch (NoSuchMethodException e2) { + return false; + } + } + + // Ignore any native code event handling methods + if ((method.getModifiers() & Modifier.NATIVE) != 0) { + return false; + } + + try { + method.setAccessible(true); + Object result = method.invoke(onThis, (Class[]) null); + return true; + } catch (InvocationTargetException e) { + Qt.tqWarning("Invocation failed : " + onThis.getClass().getName() + "." + methodName + "()"); + e.printStackTrace(); + return false; + } catch (IllegalAccessException e) { + Qt.tqWarning("Invocation failed : " + onThis.getClass().getName() + "." + methodName + "()"); + e.printStackTrace(); + return false; + } + } + /** Invoke the named method on the target object with no arguments. Returns false + iff the target method was successfully invoked AND returned false. Unlike the other + variants of boolean invoke(), this method returns true if no target java method exists. + Used for boolean callbacks such as TDEMainWindow::queryClose() */ + public static boolean booleanInvoke(long target, String methodName) throws NoSuchMethodException, ClassNotFoundException { + Method method; + Object onThis = qtjava.objectForQtKey(target, "TQObject", false); + + try { + method = onThis.getClass().getMethod(methodName, (Class[]) null); + } catch (NoSuchMethodException e1) { + try { + method = onThis.getClass().getDeclaredMethod(methodName, (Class[]) null); + } catch (NoSuchMethodException e2) { + return true; + } + } + + // Ignore any native code event handling methods + if ((method.getModifiers() & Modifier.NATIVE) != 0) { + return true; + } + + try { + method.setAccessible(true); + Object result = method.invoke(onThis, (Class[]) null); + return ((Boolean) result).booleanValue(); + } catch (InvocationTargetException e) { + Qt.tqWarning("Invocation failed : " + onThis.getClass().getName() + "." + methodName + "()"); + e.printStackTrace(); + return true; + } catch (IllegalAccessException e) { + Qt.tqWarning("Invocation failed : " + onThis.getClass().getName() + "." + methodName + "()"); + e.printStackTrace(); + return true; + } + } + + /** Invoke the named method on the target object with a single argument. Returns true + if the method was successfully invoked, otherwise false. + Used for event handling callbacks */ + public static boolean invoke(long target, long arg, String argClass, String methodName) throws NoSuchMethodException, ClassNotFoundException { + Method method = null; + Class[] parameterType = new Class[1]; + parameterType[0] = Class.forName(qtjava.toFullyQualifiedClassName(argClass)); + Object onThis = qtjava.objectForQtKey(target, "org.trinitydesktop.qt.TQObject", false); + + Class targetClass = onThis.getClass(); + + do { + try { + method = targetClass.getDeclaredMethod(methodName, parameterType); + method.setAccessible(true); + break; + } catch (NoSuchMethodException e1) { + } + + targetClass = targetClass.getSuperclass(); + } while (targetClass != null); + + if (targetClass == null) { + return false; + } + + // Ignore any native code event handling methods + if ((method.getModifiers() & Modifier.NATIVE) != 0) { + return false; + } + + Object[] arguments = new Object[1]; + arguments[0] = qtjava.objectForQtKey(arg, argClass, false); + + try { + // Invoke the event handler + Object result = method.invoke(onThis, arguments); + + // The event will no longer be referenced, so force remove its java mapping entry. + qtjava.removeObjectForQtKey(arg); + } catch (InvocationTargetException e) { + Qt.tqWarning("Event handler failed : " + onThis.getClass().getName() + "." + methodName + "(" + qtjava.toFullyQualifiedClassName(argClass) + " event)"); + e.printStackTrace(); + return false; + } catch (IllegalAccessException e) { + Qt.tqWarning("Event handler failed : " + onThis.getClass().getName() + "." + methodName + "(" + qtjava.toFullyQualifiedClassName(argClass) + " event)"); + e.printStackTrace(); + return false; + } finally { + return true; + } + } + + /** Invoke the named method on the target object with two arguments. Returns true + if the method was successfully invoked, otherwise false. + Used for event filter callbacks */ + public static boolean invoke(long target, long arg1, String arg1class, long arg2, String arg2class, String methodName) throws NoSuchMethodException, ClassNotFoundException { + Method method; + Boolean result = null; + Object[] arguments = new Object[2]; + arguments[0] = qtjava.objectForQtKey(arg1, arg1class, false); + arguments[1] = qtjava.objectForQtKey(arg2, arg2class, false); + + Class[] parameterTypes = new Class[] { TQObject.class, TQEvent.class }; + Object onThis = qtjava.objectForQtKey(target, "TQObject", false); + + try { + method = onThis.getClass().getMethod(methodName, parameterTypes); + method.setAccessible(true); + } catch (NoSuchMethodException e) { + return false; + } + + // Ignore any native code event handling methods + if ((method.getModifiers() & Modifier.NATIVE) != 0) { + return false; + } + + try { + result = (Boolean) method.invoke(onThis, arguments); + } catch (InvocationTargetException e) { + Qt.tqWarning("Event filter failed : " + onThis.getClass().getName() + "." + methodName + "()"); + e.printStackTrace(); + return false; + } catch (IllegalAccessException e) { + Qt.tqWarning("Event filter failed : " + onThis.getClass().getName() + "." + methodName + "()"); + e.printStackTrace(); + return false; + } finally { + return result.booleanValue(); + } + } +} |