diff options
Diffstat (limited to 'qtjava/javalib/org/kde/qt/qtjava.java')
-rw-r--r-- | qtjava/javalib/org/kde/qt/qtjava.java | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/qtjava/javalib/org/kde/qt/qtjava.java b/qtjava/javalib/org/kde/qt/qtjava.java new file mode 100644 index 00000000..8547776c --- /dev/null +++ b/qtjava/javalib/org/kde/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 : [email protected] + 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.kde.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 <[email protected]> + */ +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 QEvent 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 QObject, 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.qWarning("Error class not found: " + toFullyQualifiedClassName(className)); + return null; + } + + if (QtSupport.class.isAssignableFrom(aClass)) { + if (QObject.class.isAssignableFrom(aClass)) { + aClass = qtjava.classFromQtMetaData(aClass, aClass.getName(), qt); + } + + try { + result = qtjava.allocateInstance(aClass); + } catch (InstantiationException e) { + Qt.qWarning("Can't instantiate : " + toFullyQualifiedClassName(className)); + return null; + } catch (IllegalAccessException e) { + Qt.qWarning("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.kde.koala.Job"; + } else if (className.equals("Part")) { + return "org.kde.koala.Part"; + } else if (className.equals("Slave")) { + return "org.kde.koala.Slave"; + } else if (className.equals("DOMNode")) { + return "org.kde.koala.DOMNode"; + } else if (className.startsWith("Q")) { + return "org.kde.qt." + className; + } else if (className.startsWith("K")) { + return "org.kde.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(QObject receiver, String member); + + /** Looks up a 'qt instance/slot name' key and returns the corresponding + JavaSlot instance */ + public static long slotForReceiver(long qt, QObject 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(); + } +} |