io.qt.internal.MetaObjectTools Maven / Gradle / Ivy
The newest version!
/****************************************************************************
**
** Copyright (C) 1992-2009 Nokia. All rights reserved.
** Copyright (C) 2009-2022 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.registerRefMetaType;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
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.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.logging.Logger;
import io.qt.NativeAccess;
import io.qt.QFlags;
import io.qt.QSignalDeclarationException;
import io.qt.QSignalInitializationException;
import io.qt.QtByteEnumerator;
import io.qt.QtClassInfo;
import io.qt.QtEnumerator;
import io.qt.QtInvokable;
import io.qt.QtLongEnumerator;
import io.qt.QtMetaType;
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.QtUninvokable;
import io.qt.QtUnlistedEnum;
import io.qt.core.QDeclarableSignals;
import io.qt.core.QMetaObject;
import io.qt.core.QMetaType;
import io.qt.core.QObject;
import io.qt.core.QPair;
import io.qt.core.QStaticMemberSignals;
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 static class DeclarativeConstructorAccess extends io.qt.core.QObject{
static Class> type(){
return QDeclarativeConstructor.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;
}
}
@NativeAccess
static class SignalInfo{
SignalInfo(Field field, List signalTypes, Class> signalClass, int[] signalMetaTypes, long methodId) {
super();
this.field = field;
this.signalTypes = Collections.unmodifiableList(signalTypes);
this.signalClass = signalClass;
this.signalMetaTypes = signalMetaTypes;
this.methodId = methodId;
}
final @NativeAccess Field field;
final @NativeAccess List signalTypes;
final @NativeAccess Class> signalClass;
final @NativeAccess int[] signalMetaTypes;
final @NativeAccess long methodId;
}
@NativeAccess
private static class MetaData {
int addStringData(String data) {
int index = stringData.indexOf(data);
if(index<0) {
index = stringData.size();
stringData.add(data);
}
return index;
}
final @NativeAccess List metaData = new ArrayList<>();
final @NativeAccess List stringData = new StringList();
final @NativeAccess List signalInfos = new ArrayList<>();
final @NativeAccess List methods = new ArrayList<>();
final @NativeAccess List methodMetaTypes = new ArrayList<>();
final @NativeAccess List> constructors = new ArrayList<>();
final @NativeAccess List constructorMetaTypes = 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 propertyMetaTypes = new ArrayList<>();
final @NativeAccess List> propertyClassTypes = 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);
Object[] enumConstants = enumType.getEnumConstants();
enumConstantCount = enumConstants==null ? 0 : enumConstants.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.equalsIgnoreCase("true")) {
return Boolean.TRUE;
} else if (value.equalsIgnoreCase("false")) {
return Boolean.FALSE;
} else if(QtJambiInternal.majorVersion()<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.equalsIgnoreCase("true")) {
return Boolean.TRUE;
} else if (value.equalsIgnoreCase("false")) {
return Boolean.FALSE;
} else if(QtJambiInternal.majorVersion()<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.equalsIgnoreCase("true")) {
return Boolean.TRUE;
} else if (value.equalsIgnoreCase("false")) {
return Boolean.FALSE;
} else if(QtJambiInternal.majorVersion()<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) {
return Boolean.TRUE;
}
private static boolean isValidSetter(Method declaredMethod) {
return (declaredMethod.getParameterCount() == 1
&& declaredMethod.getReturnType() == Void.TYPE);
}
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.equalsIgnoreCase("true")) {
return Boolean.TRUE;
} else if (value.equalsIgnoreCase("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 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.addStringData("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(".", "::");
Hashtable classInfos = new Hashtable();
for(QtClassInfo info : clazz.getAnnotationsByType(QtClassInfo.class)) {
classInfos.put(info.key(), info.value());
}
Map methodFlags = new HashMap<>();
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);
class ParameterInfo{
public ParameterInfo(int metaTypeId, String typeName) {
super();
this.type = null;
this.metaTypeId = metaTypeId;
this.typeName = typeName;
}
public ParameterInfo(io.qt.core.QMetaType.Type type) {
super();
this.type = type;
this.metaTypeId = 0;
this.typeName = null;
}
final QMetaType.Type type;
final int metaTypeId;
final String typeName;
}
Set addedMethodSignatures = new TreeSet<>();
List signalIsClone = new ArrayList<>();
List> allSignalParameterInfos = new ArrayList<>();
// cl.getEnclosingClass() != QInstanceMemberSignals.class
boolean isQObject = QObject.class.isAssignableFrom(clazz);
// if(QObject.class.isAssignableFrom(clazz))
{
TreeSet declaredFields = new TreeSet<>((m1, m2)->{
return m1.getName().compareTo(m2.getName());
});
declaredFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
signalLoop: for (Field declaredField : declaredFields) {
Class> signalClass = declaredField.getType();
if(isQObjectSignalType(signalClass)) {
if (!Modifier.isStatic(declaredField.getModifiers())) {
if(!isQObject && signalClass.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
List> emitParameterTypes = new ArrayList<>();
List signalTypes = new ArrayList<>(QtJambiSignals.resolveSignal(declaredField));
List cppTypes = new ArrayList<>();
List signalParameterInfos = new ArrayList<>();
for (int j = 0; j < signalTypes.size(); j++) {
emitParameterTypes.add(Object.class);
QtJambiSignals.SignalParameterType signalType = signalTypes.get(j);
QtMetaType metaTypeDecl = signalType.annotatedType.getAnnotation(QtMetaType.class);
int metaTypeId = 0;
String typeName;
if(metaTypeDecl!=null) {
if(metaTypeDecl.id()!=0) {
metaTypeId = metaTypeDecl.id();
if(signalType.isPointer || signalType.isReference) {
metaTypeId = registerRefMetaType(metaTypeId, signalType.isPointer, signalType.isReference);
}
typeName = new QMetaType(metaTypeId).name().toString();
}else if(metaTypeDecl.type()!=QMetaType.Type.UnknownType){
metaTypeId = metaTypeDecl.type().value();
if(signalType.isPointer || signalType.isReference) {
metaTypeId = registerRefMetaType(metaTypeId, signalType.isPointer, signalType.isReference);
}
typeName = new QMetaType(metaTypeId).name().toString();
}else {
if(metaTypeDecl.name().isEmpty())
throw new IllegalArgumentException("Incomplete @QtMetaType declaration. Either use type, id or name to specify meta type.");
typeName = metaTypeDecl.name();
if(signalType.isPointer && !typeName.endsWith("*")) {
typeName += "*";
}
if(signalType.isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
}
}else{
typeName = internalTypeNameOfClass(signalType.type, signalType.genericType);
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){
if(metaTypeId==QMetaType.Type.UnknownType.value()) {
metaTypeId = QtJambiInternal.findMetaType(typeName);
if(metaTypeId==QMetaType.Type.UnknownType.value() || !(signalType.genericType instanceof Class || new QMetaType(metaTypeId).name().toString().equals(typeName))) {
metaTypeId = registerMetaType(signalType.type, signalType.genericType, null, signalType.isPointer, signalType.isReference);
}
if(metaTypeId!=QMetaType.Type.UnknownType.value())
typeName = new QMetaType(metaTypeId).name().toString();
else
continue signalLoop;
}
cppTypes.add(typeName);
signalParameterInfos.add(new ParameterInfo(metaTypeId, typeName));
}else{
cppTypes.add(new QMetaType(type).name().toString());
signalParameterInfos.add(new ParameterInfo(type));
}
}
long methodId = findEmitMethodId(signalClass, emitParameterTypes);
String methodSignature = String.format("%1$s(%2$s)", declaredField.getName(), String.join(", ", cppTypes));
if(!addedMethodSignatures.contains(methodSignature) && methodId!=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()));
}
}
// Rules for resetters:
// 1. Zero or one argument
if(signalTypes.size() <= 1){
PropertyAnnotation notify = PropertyAnnotation.notifyAnnotation(declaredField);
if (notify != null) {
propertyNotifies.put(notify.name(), declaredField);
}
}
addedMethodSignatures.add(methodSignature);
signalIsClone.add(Boolean.FALSE);
allSignalParameterInfos.add(new ArrayList<>(signalParameterInfos));
metaData.signalInfos.add(new SignalInfo(declaredField, new ArrayList<>(signalTypes), signalClass, new int[signalTypes.size()], methodId));
Runnable addDefaultSignal = ()->{
signalTypes.remove(signalTypes.size()-1);
signalParameterInfos.remove(signalParameterInfos.size()-1);
cppTypes.remove(cppTypes.size()-1);
emitParameterTypes.remove(emitParameterTypes.size()-1);
long _methodId = findEmitMethodId(signalClass, emitParameterTypes);
String _methodSignature = String.format("%1$s(%2$s)", declaredField.getName(), String.join(", ", cppTypes));
if(!addedMethodSignatures.contains(_methodSignature) && _methodId!=0) {
addedMethodSignatures.add(_methodSignature);
signalIsClone.add(Boolean.TRUE);
allSignalParameterInfos.add(new ArrayList<>(signalParameterInfos));
metaData.signalInfos.add(new SignalInfo(declaredField, new ArrayList<>(signalTypes), signalClass, new int[signalTypes.size()], _methodId));
}
};
switch(signalTypes.size()) {
case 9:
if(QMetaObject.Emitable8.class.isAssignableFrom(signalClass)) {
addDefaultSignal.run();
}else break;
case 8:
if(QMetaObject.Emitable7.class.isAssignableFrom(signalClass)) {
addDefaultSignal.run();
}else break;
case 7:
if(QMetaObject.Emitable6.class.isAssignableFrom(signalClass)) {
addDefaultSignal.run();
}else break;
case 6:
if(QMetaObject.Emitable5.class.isAssignableFrom(signalClass)) {
addDefaultSignal.run();
}else break;
case 5:
if(QMetaObject.Emitable4.class.isAssignableFrom(signalClass)) {
addDefaultSignal.run();
}else break;
case 4:
if(QMetaObject.Emitable3.class.isAssignableFrom(signalClass)) {
addDefaultSignal.run();
}else break;
case 3:
if(QMetaObject.Emitable2.class.isAssignableFrom(signalClass)) {
addDefaultSignal.run();
}else break;
case 2:
if(QMetaObject.Emitable1.class.isAssignableFrom(signalClass)) {
addDefaultSignal.run();
}else break;
case 1:
if(QMetaObject.Emitable0.class.isAssignableFrom(signalClass)) {
addDefaultSignal.run();
}else break;
}
}
}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 if(isQObject && QtJambiSignals.AbstractMultiSignal.class.isAssignableFrom(signalClass) && QObject.class!=signalClass.getEnclosingClass()) {
if(Modifier.isStatic(declaredField.getModifiers()))
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()));
if(declaredField.getDeclaringClass()!=signalClass.getEnclosingClass())
throw new QSignalDeclarationException(String.format("Declaration error at signal %1$s.%2$s: Multi signal class has to be declared in the class using it.", clazz.getSimpleName(), declaredField.getName()));
if(!Modifier.isFinal(signalClass.getModifiers()))
throw new QSignalDeclarationException(String.format("Missing modifier 'final' at signal class %1$s.", signalClass.getTypeName()));
if (!Modifier.isFinal(declaredField.getModifiers()))
throw new QSignalDeclarationException(String.format("Missing modifier 'final' at signal %1$s.%2$s.", clazz.getSimpleName(), declaredField.getName()));
Map>,QtJambiSignals.EmitMethodInfo> emitMethods = QtJambiSignals.findEmitMethods(signalClass);
if(emitMethods.keySet().isEmpty())
throw new QSignalDeclarationException(String.format("Missing modifier emit methods at signal class %1$s.", signalClass.getTypeName()));
for (QtJambiSignals.EmitMethodInfo emitMethodInfo : emitMethods.values()) {
if(emitMethodInfo.methodId==0)
continue;
List signalTypes = emitMethodInfo.parameterTypes;
List cppTypes = new ArrayList<>();
List signalParameterInfos = new ArrayList<>();
List> signalClassTypes = new ArrayList<>();
for (int j = 0; j < signalTypes.size(); j++) {
QtJambiSignals.SignalParameterType signalType = signalTypes.get(j);
signalClassTypes.add(signalType.type);
QtMetaType metaTypeDecl = signalType.annotatedType.getAnnotation(QtMetaType.class);
int metaTypeId = 0;
String typeName;
if(metaTypeDecl!=null) {
if(metaTypeDecl.id()!=0) {
metaTypeId = metaTypeDecl.id();
if(signalType.isPointer || signalType.isReference) {
metaTypeId = registerRefMetaType(metaTypeId, signalType.isPointer, signalType.isReference);
}
typeName = new QMetaType(metaTypeId).name().toString();
}else if(metaTypeDecl.type()!=QMetaType.Type.UnknownType){
metaTypeId = metaTypeDecl.type().value();
if(signalType.isPointer || signalType.isReference) {
metaTypeId = registerRefMetaType(metaTypeId, signalType.isPointer, signalType.isReference);
}
typeName = new QMetaType(metaTypeId).name().toString();
}else {
if(metaTypeDecl.name().isEmpty())
throw new IllegalArgumentException("Incomplete @QtMetaType declaration. Either use type, id or name to specify meta type.");
typeName = metaTypeDecl.name();
if(signalType.isPointer && !typeName.endsWith("*")) {
typeName += "*";
}
if(signalType.isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
}
}else{
typeName = internalTypeNameOfClass(signalType.type, signalType.genericType);
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){
if(metaTypeId==QMetaType.Type.UnknownType.value()) {
metaTypeId = QtJambiInternal.findMetaType(typeName);
if(metaTypeId==QMetaType.Type.UnknownType.value() || !(signalType.genericType instanceof Class || new QMetaType(metaTypeId).name().toString().equals(typeName))) {
metaTypeId = registerMetaType(signalType.type, signalType.genericType, null, signalType.isPointer, signalType.isReference);
}
if(metaTypeId!=QMetaType.Type.UnknownType.value())
typeName = new QMetaType(metaTypeId).name().toString();
else
continue signalLoop;
}
cppTypes.add(typeName);
signalParameterInfos.add(new ParameterInfo(metaTypeId, typeName));
}else{
cppTypes.add(new QMetaType(type).name().toString());
signalParameterInfos.add(new ParameterInfo(type));
}
}
String methodSignature = String.format("%1$s(%2$s)", declaredField.getName(), String.join(", ", cppTypes));
if(!addedMethodSignatures.contains(methodSignature)) {
addedMethodSignatures.add(methodSignature);
signalIsClone.add(Boolean.FALSE);
allSignalParameterInfos.add(new ArrayList<>(signalParameterInfos));
Class> _signalClass;
QtJambiSignals.SignalClasses signalClasses = QtJambiSignals.signalClasses(QObject.class);
if(signalClasses==null)
throw new QSignalInitializationException("Unable to resolve multi signal.");
if(Modifier.isPublic(emitMethodInfo.method.getModifiers())) {
_signalClass = signalClasses.getPublicSignal(emitMethodInfo.parameterTypes.size());
}else {
_signalClass = signalClasses.getPrivateSignal(emitMethodInfo.parameterTypes.size());
}
metaData.signalInfos.add(new SignalInfo(declaredField, new ArrayList<>(signalTypes), _signalClass, new int[signalTypes.size()], emitMethodInfo.methodId));
}
}
}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);
}
}
}
}
List> allConstructorParameterInfos = new ArrayList<>();
// if(QObject.class.isAssignableFrom(clazz))
{
TreeSet> declaredConstructors = new TreeSet<>((m1, m2)->{
return m1.toGenericString().compareTo(m2.toGenericString());
});
declaredConstructors.addAll(Arrays.asList(clazz.getDeclaredConstructors()));
cloop: for(Constructor> constructor : declaredConstructors){
if(!constructor.isSynthetic() && constructor.isAnnotationPresent(QtInvokable.class)) {
Class>[] parameterTypes = constructor.getParameterTypes();
for (Class> parameterType : parameterTypes) {
if(parameterType==PrivateConstructorAccess.type()
|| parameterType==DeclarativeConstructorAccess.type()) {
continue cloop;
}
}
List cppTypes = new ArrayList<>();
List constructorParameterInfos = new ArrayList<>();
Type[] genericParameterTypes = constructor.getGenericParameterTypes();
AnnotatedType[] annotatedParameterTypes = constructor.getAnnotatedParameterTypes();
for (int j = 0; j < parameterTypes.length; j++) {
boolean isPointer = false;
boolean isReference = false;
if(annotatedParameterTypes[j].isAnnotationPresent(QtPointerType.class)) {
isPointer = true;
}
QtReferenceType referenceType = annotatedParameterTypes[j].getAnnotation(QtReferenceType.class);
if(referenceType!=null && !referenceType.isConst()) {
isReference = true;
}
String typeName;
QtMetaType metaTypeDecl = annotatedParameterTypes[j].getAnnotation(QtMetaType.class);
int metaTypeId = 0;
if(metaTypeDecl!=null) {
if(metaTypeDecl.id()!=0) {
metaTypeId = metaTypeDecl.id();
if(isPointer || isReference) {
metaTypeId = registerRefMetaType(metaTypeId, isPointer, isReference);
}
typeName = new QMetaType(metaTypeId).name().toString();
}else if(metaTypeDecl.type()!=QMetaType.Type.UnknownType){
metaTypeId = metaTypeDecl.type().value();
if(isPointer || isReference) {
metaTypeId = registerRefMetaType(metaTypeId, isPointer, isReference);
}
typeName = new QMetaType(metaTypeId).name().toString();
}else {
if(metaTypeDecl.name().isEmpty())
throw new IllegalArgumentException("Incomplete @QtMetaType declaration. Either use type, id or name to specify meta type.");
typeName = metaTypeDecl.name();
if(isPointer && !typeName.endsWith("*")) {
typeName += "*";
}
if(isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
}
}else {
typeName = internalTypeNameOfClass(parameterTypes[j], genericParameterTypes[j]);
if(isPointer && !typeName.endsWith("*")) {
typeName += "*";
}
if(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){
if(metaTypeId==QMetaType.Type.UnknownType.value()) {
metaTypeId = QtJambiInternal.findMetaType(typeName);
if(metaTypeId==QMetaType.Type.UnknownType.value() || !(genericParameterTypes[j] instanceof Class || new QMetaType(metaTypeId).name().toString().equals(typeName))) {
metaTypeId = registerMetaType(parameterTypes[j],
genericParameterTypes[j],
annotatedParameterTypes[j],
isPointer,
isReference);
}
if(metaTypeId!=QMetaType.Type.UnknownType.value())
typeName = new QMetaType(metaTypeId).name().toString();
else continue cloop;
}
cppTypes.add(typeName);
constructorParameterInfos.add(new ParameterInfo(metaTypeId, typeName));
}else{
cppTypes.add(new QMetaType(type).name().toString());
constructorParameterInfos.add(new ParameterInfo(type));
}
}
String methodSignature = String.format("%1$s(%2$s)", constructor.getName(), String.join(", ", cppTypes));
if(!addedMethodSignatures.contains(methodSignature)) {
addedMethodSignatures.add(methodSignature);
allConstructorParameterInfos.add(constructorParameterInfos);
metaData.constructors.add(constructor);
metaData.constructorMetaTypes.add(new int[parameterTypes.length+1]);
metaData.hasStaticMembers = true;
}
}
}
}
List> allMethodParameterInfos = new ArrayList<>();
List possibleBindables = Collections.emptyList();
TreeSet declaredMethods = new TreeSet<>((m1, m2)->{
return m1.toGenericString().compareTo(m2.toGenericString());
});
declaredMethods.addAll(Arrays.asList(clazz.getDeclaredMethods()));
for (Method declaredMethod : declaredMethods) {
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)
) {
List methodParameterInfos = new ArrayList<>();
boolean isPointer = false;
boolean isReference = false;
if(declaredMethod.getAnnotatedReturnType().isAnnotationPresent(QtPointerType.class)
|| declaredMethod.isAnnotationPresent(QtPointerType.class)) {
isPointer = true;
}
QtReferenceType referenceType = declaredMethod.getAnnotatedReturnType().getAnnotation(QtReferenceType.class);
if(referenceType==null)
referenceType = declaredMethod.getAnnotation(QtReferenceType.class);
if(referenceType!=null && !referenceType.isConst()) {
isReference = true;
}
QtMetaType metaTypeDecl = declaredMethod.getAnnotatedReturnType().getAnnotation(QtMetaType.class);
int metaTypeId = 0;
String typeName;
if(metaTypeDecl!=null) {
if(metaTypeDecl.id()!=0) {
metaTypeId = metaTypeDecl.id();
if(isPointer || isReference) {
metaTypeId = registerRefMetaType(metaTypeId, isPointer, isReference);
}
typeName = new QMetaType(metaTypeId).name().toString();
}else if(metaTypeDecl.type()!=QMetaType.Type.UnknownType){
metaTypeId = metaTypeDecl.type().value();
if(isPointer || isReference) {
metaTypeId = registerRefMetaType(metaTypeId, isPointer, isReference);
}
typeName = new QMetaType(metaTypeId).name().toString();
}else {
if(metaTypeDecl.name().isEmpty())
throw new IllegalArgumentException("Incomplete @QtMetaType declaration. Either use type, id or name to specify meta type.");
typeName = metaTypeDecl.name();
if(isPointer && !typeName.endsWith("*")) {
typeName += "*";
}
if(isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
}
}else {
typeName = internalTypeNameOfClass(declaredMethod.getReturnType(), declaredMethod.getGenericReturnType());
if(isPointer && !typeName.endsWith("*")) {
typeName += "*";
}
if(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){
if(metaTypeId==QMetaType.Type.UnknownType.value()) {
metaTypeId = QtJambiInternal.findMetaType(typeName);
if(metaTypeId==QMetaType.Type.UnknownType.value() || !(declaredMethod.getGenericReturnType() instanceof Class || new QMetaType(metaTypeId).name().toString().equals(typeName))) {
metaTypeId = registerMetaType(
declaredMethod.getReturnType(),
declaredMethod.getGenericReturnType(),
declaredMethod.getAnnotatedReturnType(),
isPointer,
isReference);
}
if(metaTypeId!=QMetaType.Type.UnknownType.value())
typeName = new QMetaType(metaTypeId).name().toString();
}
methodParameterInfos.add(new ParameterInfo(metaTypeId, typeName));
}else{
methodParameterInfos.add(new ParameterInfo(type));
}
List cppTypes = new ArrayList<>();
Class>[] parameterTypes = declaredMethod.getParameterTypes();
Type[] genericParameterTypes = declaredMethod.getGenericParameterTypes();
AnnotatedType[] annotatedParameterTypes = declaredMethod.getAnnotatedParameterTypes();
for (int j = 0; j < parameterTypes.length; j++) {
metaTypeId = 0;
isPointer = false;
isReference = false;
if(annotatedParameterTypes[j].isAnnotationPresent(QtPointerType.class)) {
isPointer = true;
}
referenceType = annotatedParameterTypes[j].getAnnotation(QtReferenceType.class);
if(referenceType!=null && !referenceType.isConst()) {
isReference = true;
}
metaTypeDecl = annotatedParameterTypes[j].getAnnotation(QtMetaType.class);
if(metaTypeDecl!=null) {
if(metaTypeDecl.id()!=0) {
metaTypeId = metaTypeDecl.id();
if(isPointer || isReference) {
metaTypeId = registerRefMetaType(metaTypeId, isPointer, isReference);
}
typeName = new QMetaType(metaTypeId).name().toString();
}else if(metaTypeDecl.type()!=QMetaType.Type.UnknownType){
metaTypeId = metaTypeDecl.type().value();
if(isPointer || isReference) {
metaTypeId = registerRefMetaType(metaTypeId, isPointer, isReference);
}
typeName = new QMetaType(metaTypeId).name().toString();
}else {
if(metaTypeDecl.name().isEmpty())
throw new IllegalArgumentException("Incomplete @QtMetaType declaration. Either use type, id or name to specify meta type.");
typeName = metaTypeDecl.name();
if(isPointer && !typeName.endsWith("*")) {
typeName += "*";
}
if(isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
}
}else {
typeName = internalTypeNameOfClass(parameterTypes[j], genericParameterTypes[j]);
if(isPointer && !typeName.endsWith("*")) {
typeName += "*";
}
if(isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
}
type = metaType(typeName);
if(type==QMetaType.Type.UnknownType || type==QMetaType.Type.User){
if(metaTypeId==QMetaType.Type.UnknownType.value()) {
metaTypeId = QtJambiInternal.findMetaType(typeName);
if(metaTypeId==QMetaType.Type.UnknownType.value() || !(genericParameterTypes[j] instanceof Class || new QMetaType(metaTypeId).name().toString().equals(typeName))) {
metaTypeId = registerMetaType(parameterTypes[j],
genericParameterTypes[j],
annotatedParameterTypes[j],
isPointer,
isReference);
}
if(metaTypeId!=QMetaType.Type.UnknownType.value())
typeName = new QMetaType(metaTypeId).name().toString();
}
cppTypes.add(typeName);
methodParameterInfos.add(new ParameterInfo(metaTypeId, typeName));
}else{
cppTypes.add(new QMetaType(type).name().toString());
methodParameterInfos.add(new ParameterInfo(type));
}
}
String methodSignature = String.format("%1$s(%2$s)", declaredMethod.getName(), String.join(", ", cppTypes));
if(!addedMethodSignatures.contains(methodSignature)) {
allMethodParameterInfos.add(methodParameterInfos);
metaData.methods.add(declaredMethod);
if(Modifier.isStatic(declaredMethod.getModifiers())){
methodFlags.put(declaredMethod, MethodFlags.MethodMethod);
metaData.hasStaticMembers = true;
}else{
if(!QObject.class.isAssignableFrom(clazz)) {
// we need to make sure that static_metacall is set
metaData.hasStaticMembers = true;
methodFlags.put(declaredMethod, MethodFlags.MethodMethod);
}else {
methodFlags.put(declaredMethod, MethodFlags.MethodSlot);
}
}
metaData.methodMetaTypes.add(new int[declaredMethod.getParameterCount()+1]);
}
}
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));
}
}
// 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(SignalInfo signalInfo : metaData.signalInfos) {
if(signalInfo.field.getName().equals(property+"Changed")) {
if(signalInfo.signalTypes.isEmpty()) {
propertyNotifies.put(property, signalInfo.field);
}else {
if(propertyReaders.get(property)!=null) {
if(signalInfo.signalTypes.get(0).type.isAssignableFrom(getBoxedType(propertyReaders.get(property).getReturnType()))) {
propertyNotifies.put(property, signalInfo.field);
}
}else if(propertyMembers.get(property)!=null) {
Field propertyField = propertyMembers.get(property);
if(isValidQProperty(propertyField)) {
MetaObjectTools.QPropertyTypeInfo pinfo = getQPropertyTypeInfo(propertyField);
if(signalInfo.signalTypes.get(0).type.isAssignableFrom(getBoxedType(pinfo.propertyType))) {
propertyNotifies.put(property, propertyField);
}
}else if(signalInfo.signalTypes.get(0).type.isAssignableFrom(getBoxedType(propertyField.getType()))) {
propertyNotifies.put(property, propertyField);
}
}else if(propertyQPropertyFields.get(property)!=null) {
MetaObjectTools.QPropertyTypeInfo pinfo = getQPropertyTypeInfo(propertyQPropertyFields.get(property));
if(signalInfo.signalTypes.get(0).type.isAssignableFrom(getBoxedType(pinfo.propertyType))) {
propertyNotifies.put(property, signalInfo.field);
}
}
}
break;
}
}
}
}
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.addStringData(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.signalInfos.size() + metaData.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.signalInfos.size()); intdataComments.add("signalCount");
//
// Build classinfo array
//
for(Map.Entry entry : classInfos.entrySet()){
// classinfo: key, value
metaData.metaData.add(metaData.addStringData(entry.getKey())); intdataComments.add("classinfo: key");
metaData.metaData.add(metaData.addStringData(entry.getValue())); intdataComments.add("classinfo: value");
}
HashMap
© 2015 - 2024 Weber Informatics LLC | Privacy Policy