You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
286 lines
10 KiB
286 lines
10 KiB
/***************************************************************************
|
|
qtjava.java - description
|
|
-------------------
|
|
begin : Tue Oct 31 06:12:14 2000
|
|
copyright : (C) 2000 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.Error;
|
|
|
|
/** The 'Run the Qt Java library' class'. Various utility methods to manage
|
|
the mapping between C++ and java instances. Used in conjunction the C++ methods
|
|
in QtSupport.cpp and JavaSlot.cpp.
|
|
|
|
@author Richard Dale <Richard_Dale@tipitina.demon.co.uk>
|
|
*/
|
|
public class qtjava {
|
|
/** Uses a C++ key to retrieve the corresponding Java instance */
|
|
public static WeakValueMap qtKeyToJavaMap = null;
|
|
|
|
/** Allows a JavaSignal proxy instance to be retrieved for a given Java
|
|
instance/Signal name combination */
|
|
public static HashMap qtSignalDictionary = null;
|
|
|
|
/** Allows a JavaSlot proxy instance to be retrieved for a given Java
|
|
instance/Slot name combination */
|
|
public static HashMap qtSlotDictionary = null;
|
|
|
|
/** Register a JavaVM pointer to make it easy to retrieve the current
|
|
JNIEnv later */
|
|
private native static void registerJVM();
|
|
|
|
/** Get/set the C++ instance for a given Java instance */
|
|
private native static void setQt(Object obj, long qt);
|
|
private native static long getQt(Object obj);
|
|
|
|
/** If a C++ instance has been allocated in the Java World, it will
|
|
be deleted within the corresponding Java instance's finalize method. */
|
|
private native static void setAllocatedInJavaWorld(Object obj, boolean yn);
|
|
private native static boolean allocatedInJavaWorld(Object obj);
|
|
|
|
/** This member allows a typecast of an instance which wraps a
|
|
Qt instance, to a more specialized type. */
|
|
private static QtSupport dynamicCast(String type, QtSupport source) {
|
|
boolean sourceAllocatedInJavaWorld = allocatedInJavaWorld(source);
|
|
long qtHandle = getQt(source);
|
|
|
|
removeObjectForQtKey(qtHandle);
|
|
setAllocatedInJavaWorld(source, false);
|
|
return (QtSupport) objectForQtKey(qtHandle, type, sourceAllocatedInJavaWorld);
|
|
}
|
|
|
|
/** Add a 'C++ qt instance key/Java instance value' pair to the map */
|
|
public static void setObjectForQtKey(Object obj, long qt) {
|
|
qtKeyToJavaMap.put(Long.toString(qt).intern(), obj);
|
|
return;
|
|
}
|
|
|
|
/** Remove a 'C++ qt instance key/Java instance value' pair from the map.
|
|
Normally an entry would be removed when its map value is the last reference
|
|
left to the java instance, and it becomes a weak reference to be reaped.
|
|
But C++ can reuse a heap address for a C++ ref without giving the java runtime
|
|
a chance to do any garbage collection and tidy up the corresponding entry in the
|
|
qtKeyToJavaMap (tricky!).
|
|
|
|
So it is useful to be able to force the early removal of an entry, when the C++
|
|
instance has a known lifetime (eg a TQEvent after its event handler has
|
|
returned).
|
|
*/
|
|
public static void removeObjectForQtKey(long qt) {
|
|
qtKeyToJavaMap.remove(Long.toString(qt).intern());
|
|
return;
|
|
}
|
|
|
|
/** Allocates an instance of a class without initializing it */
|
|
private native static Object allocateInstance(Class cls) throws InstantiationException, IllegalAccessException;
|
|
|
|
/** If the C++ qt instance is an instance of TQObject, then
|
|
use the Qt runtime meta-data to retrieve the class name.
|
|
If there is a Java class with the same name, then return
|
|
a Class object for that class. Otherwise, just return the
|
|
original 'approximate' Class passed to the method.
|
|
|
|
Note that a java equivalent of the C++ instance doesn't have
|
|
to be instantiated to do this */
|
|
private native static Class classFromQtMetaData(Class approximateClass, String approximateClassName, long qt);
|
|
|
|
/** Retrieves a corresponding Java instance for a given C++ instance. Allocates
|
|
the Java instance if it doesn't already exist. */
|
|
public static Object objectForQtKey(long qt, String className, boolean allocatedInJavaWorld) {
|
|
Object result;
|
|
Class aClass;
|
|
|
|
result = qtKeyToJavaMap.get(Long.toString(qt).intern());
|
|
|
|
if (result == null) {
|
|
try {
|
|
aClass = Class.forName(toFullyQualifiedClassName(className));
|
|
} catch (ClassNotFoundException e) {
|
|
Qt.tqWarning("Error class not found: " + toFullyQualifiedClassName(className));
|
|
return null;
|
|
}
|
|
|
|
if (QtSupport.class.isAssignableFrom(aClass)) {
|
|
if (TQObject.class.isAssignableFrom(aClass)) {
|
|
aClass = qtjava.classFromQtMetaData(aClass, aClass.getName(), qt);
|
|
}
|
|
|
|
try {
|
|
result = qtjava.allocateInstance(aClass);
|
|
} catch (InstantiationException e) {
|
|
Qt.tqWarning("Can't instantiate : " + toFullyQualifiedClassName(className));
|
|
return null;
|
|
} catch (IllegalAccessException e) {
|
|
Qt.tqWarning("Illegal access to class : " + toFullyQualifiedClassName(className));
|
|
return null;
|
|
}
|
|
|
|
setQt(result, qt);
|
|
setAllocatedInJavaWorld(result, allocatedInJavaWorld);
|
|
} else {
|
|
// A Java instance without a wrapped Qt C++ instance (eg a list)
|
|
try {
|
|
result = aClass.newInstance();
|
|
} catch (InstantiationException e) {
|
|
return null;
|
|
} catch (IllegalAccessException e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
setObjectForQtKey(result, qt);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/** When a C++ instance has been deleted. Retrieves a corresponding Java instance for a given C++ instance. Sets
|
|
the '_allocatedInJavaWorld' flag to false. */
|
|
public static void qtKeyDeleted(long qt) {
|
|
Object result = qtKeyToJavaMap.get(Long.toString(qt).intern());
|
|
|
|
if ( result != null
|
|
&& QtSupport.class.isAssignableFrom(result.getClass()) )
|
|
{
|
|
setAllocatedInJavaWorld(result, false);
|
|
}
|
|
}
|
|
|
|
/** Converts any unqualified class names in a signal or slot string to the fully qualified versions */
|
|
public static String toFullyQualifiedClassName(String className) {
|
|
if (className.equals("String")) {
|
|
return "java.lang.String";
|
|
} else if (className.equals("Date")) {
|
|
return "java.util.Date";
|
|
} else if (className.equals("Calendar")) {
|
|
return "java.util.GregorianCalendar";
|
|
} else if (className.equals("ArrayList")) {
|
|
return "java.util.ArrayList";
|
|
} else if (className.equals("ByteArrayOutputStream")) {
|
|
return "java.io.ByteArrayOutputStream";
|
|
} else if (className.equals("Job")) {
|
|
return "org.trinitydesktop.koala.Job";
|
|
} else if (className.equals("Part")) {
|
|
return "org.trinitydesktop.koala.Part";
|
|
} else if (className.equals("Slave")) {
|
|
return "org.trinitydesktop.koala.Slave";
|
|
} else if (className.equals("DOMNode")) {
|
|
return "org.trinitydesktop.koala.DOMNode";
|
|
} else if (className.startsWith("Q")) {
|
|
return "org.trinitydesktop.qt." + className;
|
|
} else if (className.startsWith("K")) {
|
|
return "org.trinitydesktop.koala." + className;
|
|
}
|
|
return className;
|
|
}
|
|
|
|
/** Converts from a list Java types in a signal or slot string, to the fully qualified equivalent */
|
|
private static String toNormalizedTypeSignature(String typeSignature) {
|
|
StringBuffer normalizedTypeSignature = new StringBuffer( typeSignature.substring( 0,
|
|
typeSignature.indexOf('(') + 1 ) );
|
|
StringTokenizer tokenizer = new StringTokenizer( typeSignature.substring( typeSignature.indexOf('(') + 1,
|
|
typeSignature.indexOf(')') ),
|
|
"," );
|
|
|
|
while (tokenizer.hasMoreTokens()) {
|
|
String token = tokenizer.nextToken();
|
|
|
|
if ( token.equals("boolean")
|
|
|| token.equals("byte")
|
|
|| token.equals("char")
|
|
|| token.equals("long")
|
|
|| token.equals("int")
|
|
|| token.equals("short")
|
|
|| token.equals("float")
|
|
|| token.equals("double") )
|
|
{
|
|
normalizedTypeSignature.append(token);
|
|
} else {
|
|
normalizedTypeSignature.append(toFullyQualifiedClassName(token));
|
|
}
|
|
|
|
if (tokenizer.hasMoreTokens()) {
|
|
normalizedTypeSignature.append(",");
|
|
}
|
|
}
|
|
|
|
normalizedTypeSignature.append(")");
|
|
return normalizedTypeSignature.toString();
|
|
}
|
|
|
|
/** Returns a new C++ JavaSignal proxy instance, to forward the signal
|
|
onto the target Java slot */
|
|
private native static long newJavaSignal();
|
|
|
|
/** Looks up a 'qt instance/signal name' key and returns the corresponding
|
|
JavaSignal instance */
|
|
public static long signalForSender(long qt, String signal) {
|
|
String normalizedSignal = toNormalizedTypeSignature(signal);
|
|
String key = (Long.toString(qt) + normalizedSignal).intern();
|
|
Long result = (Long) qtSignalDictionary.get(key);
|
|
|
|
if (result == null) {
|
|
long javaSignal = newJavaSignal();
|
|
qtSignalDictionary.put(key, new Long(javaSignal));
|
|
return javaSignal;
|
|
} else {
|
|
return result.longValue();
|
|
}
|
|
}
|
|
|
|
/** Initialises the JavaSlot factory */
|
|
private native static void setJavaSlotFactory();
|
|
|
|
/** Returns a new C++ JavaSlot proxy instance, to receive signals
|
|
and invoke the target Java slot */
|
|
private native static long newJavaSlot(TQObject receiver, String member);
|
|
|
|
/** Looks up a 'qt instance/slot name' key and returns the corresponding
|
|
JavaSlot instance */
|
|
public static long slotForReceiver(long qt, TQObject receiver, String slot) {
|
|
String normalizedSlot = toNormalizedTypeSignature(slot);
|
|
String key = (Long.toString(qt) + normalizedSlot).intern();
|
|
Long result = (Long) qtSlotDictionary.get(key);
|
|
|
|
if (result == null) {
|
|
long javaSlot = newJavaSlot(receiver, normalizedSlot);
|
|
qtSlotDictionary.put(key, new Long(javaSlot));
|
|
return javaSlot;
|
|
} else {
|
|
return result.longValue();
|
|
}
|
|
}
|
|
|
|
private static boolean _initialized = false;
|
|
|
|
public static void initialize() {
|
|
if (!_initialized) {
|
|
System.loadLibrary("qtjava");
|
|
qtjava.registerJVM();
|
|
qtjava.setJavaSlotFactory();
|
|
qtKeyToJavaMap = new WeakValueMap();
|
|
qtSignalDictionary = new HashMap();
|
|
qtSlotDictionary = new HashMap();
|
|
_initialized = true;
|
|
}
|
|
}
|
|
|
|
static {
|
|
initialize();
|
|
}
|
|
}
|