
io.qt.internal.MetaObjectTools Maven / Gradle / Ivy
/****************************************************************************
**
** Copyright (C) 1992-2009 Nokia. All rights reserved.
** Copyright (C) 2009-2021 Dr. Peter Droste, Omix Visualization GmbH & Co. KG. All rights reserved.
**
** This file is part of Qt Jambi.
**
** ** $BEGIN_LICENSE$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
** $END_LICENSE$
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
package io.qt.internal;
import static io.qt.internal.QtJambiInternal.internalTypeNameOfClass;
import static io.qt.internal.QtJambiInternal.registerMetaType;
import static io.qt.internal.QtJambiInternal.registerQmlListProperty;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Logger;
import io.qt.NativeAccess;
import io.qt.QFlags;
import io.qt.QSignalDeclarationException;
import io.qt.QtByteEnumerator;
import io.qt.QtClassInfo;
import io.qt.QtEnumerator;
import io.qt.QtInvokable;
import io.qt.QtLongEnumerator;
import io.qt.QtPointerType;
import io.qt.QtPropertyConstant;
import io.qt.QtPropertyDesignable;
import io.qt.QtPropertyMember;
import io.qt.QtPropertyNotify;
import io.qt.QtPropertyReader;
import io.qt.QtPropertyRequired;
import io.qt.QtPropertyResetter;
import io.qt.QtPropertyScriptable;
import io.qt.QtPropertyStored;
import io.qt.QtPropertyUser;
import io.qt.QtPropertyWriter;
import io.qt.QtReferenceType;
import io.qt.QtShortEnumerator;
import io.qt.QtSignalEmitterInterface;
import io.qt.QtUninvokable;
import io.qt.QtUnlistedEnum;
import io.qt.core.QMetaMethod;
import io.qt.core.QMetaObject;
import io.qt.core.QMetaType;
import io.qt.core.QObject;
import io.qt.core.QPair;
import io.qt.internal.QtJambiSignals.AbstractSignal;
import io.qt.internal.QtJambiSignals.SignalParameterType;
/**
* Methods to help construct the fake meta object.
*/
final class MetaObjectTools extends AbstractMetaObjectTools{
private static class PrivateConstructorAccess extends io.qt.QtObject{
static Class> type(){
return QPrivateConstructor.class;
}
}
private MetaObjectTools() { throw new RuntimeException();}
static class AnnotationInfo{
AnnotationInfo(String name, boolean enabled) {
super();
this.name = name;
this.enabled = enabled;
}
final String name;
final boolean enabled;
}
static class QPropertyTypeInfo{
QPropertyTypeInfo(Class> propertyType, Type genericPropertyType, AnnotatedType annotatedPropertyType, boolean isPointer,
boolean isReference, boolean isWritable) {
super();
this.propertyType = propertyType;
this.genericPropertyType = genericPropertyType;
this.annotatedPropertyType = annotatedPropertyType;
this.isPointer = isPointer;
this.isReference = isReference;
this.isWritable = isWritable;
}
final Class> propertyType;
final Type genericPropertyType;
final AnnotatedType annotatedPropertyType;
final boolean isPointer;
final boolean isReference;
final boolean isWritable;
}
static class PropertyAnnotation {
enum AnnotationType {
Reader,
Writer,
Resetter,
Notify,
Bindable,
Member
}
private Member member;
private String name = null;
private boolean enabled;
private AnnotationType type;
private PropertyAnnotation(String name, Member member, boolean enabled, AnnotationType type) {
this.name = name;
this.member = member;
this.enabled = enabled;
this.type = type;
}
private static String removeAndLowercaseFirst(String name, int count) {
return Character.toLowerCase(name.charAt(count)) + name.substring(count + 1);
}
private String getNameFromMethod(Member member) {
String name = member.getName();
switch(type) {
case Resetter:
if(name.startsWith("reset") && name.length() > 5) {
return removeAndLowercaseFirst(name, 5);
}
return "";
case Bindable:
if(name.startsWith("bindable") && name.length() > 8) {
return removeAndLowercaseFirst(name, 8);
}
return "";
case Member:
if(name.endsWith("Prop") && name.length() > 4) {
return name.substring(0, name.length()-4);
}
if(name.endsWith("Property") && name.length() > 8) {
return name.substring(0, name.length()-8);
}
return name;
case Notify:
if(name.endsWith("Changed") && name.length() > 7) {
return name.substring(0, name.length()-7);
}
return "";
case Reader:
int len = name.length();
if (name.startsWith("get") && len > 3)
name = removeAndLowercaseFirst(name, 3);
else if (isBoolean(((Method)member).getReturnType()) && name.startsWith("is") && len > 2)
name = removeAndLowercaseFirst(name, 2);
else if (isBoolean(((Method)member).getReturnType()) && name.startsWith("has") && len > 3)
name = removeAndLowercaseFirst(name, 3);
return name;
case Writer: // starts with "set"
default:
if (!name.startsWith("set") || name.length() <= 3) {
throw new IllegalArgumentException("The correct pattern for setter accessor names is setXxx where Xxx is the property name with upper case initial.");
}
name = removeAndLowercaseFirst(name, 3);
return name;
}
}
String name() {
if (name == null || name.length() == 0)
name = getNameFromMethod(member);
return name;
}
boolean enabled() {
return enabled;
}
static PropertyAnnotation readerAnnotation(Method method) {
QtPropertyReader reader = method.getAnnotation(QtPropertyReader.class);
return reader == null ? null : new PropertyAnnotation(reader.name(), method, reader.enabled(), AnnotationType.Reader);
}
static PropertyAnnotation memberAnnotation(Field field) {
QtPropertyMember member = field.getAnnotation(QtPropertyMember.class);
return member == null ? null : new PropertyAnnotation(member.name(), field, member.enabled(), AnnotationType.Member);
}
static PropertyAnnotation writerAnnotation(Method method) {
QtPropertyWriter writer = method.getAnnotation(QtPropertyWriter.class);
return writer == null ? null : new PropertyAnnotation(writer.name(), method, writer.enabled(), AnnotationType.Writer);
}
static PropertyAnnotation resetterAnnotation(Method method) {
QtPropertyResetter resetter = method.getAnnotation(QtPropertyResetter.class);
return resetter == null ? null : new PropertyAnnotation(resetter.name(), method, resetter.enabled(), AnnotationType.Resetter);
}
static PropertyAnnotation notifyAnnotation(Field field) {
QtPropertyNotify notify = field.getAnnotation(QtPropertyNotify.class);
return notify == null ? null : new PropertyAnnotation(notify.name(), field, notify.enabled(), AnnotationType.Notify);
}
static PropertyAnnotation bindableAnnotation(Method method) {
AnnotationInfo bindable = analyzeBindableAnnotation(method);
return bindable == null ? null : new PropertyAnnotation(bindable.name, method, bindable.enabled, AnnotationType.Bindable);
}
}
private static class StringList extends ArrayList{
private static final long serialVersionUID = -7793211808465428478L;
@Override
public boolean add(String e) {
if (!contains(e))
return super.add(e);
return true;
}
}
private static class MetaData {
final @NativeAccess List metaData = new ArrayList<>();
final @NativeAccess List stringData = new StringList();
final @NativeAccess List signalFields = new ArrayList<>();
final @NativeAccess List methods = new ArrayList<>();
final @NativeAccess List> constructors = new ArrayList<>();
final @NativeAccess List propertyReaders = new ArrayList<>();
final @NativeAccess List propertyWriters = new ArrayList<>();
final @NativeAccess List propertyResetters = new ArrayList<>();
final @NativeAccess List propertyNotifies = new ArrayList<>();
final @NativeAccess List propertyBindables = new ArrayList<>();
final @NativeAccess List propertyQPropertyFields = new ArrayList<>();
final @NativeAccess List propertyMemberFields = new ArrayList<>();
final @NativeAccess List propertyDesignableResolvers = new ArrayList<>();
final @NativeAccess List propertyScriptableResolvers = new ArrayList<>();
final @NativeAccess List propertyEditableResolvers = new ArrayList<>();
final @NativeAccess List propertyStoredResolvers = new ArrayList<>();
final @NativeAccess List propertyUserResolvers = new ArrayList<>();
final @NativeAccess List> relatedMetaObjects = new ArrayList<>();
@NativeAccess boolean hasStaticMembers;
final @NativeAccess List metaTypes = new ArrayList<>();
}
private static Method notBogus(Method method, String propertyName, Class> paramType) {
if (method == null)
return null;
PropertyAnnotation reader = PropertyAnnotation.readerAnnotation(method);
if (reader != null
&& (!reader.name().equals(propertyName)
|| !reader.enabled()
|| !method.getReturnType().isAssignableFrom(paramType))) {
return null;
} else {
return method;
}
}
private static int queryEnums(Class> clazz, Hashtable> enums) {
int enumConstantCount = 0;
Class> declaredClasses[] = clazz.getDeclaredClasses();
for (Class> declaredClass : declaredClasses)
enumConstantCount += putEnumTypeInHash(declaredClass, enums);
return enumConstantCount;
}
@NativeAccess
private static Class> getEnumForQFlags(Class> flagsType) {
Type t = flagsType.getGenericSuperclass();
if (t instanceof ParameterizedType) {
Type typeArguments[] = ((ParameterizedType)t).getActualTypeArguments();
return ((Class>) typeArguments[0]);
}
return null;
}
private static int putEnumTypeInHash(Class> type, Hashtable> enums) {
Class> flagsType = QFlags.class.isAssignableFrom(type) ? type : null;
Class> enumType = type.isEnum() ? type : null;
if (enumType == null && flagsType != null) {
enumType = getEnumForQFlags(flagsType);
}
if (enumType == null)
return 0;
// Since Qt supports enums that are not part of the meta object
// we need to check whether the enum can actually be used in
// a property.
Class> enclosingClass = enumType.getEnclosingClass();
if (enclosingClass == null){
return -1;
}
if (enumType.isAnnotationPresent(QtUnlistedEnum.class)) {
return -1;
}
int enumConstantCount = 0;
if (!enums.contains(enumType.getName())) {
enums.put(enumType.getName(), enumType);
enumConstantCount = enumType.getEnumConstants().length;
}
if (flagsType != null && !enums.contains(flagsType.getName()))
enums.put(flagsType.getName(), flagsType);
return enumConstantCount;
}
private static boolean isEnumAllowedForProperty(Class> type) {
Class> flagsType = QFlags.class.isAssignableFrom(type) ? type : null;
Class> enumType = type.isEnum() ? type : null;
if (enumType == null && flagsType != null) {
enumType = getEnumForQFlags(flagsType);
}
if (enumType == null)
return false;
// Since Qt supports enums that are not part of the meta object
// we need to check whether the enum can actually be used in
// a property.
Class> enclosingClass = enumType.getEnclosingClass();
if (enclosingClass == null){
return false;
}
if(enumType.isAnnotationPresent(QtUnlistedEnum.class))
return false;
return true;
}
private static Object isDesignable(Method declaredMethod, Class> clazz) {
QtPropertyDesignable designable = declaredMethod.getAnnotation(QtPropertyDesignable.class);
if (designable != null) {
String value = designable.value();
if (value.equals("true")) {
return Boolean.TRUE;
} else if (value.equals("false")) {
return Boolean.FALSE;
} else if(NativeLibraryManager.VERSION_MAJOR<6) {
try {
Method m = clazz.getMethod(value);
if (isBoolean(m.getReturnType()))
return m;
else
throw new RuntimeException("Wrong return type of designable method '" + m.getName() + "'");
} catch (Throwable t) {
java.util.logging.Logger.getLogger("io.qt.internal").log(java.util.logging.Level.SEVERE, "", t);
}
}
}
return Boolean.TRUE;
}
private static Object isScriptable(Method declaredMethod, Class> clazz) {
QtPropertyScriptable scriptable = declaredMethod.getAnnotation(QtPropertyScriptable.class);
if (scriptable != null) {
String value = scriptable.value();
if (value.equals("true")) {
return Boolean.TRUE;
} else if (value.equals("false")) {
return Boolean.FALSE;
} else if(NativeLibraryManager.VERSION_MAJOR<6) {
try {
Method m = clazz.getMethod(value);
if (isBoolean(m.getReturnType()))
return m;
else
throw new RuntimeException("Wrong return type of scriptable method '" + m.getName() + "'");
} catch (Throwable t) {
java.util.logging.Logger.getLogger("io.qt.internal").log(java.util.logging.Level.SEVERE, "", t);
}
}
}
return Boolean.TRUE;
}
private static Object isStored(Method declaredMethod, Class> clazz) {
QtPropertyStored stored = declaredMethod.getAnnotation(QtPropertyStored.class);
if (stored != null) {
String value = stored.value();
if (value.equals("true")) {
return Boolean.TRUE;
} else if (value.equals("false")) {
return Boolean.FALSE;
} else if(NativeLibraryManager.VERSION_MAJOR<6) {
try {
Method m = clazz.getMethod(value);
if (isBoolean(m.getReturnType()))
return m;
else
throw new RuntimeException("Wrong return type of scriptable method '" + m.getName() + "'");
} catch (Throwable t) {
java.util.logging.Logger.getLogger("io.qt.internal").log(java.util.logging.Level.SEVERE, "", t);
}
}
}
return Boolean.TRUE;
}
private static Object isEditable(Method declaredMethod, Class> clazz) {
/*
QtPropertyEditable editable = declaredMethod.getAnnotation(QtPropertyEditable.class);
if (editable != null) {
String value = editable.value();
if (value.equals("true")) {
return Boolean.TRUE;
} else if (value.equals("false")) {
return Boolean.FALSE;
} else try {
Method m = clazz.getMethod(value);
if (isBoolean(m.getReturnType()))
return m;
else
throw new RuntimeException("Wrong return type of scriptable method '" + m.getName() + "'");
} catch (Throwable t) {
java.util.logging.Logger.getLogger("io.qt.internal").log(java.util.logging.Level.SEVERE, "", t);
}
}
*/
return Boolean.TRUE;
}
private static boolean isValidSetter(Method declaredMethod) {
return (declaredMethod.getParameterCount() == 1
&& declaredMethod.getReturnType() == Void.TYPE
&& !internalTypeNameOfParameters(declaredMethod).equals(""));
}
private static Method getDeclaredMethod(Class> clazz, String name, Class> args[]) {
try {
return clazz.getDeclaredMethod(name, args);
} catch (NoSuchMethodException e) {
return null;
}
}
private static String capitalizeFirst(String str) {
return Character.toUpperCase(str.charAt(0)) + str.substring(1);
}
private static boolean isBoolean(Class> type) {
return (type == Boolean.class || type == Boolean.TYPE);
}
private static Object isUser(Method declaredMethod, Class> clazz) {
QtPropertyUser user = declaredMethod.getAnnotation(QtPropertyUser.class);
if (user != null) {
String value = user.value();
if (value.equals("true")) {
return Boolean.TRUE;
} else if (value.equals("false")) {
return Boolean.FALSE;
} else try {
Method m = clazz.getMethod(value);
if (isBoolean(m.getReturnType()))
return m;
else
throw new RuntimeException("Wrong return type of scriptable method '" + m.getName() + "'");
} catch (Throwable t) {
java.util.logging.Logger.getLogger("io.qt.internal").log(java.util.logging.Level.SEVERE, "", t);
}
}
return Boolean.FALSE;
}
private static Boolean isRequired(Method declaredMethod, Class> clazz) {
QtPropertyRequired required = declaredMethod.getAnnotation(QtPropertyRequired.class);
if (required != null) {
return required.value();
}
return Boolean.FALSE;
}
private static Boolean isFinal(Method declaredMethod) {
return Modifier.isFinal(declaredMethod.getModifiers());
}
private static Boolean isConstant(Method declaredMethod) {
QtPropertyConstant isConstant = declaredMethod.getAnnotation(QtPropertyConstant.class);
if (isConstant != null) {
return isConstant.value();
}
return Boolean.FALSE;
}
private static boolean isValidGetter(Method method) {
return (method.getParameterCount() == 0
&& method.getReturnType() != Void.TYPE);
}
private static String bunchOfClassNamesInARow(Class> classes[], Type[] genericTypes, AnnotatedType[] annotatedTypes, boolean cppName) {
List typeList = Collections.emptyList();
for (int i = 0; i < classes.length && i < genericTypes.length && i < annotatedTypes.length; i++) {
int arrayDimension = 0;
Class> type = classes[i];
Type genericType = genericTypes[i];
AnnotatedType annotatedType = annotatedTypes[i];
while (type.isArray()) {
arrayDimension++;
type = type.getComponentType();
if(genericType instanceof GenericArrayType) {
genericType = ((GenericArrayType) genericType).getGenericComponentType();
}else {
genericType = type;
}
}
boolean isPointer = annotatedType.isAnnotationPresent(QtPointerType.class);
QtReferenceType referenceType = annotatedType!=null ? annotatedType.getAnnotation(QtReferenceType.class) : null;
boolean isReference = !isPointer && referenceType!=null && !referenceType.isConst();
SignalParameterType signalType = new SignalParameterType(classes[i], type, genericType, annotatedType, arrayDimension, isPointer, isReference);
if(i==0) {
if(classes.length>1) {
typeList = new ArrayList<>();
typeList.add(signalType);
}else {
typeList = Collections.singletonList(signalType);
}
}else {
typeList.add(signalType);
}
}
return bunchOfClassNamesInARow(typeList, cppName);
}
static String bunchOfClassNamesInARow(QtJambiSignals.SignalParameterType type, boolean cppName) {
if(type.type==null)
return "";
String className = type.type.getName();
String arrays = "";
for (int j=0; j types, boolean cppName) {
String classNames = "";
for (int i=0; i methodTypes(AccessibleObject accessible) {
Class> returnType = null;
Type genericReturnType = null;
AnnotatedType annotatedReturnType = null;
Class>[] parameterTypes = null;
Type[] genericParameterTypes = null;
AnnotatedType[] annotatedParameterTypes = null;
if(accessible instanceof Method) {
Method m = (Method)accessible;
returnType = m.getReturnType();
genericReturnType = m.getGenericReturnType();
parameterTypes = m.getParameterTypes();
annotatedReturnType = m.getAnnotatedReturnType();
genericParameterTypes = m.getGenericParameterTypes();
annotatedParameterTypes = m.getAnnotatedParameterTypes();
}else if(accessible instanceof Constructor>) {
Constructor> c = (Constructor>)accessible;
returnType = void.class;
genericReturnType = void.class;
parameterTypes = c.getParameterTypes();
genericParameterTypes = c.getGenericParameterTypes();
annotatedParameterTypes = c.getAnnotatedParameterTypes();
}else if(accessible instanceof Field) {
Field f = (Field)accessible;
if(isValidQProperty(f)) {
MetaObjectTools.QPropertyTypeInfo propertyTypeInfo = getQPropertyTypeInfo(f);
if(propertyTypeInfo!=null) {
Class>[] cresult = new Class[1];
String[] qresult = new String[1];
cresult[0] = propertyTypeInfo.propertyType;
qresult[0] = internalTypeNameOfClass(propertyTypeInfo.propertyType, propertyTypeInfo.genericPropertyType);
if(propertyTypeInfo.isPointer) {
if(!qresult[0].endsWith("*")) {
qresult[0] += "*";
}
}
if(propertyTypeInfo.isReference) {
if(qresult[0].endsWith("*")) {
qresult[0] = qresult[0].substring(0, qresult[0].length()-2);
}
if(!qresult[0].endsWith("&")) {
qresult[0] += "&";
}
}
return new QPair<>(cresult, qresult);
}
}else if(QtJambiInternal.isSignalType(f.getType())) {
QtJambiInternal.ResolvedSignal resolvedSignal = QtJambiInternal.resolveSignal(f, f.getDeclaringClass());
Class>[] cresult = new Class[1+resolvedSignal.signalTypes.size()];
String[] qresult = new String[1+resolvedSignal.signalTypes.size()];
qresult[0] = "void";
cresult[0] = void.class;
for (int i = 0; i < resolvedSignal.signalTypes.size(); i++) {
cresult[i+1] = resolvedSignal.signalTypes.get(i).originalType;
qresult[i+1] = internalTypeNameOfClass(resolvedSignal.signalTypes.get(i).originalType, resolvedSignal.signalTypes.get(i).genericType);
if(resolvedSignal.signalTypes.get(i).isPointer) {
if(!qresult[i+1].endsWith("*")) {
qresult[i+1] += "*";
}
}
if(resolvedSignal.signalTypes.get(i).isReference) {
if(qresult[i+1].endsWith("*")) {
qresult[i+1] = qresult[i+1].substring(0, qresult[i+1].length()-2);
}
if(!qresult[i+1].endsWith("&")) {
qresult[i+1] += "&";
}
}
}
return new QPair<>(cresult, qresult);
}else {
Class>[] cresult = new Class[1];
String[] qresult = new String[1];
AnnotatedType annotatedType = f.getAnnotatedType();
boolean isPointer = annotatedType!=null && annotatedType.isAnnotationPresent(QtPointerType.class);
QtReferenceType referenceType = annotatedType!=null ? annotatedType.getAnnotation(QtReferenceType.class) : null;
boolean isReference = !isPointer && referenceType!=null && !referenceType.isConst();
cresult[0] = f.getType();
qresult[0] = internalTypeNameOfClass(f.getType(), f.getGenericType());
if(isPointer) {
if(!qresult[0].endsWith("*")) {
qresult[0] += "*";
}
}
if(isReference) {
if(qresult[0].endsWith("*")) {
qresult[0] = qresult[0].substring(0, qresult[0].length()-2);
}
if(!qresult[0].endsWith("&")) {
qresult[0] += "&";
}
}
return new QPair<>(cresult, qresult);
}
}
if(returnType!=null) {
Class>[] cresult = new Class[1+parameterTypes.length];
String[] qresult = new String[1+parameterTypes.length];
{
boolean isPointer = annotatedReturnType!=null && annotatedReturnType.isAnnotationPresent(QtPointerType.class);
QtReferenceType referenceType = annotatedReturnType!=null ? annotatedReturnType.getAnnotation(QtReferenceType.class) : null;
boolean isReference = !isPointer && referenceType!=null && !referenceType.isConst();
cresult[0] = returnType;
qresult[0] = internalTypeNameOfClass(returnType, genericReturnType);
if(isPointer) {
if(!qresult[0].endsWith("*")) {
qresult[0] += "*";
}
}
if(isReference) {
if(qresult[0].endsWith("*")) {
qresult[0] = qresult[0].substring(0, qresult[0].length()-2);
}
if(!qresult[0].endsWith("&")) {
qresult[0] += "&";
}
}
}
for (int i = 0; i < genericParameterTypes.length; i++) {
AnnotatedType annotatedType = annotatedParameterTypes[i];
boolean isPointer = annotatedType!=null && annotatedType.isAnnotationPresent(QtPointerType.class);
QtReferenceType referenceType = annotatedType!=null ? annotatedType.getAnnotation(QtReferenceType.class) : null;
boolean isReference = !isPointer && referenceType!=null && !referenceType.isConst();
cresult[i+1] = parameterTypes[i];
String typeName = internalTypeNameOfClass(parameterTypes[i], genericParameterTypes[i]);
if(isPointer) {
if(!typeName.endsWith("*")) {
typeName += "*";
}
}
if(isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
qresult[i+1] = typeName;
}
return new QPair<>(cresult, qresult);
}else {
return null;
}
}
/**
* Returns the signature of the method m excluding the modifiers and the
* return type.
*/
private static String methodSignature(Method m, boolean includeReturnType) {
return (includeReturnType ? m.getReturnType().getName() + " " : "")
+ m.getName() + "(" + methodParameters(m) + ")";
}
private static String constructorSignature(Constructor> m) {
return m.getName() + "(" + constructorParameters(m) + ")";
}
private static String methodSignature(QtJambiInternal.ResolvedSignal r) {
return r.field.getName() + "(" + bunchOfClassNamesInARow(r.signalTypes, false) + ")";
}
static String methodSignature(Method m) {
return methodSignature(m, false);
}
private static String shortConstructorSignature(Constructor> c) {
String name = c.getName();
int idx = name.lastIndexOf('.');
if(idx>0){
name = name.substring(idx+1, name.length());
}
return name + "(" + constructorParameters(c) + ")";
}
private static String constructorParameters(Constructor> c) {
return bunchOfClassNamesInARow(c.getParameterTypes(), c.getGenericParameterTypes(), c.getAnnotatedParameterTypes(), false);
}
private static QtJambiSignals.AbstractSignal lookupSignal(QtSignalEmitterInterface signalEmitter, String name, Class>[] requiredParameters) {
try {
if (name == null || signalEmitter == null) {
java.util.logging.Logger.getLogger("io.qt.internal").log(java.util.logging.Level.WARNING,
"lookupSignal: Name or object is null");
return null;
}
String parameters;
if (requiredParameters != null) {
return QtJambiInternal.findSignal((QtSignalEmitterInterface) signalEmitter, name, requiredParameters);
} else {
parameters = "";
int idx = name.indexOf("(");
if (idx >= 0) {
parameters = name.substring(idx).trim();
name = name.substring(0, idx);
}
}
String[] argumentTypes = {};
if (parameters != null && !parameters.isEmpty()) {
if (parameters.startsWith("(") && parameters.endsWith(")")) {
parameters = parameters.substring(1, parameters.length() - 1).trim();
if (!parameters.isEmpty()) {
argumentTypes = parameters.split("\\,");
for (int i = 0; i < argumentTypes.length; ++i)
argumentTypes[i] = argumentTypes[i].replace(" ", "");
}
}
}
Set visitedSignals = new HashSet<>();
for (Class> cls = signalEmitter.getClass(); QtSignalEmitterInterface.class
.isAssignableFrom(cls); cls = cls.getSuperclass()) {
try {
Field f = cls.getDeclaredField(name);
if (!java.lang.reflect.Modifier.isStatic(f.getModifiers())) {
List extends QtJambiSignals.AbstractSignal> signals = Collections.emptyList();
if (QtJambiSignals.AbstractSignal.class.isAssignableFrom(f.getType())) {
signals = Collections.singletonList((QtJambiSignals.AbstractSignal) QtJambiInternal.fetchField(signalEmitter, f));
} else if (QtJambiSignals.MultiSignal.class.isAssignableFrom(f.getType())) {
QtJambiSignals.MultiSignal multiSignal = (QtJambiSignals.MultiSignal) QtJambiInternal.fetchField(signalEmitter, f);
signals = multiSignal.signals();
}
visitedSignals.addAll(signals);
for (QtJambiSignals.AbstractSignal signal : signals) {
if (argumentTypes.length == 0 && signal.signalTypes().isEmpty()) {
return signal;
} else if (argumentTypes.length == signal.signalTypes().size()) {
List signalTypes = signal.signalTypes();
boolean matches = true;
for (int i = 0; i < signalTypes.size(); ++i) {
Class> t = signalTypes.get(i).type;
String arg = t.getName();
if (t.isArray()) {
String brackets = "";
do {
t = t.getComponentType();
brackets += "[]";
} while (t.isArray());
arg = t.getName() + brackets;
}
if (argumentTypes[i].indexOf('.') < 0) {
arg = arg.substring(arg.lastIndexOf('.') + 1);
}
String argLenient = t.isMemberClass() ? arg.replace('$', '.') : null;
if (!arg.equals(argumentTypes[i])
&& (argLenient == null || !argLenient.equals(argumentTypes[i]))) {
matches = false;
break;
}
}
if (matches) {
return signal;
}
}
}
}
} catch (NoSuchFieldException | SecurityException t) {
}
}
if (signalEmitter instanceof QObject) {
List listOfExtraSignal = QtJambiInternal.getListOfExtraSignal(QtJambiInternal.internalAccess.nativeId((QObject) signalEmitter));
visitedSignals.addAll(listOfExtraSignal);
for (AbstractSignal signal : listOfExtraSignal) {
if (signal.name().equals(name)) {
if (argumentTypes.length == 0 && signal.signalTypes().isEmpty()) {
return signal;
} else if (argumentTypes.length == signal.signalTypes().size()) {
List signalTypes = signal.signalTypes();
boolean matches = true;
for (int i = 0; i < signalTypes.size(); ++i) {
Class> t = signalTypes.get(i).type;
String arg = t.getName();
if (t.isArray()) {
String brackets = "";
do {
t = t.getComponentType();
brackets += "[]";
} while (t.isArray());
arg = t.getName() + brackets;
}
if (argumentTypes[i].indexOf('.') < 0) {
arg = arg.substring(arg.lastIndexOf('.') + 1);
}
String argLenient = t.isMemberClass() ? arg.replace('$', '.') : null;
if (!arg.equals(argumentTypes[i])
&& (argLenient == null || !argLenient.equals(argumentTypes[i]))) {
matches = false;
break;
}
}
if (matches) {
return signal;
}
}
}
}
for (QMetaMethod method : QMetaObject.forType(signalEmitter.getClass()).methods()) {
if (method.methodType() == QMetaMethod.MethodType.Signal) {
AbstractSignal signal = method.toSignal((QObject) signalEmitter);
if (signal != null && signal.name().equals(name) && !visitedSignals.contains(signal)) {
if (argumentTypes.length == 0 && signal.signalTypes().isEmpty()) {
return signal;
} else if (argumentTypes.length == signal.signalTypes().size()) {
List signalTypes = signal.signalTypes();
boolean matches = true;
for (int i = 0; i < signalTypes.size(); ++i) {
Class> t = signalTypes.get(i).type;
String arg = t.getName();
if (t.isArray()) {
String brackets = "";
do {
t = t.getComponentType();
brackets += "[]";
} while (t.isArray());
arg = t.getName() + brackets;
}
if (argumentTypes[i].indexOf('.') < 0) {
arg = arg.substring(arg.lastIndexOf('.') + 1);
}
String argLenient = t.isMemberClass() ? arg.replace('$', '.') : null;
if (!arg.equals(argumentTypes[i])
&& (argLenient == null || !argLenient.equals(argumentTypes[i]))) {
matches = false;
break;
}
}
if (matches) {
return signal;
}
}
}
}
}
}
return null;
} catch (RuntimeException | Error e) {
e.printStackTrace();
throw e;
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static String cppSignalSignature(QtSignalEmitterInterface signalEmitter, String signalName) {
QtJambiSignals.AbstractSignal signal = lookupSignal(signalEmitter, signalName, null);
if (signal != null) {
return cppSignalSignature(signal);
}else {
return "";
}
}
public static String cppNormalizedSignature(String signalName) {
int idx = signalName.indexOf("(");
if(idx>=0) {
String parameters = signalName.substring(idx).trim();
String name = signalName.substring(0, idx);
if(parameters.startsWith("(") && parameters.endsWith(")")) {
parameters = parameters.substring(1, parameters.length()-1).trim();
if(parameters.isEmpty()) {
return name+"()";
}else {
String[] argumentTypes = parameters.split("\\,");
name += "(";
for (int i = 0; i < argumentTypes.length; ++i) {
if(i>0) {
name += ",";
}
name += internalTypeName(argumentTypes[i].replace(" ", ""), MetaObjectTools.class.getClassLoader());
}
name += ")";
}
return name;
}
return signalName;
}else {
return signalName+"()";
}
}
public static String cppSignalSignature(String signal) {
if(signal.length()>0) {
if(signal.charAt(0)!=io.qt.internal.QtJambiInternal.SignalPrefix
&& signal.charAt(0)!=io.qt.internal.QtJambiInternal.SlotPrefix) {
signal = io.qt.internal.QtJambiInternal.SignalPrefix + signal;
}
}
return signal;
}
public static String cppSlotSignature(String slot) {
if(slot.length()>0) {
if(slot.charAt(0)!=io.qt.internal.QtJambiInternal.SignalPrefix
&& slot.charAt(0)!=io.qt.internal.QtJambiInternal.SlotPrefix) {
slot = io.qt.internal.QtJambiInternal.SlotPrefix + slot;
}
}
return slot;
}
public static String cppSignalSignature(QMetaObject.AbstractSignal signal) {
return cppSignalSignature((QtJambiSignals.AbstractSignal)signal);
}
static String cppSignalSignature(QtJambiSignals.AbstractSignal signal) {
QMetaMethod method = QMetaMethod.fromSignal((QMetaObject.AbstractSignal)signal);
if(method!=null && method.isValid() && method.methodType()==QMetaMethod.MethodType.Signal) {
return io.qt.internal.QtJambiInternal.SignalPrefix + method.cppMethodSignature().toString();
}
String signalParameters = bunchOfClassNamesInARow(signal.signalTypes(), true);
return io.qt.internal.QtJambiInternal.SignalPrefix + signal.name() + "(" + signalParameters + ")";
}
private static String signalParameters(QtJambiInternal.ResolvedSignal resolvedSignal) {
return bunchOfClassNamesInARow(resolvedSignal.signalTypes, false);
}
private static String internalTypeNameOfSignal(String s, ClassLoader classCoader) {
try {
return internalTypeName(s, classCoader);
} catch (Throwable t) {
return "";
}
}
private static String internalTypeNameOfParameters(Method declaredMethod) {
try {
String s = methodParameters(declaredMethod);
return internalTypeName(s, declaredMethod.getDeclaringClass().getClassLoader());
} catch (Throwable t) {
return "";
}
}
public static String internalTypeNameOfParameters(Constructor> declaredConstructor) {
try {
String s = constructorParameters(declaredConstructor);
return internalTypeName(s, declaredConstructor.getDeclaringClass().getClassLoader());
} catch (Throwable t) {
return "";
}
}
public static String internalTypeNameOfMethodSignature(Constructor> constructor) {
try {
String javaMethodSignature = shortConstructorSignature(constructor);
return internalTypeName(javaMethodSignature, constructor.getDeclaringClass().getClassLoader());
} catch (Throwable t) {
return "";
}
}
private static Class> getBoxedType(Class> type){
if(type.isPrimitive()) {
if(int.class==type) {
type = Integer.class;
}else if(byte.class==type) {
type = Byte.class;
}else if(short.class==type) {
type = Short.class;
}else if(long.class==type) {
type = Long.class;
}else if(double.class==type) {
type = Double.class;
}else if(float.class==type) {
type = Float.class;
}else if(boolean.class==type) {
type = Boolean.class;
}else if(char.class==type) {
type = Character.class;
}
}
return type;
}
/**
* this method creates Qt5 meta object data from the submitted class.
* It is based upon code of the moc tool.
*/
@NativeAccess
private static MetaData buildMetaData(Class> clazz) {
try {
if(clazz.isPrimitive() || clazz.isArray() || clazz.isSynthetic() || clazz.getName().contains("$Lamda$")) {
return null;
}
MetaData metaData = new MetaData();
metaData.stringData.add("Reserving the first string for QDynamicMetaObject identification.");
List intdataComments = /*new ArrayList<>();*/new AbstractList() {
@Override
public boolean add(String e) { return false; }
@Override
public String get(int index) {return null;}
@Override
public int size() {return 0; }
};
final String classname = clazz.getName().replace(".", "::");
metaData.stringData.add(classname);
Hashtable classInfos = new Hashtable();
for(QtClassInfo info : clazz.getAnnotationsByType(QtClassInfo.class)) {
classInfos.put(info.key(), info.value());
}
for(Map.Entry entry : classInfos.entrySet()){
metaData.stringData.add(entry.getKey());
metaData.stringData.add(entry.getValue());
}
List slots = new ArrayList();
List methods = new ArrayList();
List originalSignatures = new ArrayList();
TreeMap propertyReaders = new TreeMap<>();
TreeMap> propertyWriters = new TreeMap<>();
TreeMap propertyDesignableResolvers = new TreeMap<>();
TreeMap propertyScriptableResolvers = new TreeMap<>();
TreeMap propertyEditableResolvers = new TreeMap<>();
TreeMap propertyStoredResolvers = new TreeMap<>();
TreeMap propertyUserResolvers = new TreeMap<>();
TreeMap propertyRequiredResolvers = new TreeMap<>();
TreeMap propertyConstantResolvers = new TreeMap<>();
TreeMap propertyFinalResolvers = new TreeMap<>();
TreeMap propertyResetters = new TreeMap<>();
TreeMap propertyNotifies = new TreeMap<>();
TreeMap propertyBindables = new TreeMap<>();
TreeMap propertyMembers = new TreeMap<>();
TreeMap propertyQPropertyFields = new TreeMap<>();
// First we get all enums actually declared in the class
Hashtable> enums = new Hashtable>();
queryEnums(clazz, enums);
List resolvedSignals = new ArrayList<>();
// cl.getEnclosingClass() != QInstanceMemberSignals.class
boolean isQObject = QObject.class.isAssignableFrom(clazz);
// if(QObject.class.isAssignableFrom(clazz))
{
Field declaredFields[] = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
if(QtJambiInternal.isSignalType(declaredField.getType())) {
if (!Modifier.isStatic(declaredField.getModifiers())) {
if(!isQObject && declaredField.getType().getEnclosingClass() == QObject.class) {
throw new QSignalDeclarationException(String.format("Declaration error at signal %1$s.%2$s: do not use QObject signals within non-QObjects.", clazz.getSimpleName(), declaredField.getName()));
}
// If we can't convert all the types we don't list the signal
QtJambiInternal.ResolvedSignal resolvedSignal = QtJambiInternal.resolveSignal(declaredField, declaredField.getDeclaringClass());
String signalParameters = signalParameters(resolvedSignal);
if (signalParameters.length() == 0 || internalTypeNameOfSignal(signalParameters, clazz.getClassLoader()).length() != 0) {
if (!Modifier.isFinal(declaredField.getModifiers())) {
if(!Boolean.getBoolean("qtjambi.allow-nonfinal-signals") && !Boolean.getBoolean("io.qt.allow-nonfinal-signals")) {
java.util.logging.Logger.getLogger("io.qt.internal").severe(String.format("Missing modifier 'final' at signal %1$s.%2$s. Specify JVM argument -Dqtjambi.allow-nonfinal-signals=true to disable this error.", clazz.getSimpleName(), declaredField.getName()));
throw new QSignalDeclarationException(String.format("Missing modifier 'final' at signal %1$s.%2$s.", clazz.getSimpleName(), declaredField.getName()));
}
}
metaData.signalFields.add(declaredField);
resolvedSignals.add(resolvedSignal);
originalSignatures.add(methodSignature(resolvedSignal));
metaData.stringData.add(resolvedSignal.field.getName());
for (int i = 1; i <= resolvedSignal.signalTypes.size(); i++) {
QtJambiSignals.SignalParameterType signalType = resolvedSignal.signalTypes.get(i-1);
String typeName;
if(signalType.arrayDimension==0){
typeName = internalTypeNameOfClass(signalType.type, signalType.genericType);
}else{
typeName = internalTypeNameOfClass(signalType.originalType, signalType.originalType);
}
if(signalType.isPointer) {
if(!typeName.endsWith("*")) {
typeName += "*";
}
}
if(signalType.isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
QMetaType.Type type = metaType(typeName);
if(type==QMetaType.Type.UnknownType || type==QMetaType.Type.User){
metaData.stringData.add(typeName);
}
metaData.stringData.add("arg__"+i);
}
metaData.stringData.add(""); // for the method tag
// Rules for resetters:
// 1. Zero or one argument
if(resolvedSignal.signalTypes.size() <= 1){
PropertyAnnotation notify = PropertyAnnotation.notifyAnnotation(declaredField);
if (notify != null) {
propertyNotifies.put(notify.name(), declaredField);
}
}
}
}else {
throw new QSignalDeclarationException(String.format("Modifier 'static' not allowed for signal %1$s.%2$s. Use QStaticMemberSignals instead to declare a static signal.", clazz.getSimpleName(), declaredField.getName()));
}
}else{
PropertyAnnotation member = PropertyAnnotation.memberAnnotation(declaredField);
if(member!=null) {
if(member.enabled()) {
propertyMembers.put(member.name(), declaredField);
}
}else if(isQObject && isValidQProperty(declaredField)) {
propertyQPropertyFields.put(declaredField.getName(), declaredField);
}
}
}
}
// if(QObject.class.isAssignableFrom(clazz))
{
cloop: for(Constructor> constructor : clazz.getDeclaredConstructors()){
if(!constructor.isSynthetic() && constructor.isAnnotationPresent(QtInvokable.class)) {
Class>[] parameterTypes = constructor.getParameterTypes();
for (Class> parameterType : parameterTypes) {
if(parameterType==PrivateConstructorAccess.type()) {
continue cloop;
}
}
metaData.constructors.add(constructor);
metaData.hasStaticMembers = true;
originalSignatures.add(constructorSignature(constructor));
Parameter[] parameters = constructor.getParameters();
Type[] genericParameterTypes = constructor.getGenericParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
String typeName = internalTypeNameOfClass(parameterTypes[i], genericParameterTypes[i]);
QMetaType.Type type = metaType(typeName);
if(type==QMetaType.Type.UnknownType || type==QMetaType.Type.User){
metaData.stringData.add(typeName);
}
if(parameters[i].isNamePresent()) {
metaData.stringData.add(parameters[i].getName());
}else {
metaData.stringData.add("arg__"+(i+1));
}
}
metaData.stringData.add("");
}
}
}
List possibleBindables = Collections.emptyList();
for (Method declaredMethod : clazz.getDeclaredMethods()) {
if(declaredMethod.isSynthetic()
|| declaredMethod.isBridge()) {
continue;
}
if (
(
(
QObject.class.isAssignableFrom(clazz)
&& !declaredMethod.isAnnotationPresent(QtUninvokable.class)
&& !Modifier.isStatic(declaredMethod.getModifiers())
) || (
declaredMethod.isAnnotationPresent(QtInvokable.class)
&& declaredMethod.getAnnotation(QtInvokable.class).value()
)
)
&& !overridesGeneratedSlot(declaredMethod, clazz)
) {
// If we can't convert the type, we don't list it
String methodParameters = methodParameters(declaredMethod);
String returnType = declaredMethod.getReturnType().getName();
String returnTypeName = internalTypeNameOfClass(declaredMethod.getReturnType(), declaredMethod.getGenericReturnType());
if(returnTypeName.startsWith("QQmlListProperty<") && QtJambiInternal.findMetaType(returnTypeName)==QMetaType.Type.UnknownType.value()) {
registerQmlListProperty(returnTypeName);
}
QtReferenceType referenceType = declaredMethod.getAnnotatedReturnType().getAnnotation(QtReferenceType.class);
if(referenceType==null)
declaredMethod.getAnnotation(QtReferenceType.class);
if(declaredMethod.getAnnotatedReturnType().isAnnotationPresent(QtPointerType.class)) {
if(!returnTypeName.endsWith("*")) {
returnTypeName += "*";
}
}else if(referenceType!=null && !referenceType.isConst()) {
if(returnTypeName.endsWith("*")) {
returnTypeName = returnTypeName.substring(0, returnTypeName.length()-2);
}
if(!returnTypeName.endsWith("&")) {
returnTypeName += "&";
}
}
if ((methodParameters.equals("") || !internalTypeNameOfParameters(declaredMethod).equals(""))
&&(returnType.equals("") || returnType.equals("void") || !returnTypeName.equals(""))) {
String methodSignature = methodSignature(declaredMethod);
if(!originalSignatures.contains(methodSignature)) {
if(Modifier.isStatic(declaredMethod.getModifiers())){
methods.add(declaredMethod);
metaData.hasStaticMembers = true;
}else{
if(!QObject.class.isAssignableFrom(clazz)) {
// we need to make sure that static_metacall is set
metaData.hasStaticMembers = true;
}
slots.add(declaredMethod);
}
originalSignatures.add(methodSignature);
metaData.stringData.add(declaredMethod.getName());
metaData.stringData.add(returnTypeName);
Parameter[] parameters = declaredMethod.getParameters();
Class>[] parameterTypes = declaredMethod.getParameterTypes();
Type[] genericParameterTypes = declaredMethod.getGenericParameterTypes();
AnnotatedType[] annotatedParameterTypes = declaredMethod.getAnnotatedParameterTypes();
for (int i = 1; i <= parameterTypes.length; i++) {
String typeName = internalTypeNameOfClass(parameterTypes[i-1], genericParameterTypes[i-1]);
if(annotatedParameterTypes[i-1].isAnnotationPresent(QtPointerType.class)) {
if(!typeName.endsWith("*")) {
typeName += "*";
}
}
QtReferenceType _referenceType = annotatedParameterTypes[i-1].getAnnotation(QtReferenceType.class);
if(_referenceType!=null && !_referenceType.isConst()) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
QMetaType.Type type = metaType(typeName);
if(type==QMetaType.Type.UnknownType || type==QMetaType.Type.User){
metaData.stringData.add(typeName);
}
if(parameters[i-1].isNamePresent()) {
metaData.stringData.add(parameters[i-1].getName());
}else {
metaData.stringData.add("arg__"+i);
}
}
metaData.stringData.add(""); // for the method tag
}
}
}
final String declaredMethodName = declaredMethod.getName();
// Rules for readers:
// 1. Zero arguments
// 2. Return something other than void
// 3. We can convert the type
PropertyAnnotation reader = PropertyAnnotation.readerAnnotation(declaredMethod);
{
if (
(reader != null && reader.enabled())
&& isValidGetter(declaredMethod)
&& !internalTypeNameOfClass(declaredMethod.getReturnType(), declaredMethod.getGenericReturnType()).equals("")) {
String name = reader.name();
// If the return type of the property reader is not registered, then
// we need to register the owner class in the meta object (in which case
// it has to be a QObject)
Class> returnType = declaredMethod.getReturnType();
if ( (QFlags.class.isAssignableFrom(returnType) || Enum.class.isAssignableFrom(returnType))
&& !isEnumAllowedForProperty(returnType) ) {
int type = registerMetaType(returnType);
if(type==QMetaType.Type.UnknownType.value()) {
System.err.println("Problem in property '" + name + "' in '" + clazz.getName()
+ "' with return type '"+returnType.getName()
+"': Unable to register meta type.");
continue;
}
}
propertyReaders.put(name, declaredMethod);
propertyDesignableResolvers.put(name, isDesignable(declaredMethod, clazz));
propertyScriptableResolvers.put(name, isScriptable(declaredMethod, clazz));
propertyEditableResolvers.put(name, isEditable(declaredMethod, clazz));
propertyStoredResolvers.put(name, isStored(declaredMethod, clazz));
propertyUserResolvers.put(name, isUser(declaredMethod, clazz));
propertyRequiredResolvers.put(name, isRequired(declaredMethod, clazz));
propertyConstantResolvers.put(name, isConstant(declaredMethod));
propertyFinalResolvers.put(name, isFinal(declaredMethod));
metaData.stringData.add(name);
}
}
// Rules for writers:
// 1. Takes exactly one argument
// 2. Return void
// 3. We can convert the type
PropertyAnnotation writer = PropertyAnnotation.writerAnnotation(declaredMethod);
{
if ( writer != null
&& writer.enabled()
&& isValidSetter(declaredMethod)) {
propertyWriters.computeIfAbsent(writer.name(), name->new ArrayList<>()).add(declaredMethod);
}
}
// Check naming convention by looking for setXxx patterns, but only if it hasn't already been
// annotated as a writer
if (QObject.class.isAssignableFrom(clazz)
&& writer == null
&& reader == null // reader can't be a writer, cause the signature doesn't match, just an optimization
&& declaredMethodName.startsWith("set")
&& declaredMethodName.length() > 3
&& Character.isUpperCase(declaredMethodName.charAt(3))
&& isValidSetter(declaredMethod)) {
Class> paramType = declaredMethod.getParameterTypes()[0];
String propertyName = Character.toLowerCase(declaredMethodName.charAt(3))
+ declaredMethodName.substring(4);
if (!propertyReaders.containsKey(propertyName)) {
// We need a reader as well, and the reader must not be annotated as disabled
// The reader can be called 'xxx', 'getXxx', 'isXxx' or 'hasXxx'
// (just booleans for the last two)
Method readerMethod = notBogus(getDeclaredMethod(clazz, propertyName, null), propertyName, paramType);
if (readerMethod == null)
readerMethod = notBogus(getDeclaredMethod(clazz, "get" + capitalizeFirst(propertyName), null), propertyName, paramType);
if (readerMethod == null && isBoolean(paramType))
readerMethod = notBogus(getDeclaredMethod(clazz, "is" + capitalizeFirst(propertyName), null), propertyName, paramType);
if (readerMethod == null && isBoolean(paramType))
readerMethod = notBogus(getDeclaredMethod(clazz, "has" + capitalizeFirst(propertyName), null), propertyName, paramType);
if (readerMethod != null) { // yay
reader = PropertyAnnotation.readerAnnotation(readerMethod);
if (reader == null) {
propertyReaders.put(propertyName, readerMethod);
propertyWriters.computeIfAbsent(propertyName, name->new ArrayList<>()).add(declaredMethod);
propertyDesignableResolvers.put(propertyName, isDesignable(readerMethod, clazz));
propertyScriptableResolvers.put(propertyName, isScriptable(readerMethod, clazz));
propertyUserResolvers.put(propertyName, isUser(readerMethod, clazz));
propertyRequiredResolvers.put(propertyName, isRequired(readerMethod, clazz));
}
}
}
}
// Rules for notifys:
// 1. No arguments
// 2. Return void
{
PropertyAnnotation resetter = PropertyAnnotation.resetterAnnotation(declaredMethod);
if (resetter != null
&& declaredMethod.getParameterCount() == 0
&& declaredMethod.getReturnType() == void.class) {
propertyResetters.put(resetter.name(), declaredMethod);
}
}
if(isValidBindable(declaredMethod)) {
PropertyAnnotation bindables = PropertyAnnotation.bindableAnnotation(declaredMethod);
if (bindables != null) {
propertyBindables.put(bindables.name(), declaredMethod);
}else{
if(possibleBindables.isEmpty())
possibleBindables = new ArrayList<>();
possibleBindables.add(declaredMethod);
}
}
}
for(Method possibleBindable : possibleBindables) {
String name = possibleBindable.getName();
if(name.startsWith("bindable") && name.length() > 8) {
name = PropertyAnnotation.removeAndLowercaseFirst(name, 8);
if (propertyReaders.containsKey(name)) {
propertyBindables.put(name, possibleBindable);
}
}
}
{
TreeMap _propertyQPropertyFields = new TreeMap<>(propertyQPropertyFields);
propertyQPropertyFields.clear();
for(Map.Entry entry : _propertyQPropertyFields.entrySet()) {
String name = entry.getKey();
if(name.endsWith("Prop")) {
name = name.substring(0, name.length()-4);
}else if(name.endsWith("Property")) {
name = name.substring(0, name.length()-8);
}
if(!propertyReaders.containsKey(entry.getKey())
&& !propertyReaders.containsKey(name)
&& !Modifier.isStatic(entry.getValue().getModifiers())
&& Modifier.isFinal(entry.getValue().getModifiers())
&& Modifier.isPublic(entry.getValue().getModifiers())) {
propertyReaders.put(name, null);
propertyQPropertyFields.put(name, entry.getValue());
}
}
}
for(String prop : propertyMembers.keySet()) {
if(!propertyReaders.containsKey(prop)) {
propertyReaders.put(prop, null);
}
}
for(String property : propertyReaders.keySet()) {
if(propertyNotifies.get(property)==null) {
for(QtJambiInternal.ResolvedSignal resolvedSignal : resolvedSignals) {
if(resolvedSignal.field.getName().equals(property+"Changed")) {
if(resolvedSignal.signalTypes.isEmpty()) {
propertyNotifies.put(property, resolvedSignal.field);
}else {
if(propertyReaders.get(property)!=null) {
if(resolvedSignal.signalTypes.get(0).originalType.isAssignableFrom(getBoxedType(propertyReaders.get(property).getReturnType()))) {
propertyNotifies.put(property, resolvedSignal.field);
}
}else if(propertyMembers.get(property)!=null) {
Field field = propertyMembers.get(property);
if(isValidQProperty(field)) {
MetaObjectTools.QPropertyTypeInfo pinfo = getQPropertyTypeInfo(field);
if(resolvedSignal.signalTypes.get(0).originalType.isAssignableFrom(getBoxedType(pinfo.propertyType))) {
propertyNotifies.put(property, resolvedSignal.field);
}
}else if(resolvedSignal.signalTypes.get(0).originalType.isAssignableFrom(getBoxedType(field.getType()))) {
propertyNotifies.put(property, resolvedSignal.field);
}
}else if(propertyQPropertyFields.get(property)!=null) {
MetaObjectTools.QPropertyTypeInfo pinfo = getQPropertyTypeInfo(propertyQPropertyFields.get(property));
if(resolvedSignal.signalTypes.get(0).originalType.isAssignableFrom(getBoxedType(pinfo.propertyType))) {
propertyNotifies.put(property, resolvedSignal.field);
}
}
}
break;
}
}
}
}
metaData.methods.addAll(slots);
metaData.methods.addAll(methods);
int flagsIndex = 0;
{
// Until 4.7.x QtJambi used revision=1 however due to a change in the way
// 4.7.x works some features of QtJambi stopped working.
// revision 1 = MO_HEADER_LEN=10
// revision 2 (4.5.x) = MO_HEADER_LEN=12 (added: constructorCount, constructorData)
// revision 3 = MO_HEADER_LEN=13 (added: flags)
// revision 4 (4.6.x) = MO_HEADER_LEN=14 (added: signalCount)
// revision 5 (4.7.x) = MO_HEADER_LEN=14 (normalization)
// revision 6 (4.8.x) = MO_HEADER_LEN=14 (added support for qt_static_metacall)
// revision 7 (5.0.x) = MO_HEADER_LEN=14 (Qt5 to break backwards compatibility)
// The format is compatible to share the same encoding code
// then we can change the revision to suit the Qt
/// implementation we are working with.
final int MO_HEADER_LEN = 14; // header size
// revision
metaData.metaData.add(resolveMetaDataRevision()); intdataComments.add("revision");
// classname
metaData.metaData.add(metaData.stringData.indexOf(classname)); intdataComments.add("className");
// classinfo
metaData.metaData.add(classInfos.size()); intdataComments.add("classInfoCount");
metaData.metaData.add(classInfos.isEmpty() ? 0 : MO_HEADER_LEN); intdataComments.add("classInfoData");
// methods
int methodCount = metaData.signalFields.size() + slots.size() + methods.size();
metaData.metaData.add(methodCount); intdataComments.add("methodCount");
final int METHOD_METADATA_INDEX = metaData.metaData.size();
metaData.metaData.add(0); intdataComments.add("methodData");
// properties
metaData.metaData.add(propertyReaders.size()); intdataComments.add("propertyCount");
final int PROPERTY_METADATA_INDEX = metaData.metaData.size();
metaData.metaData.add(0); intdataComments.add("propertyData");
// enums/sets
metaData.metaData.add(enums.size()); intdataComments.add("enumeratorCount");
final int ENUM_METADATA_INDEX = metaData.metaData.size();
metaData.metaData.add(0); intdataComments.add("enumeratorData");
// constructors
metaData.metaData.add(!metaData.constructors.isEmpty() ? metaData.constructors.size() : 0); intdataComments.add("constructorCount");
final int CONSTRUCTOR_METADATA_INDEX = metaData.metaData.size();
metaData.metaData.add(0); intdataComments.add("constructorData");
// flags
flagsIndex = metaData.metaData.size();
metaData.metaData.add(0); intdataComments.add("flags");
// signalCount
metaData.metaData.add(metaData.signalFields.size()); intdataComments.add("signalCount");
//
// Build classinfo array
//
for(Map.Entry entry : classInfos.entrySet()){
// classinfo: key, value
metaData.metaData.add(metaData.stringData.indexOf(entry.getKey())); intdataComments.add("classinfo: key");
metaData.metaData.add(metaData.stringData.indexOf(entry.getValue())); intdataComments.add("classinfo: value");
}
HashMap
© 2015 - 2025 Weber Informatics LLC | Privacy Policy