summaryrefslogtreecommitdiffstats
path: root/qtjava/javalib/org/trinitydesktop/qt/qtjava.java
diff options
context:
space:
mode:
Diffstat (limited to 'qtjava/javalib/org/trinitydesktop/qt/qtjava.java')
-rw-r--r--qtjava/javalib/org/trinitydesktop/qt/qtjava.java285
1 files changed, 285 insertions, 0 deletions
diff --git a/qtjava/javalib/org/trinitydesktop/qt/qtjava.java b/qtjava/javalib/org/trinitydesktop/qt/qtjava.java
new file mode 100644
index 00000000..105fa3d3
--- /dev/null
+++ b/qtjava/javalib/org/trinitydesktop/qt/qtjava.java
@@ -0,0 +1,285 @@
+/***************************************************************************
+ 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();
+ }
+}