diff options
Diffstat (limited to 'src/tools')
-rw-r--r-- | src/tools/bootstrap/bootstrap.pri | 2 | ||||
-rw-r--r-- | src/tools/bootstrap/bootstrap.pro | 9 | ||||
-rw-r--r-- | src/tools/moc/generator.cpp | 413 | ||||
-rw-r--r-- | src/tools/moc/generator.h | 11 | ||||
-rw-r--r-- | src/tools/moc/main.cpp | 2 | ||||
-rw-r--r-- | src/tools/moc/moc.cpp | 10 | ||||
-rw-r--r-- | src/tools/moc/moc.h | 3 | ||||
-rw-r--r-- | src/tools/moc/moc.pro | 2 | ||||
-rw-r--r-- | src/tools/moc/outputrevision.h | 2 | ||||
-rw-r--r-- | src/tools/moc/preprocessor.cpp | 9 | ||||
-rw-r--r-- | src/tools/moc/preprocessor.h | 2 | ||||
-rw-r--r-- | src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp | 458 | ||||
-rw-r--r-- | src/tools/qdbuscpp2xml/qdbuscpp2xml.pro | 34 | ||||
-rw-r--r-- | src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp | 1178 | ||||
-rw-r--r-- | src/tools/qdbusxml2cpp/qdbusxml2cpp.pro | 33 | ||||
-rw-r--r-- | src/tools/qdoc/qmlparser/qqmljsmemorypool_p.h | 9 | ||||
-rw-r--r-- | src/tools/rcc/main.cpp | 9 | ||||
-rw-r--r-- | src/tools/rcc/rcc.cpp | 4 | ||||
-rw-r--r-- | src/tools/tools.pro | 11 | ||||
-rw-r--r-- | src/tools/uic/cpp/cppwriteinitialization.cpp | 2 | ||||
-rw-r--r-- | src/tools/uic/qclass_lib_map.h | 4 |
21 files changed, 2056 insertions, 151 deletions
diff --git a/src/tools/bootstrap/bootstrap.pri b/src/tools/bootstrap/bootstrap.pri index 228fcaca0d..6a7eb8538f 100644 --- a/src/tools/bootstrap/bootstrap.pri +++ b/src/tools/bootstrap/bootstrap.pri @@ -14,10 +14,8 @@ DEFINES += \ QT_NO_CAST_TO_ASCII \ QT_NO_CODECS \ QT_NO_DATASTREAM \ - QT_NO_GEOM_VARIANT \ QT_NO_LIBRARY \ QT_NO_QOBJECT \ - QT_NO_STL \ QT_NO_SYSTEMLOCALE \ QT_NO_THREAD \ QT_NO_UNICODETABLES \ diff --git a/src/tools/bootstrap/bootstrap.pro b/src/tools/bootstrap/bootstrap.pro index 5b70a5af64..21fc2f9ca5 100644 --- a/src/tools/bootstrap/bootstrap.pro +++ b/src/tools/bootstrap/bootstrap.pro @@ -17,10 +17,8 @@ DEFINES += \ QT_NO_CAST_TO_ASCII \ QT_NO_CODECS \ QT_NO_DATASTREAM \ - QT_NO_GEOM_VARIANT \ QT_NO_LIBRARY \ QT_NO_QOBJECT \ - QT_NO_STL \ QT_NO_SYSTEMLOCALE \ QT_NO_THREAD \ QT_NO_UNICODETABLES \ @@ -63,15 +61,16 @@ SOURCES += \ ../../corelib/io/qfsfileengine.cpp \ ../../corelib/io/qfsfileengine_iterator.cpp \ ../../corelib/io/qiodevice.cpp \ + ../../corelib/io/qfiledevice.cpp \ ../../corelib/io/qtemporaryfile.cpp \ ../../corelib/io/qtextstream.cpp \ - ../../corelib/io/qurl.cpp \ ../../corelib/kernel/qmetatype.cpp \ ../../corelib/kernel/qvariant.cpp \ ../../corelib/kernel/qsystemerror.cpp \ ../../corelib/plugin/quuid.cpp \ ../../corelib/tools/qbitarray.cpp \ ../../corelib/tools/qbytearray.cpp \ + ../../corelib/tools/qarraydata.cpp \ ../../corelib/tools/qbytearraymatcher.cpp \ ../../corelib/tools/qdatetime.cpp \ ../../corelib/tools/qhash.cpp \ @@ -80,6 +79,10 @@ SOURCES += \ ../../corelib/tools/qlocale_tools.cpp \ ../../corelib/tools/qmap.cpp \ ../../corelib/tools/qregexp.cpp \ + ../../corelib/tools/qpoint.cpp \ + ../../corelib/tools/qrect.cpp \ + ../../corelib/tools/qsize.cpp \ + ../../corelib/tools/qline.cpp \ ../../corelib/tools/qstring.cpp \ ../../corelib/tools/qstringlist.cpp \ ../../corelib/tools/qvector.cpp \ diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 608d53c1f2..74cdc5874c 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -54,30 +54,37 @@ QT_BEGIN_NAMESPACE -uint qvariant_nameToType(const QByteArray &name) +uint nameToBuiltinType(const QByteArray &name) { if (name.isEmpty()) return 0; uint tp = QMetaType::type(name.constData()); - return tp < QMetaType::User ? tp : 0; + return tp < uint(QMetaType::User) ? tp : uint(QMetaType::UnknownType); } /* - Returns true if the type is a QVariant types. + Returns true if the type is a built-in type. */ -bool isVariantType(const QByteArray &type) -{ - return qvariant_nameToType(type) != 0; +bool isBuiltinType(const QByteArray &type) + { + int id = QMetaType::type(type.constData()); + if (id == QMetaType::UnknownType) + return false; + return (id < QMetaType::User); } -/*! - Returns true if the type is qreal. -*/ -static bool isQRealType(const QByteArray &type) -{ - return (type == "qreal"); -} +static const char *metaTypeEnumValueString(int type) + { +#define RETURN_METATYPENAME_STRING(MetaTypeName, MetaTypeId, RealType) \ + case QMetaType::MetaTypeName: return #MetaTypeName; + + switch (type) { +QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING) + } +#undef RETURN_METATYPENAME_STRING + return 0; + } Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, FILE *outfile) : out(outfile), cdef(classDef), metaTypes(metaTypes) @@ -109,24 +116,28 @@ static inline int lengthOfEscapeSequence(const QByteArray &s, int i) return i - startPos; } -int Generator::strreg(const QByteArray &s) +void Generator::strreg(const QByteArray &s) { - int idx = 0; - for (int i = 0; i < strings.size(); ++i) { - const QByteArray &str = strings.at(i); - if (str == s) - return idx; - idx += str.length() + 1; - for (int i = 0; i < str.length(); ++i) { - if (str.at(i) == '\\') { - int cnt = lengthOfEscapeSequence(str, i) - 1; - idx -= cnt; - i += cnt; - } - } - } - strings.append(s); - return idx; + if (!strings.contains(s)) + strings.append(s); +} + +int Generator::stridx(const QByteArray &s) +{ + int i = strings.indexOf(s); + Q_ASSERT_X(i != -1, Q_FUNC_INFO, "We forgot to register some strings"); + return i; +} + +// Returns the sum of all parameters (including return type) for the given +// \a list of methods. This is needed for calculating the size of the methods' +// parameter type/name meta-data. +static int aggregateParameterCount(const QList<FunctionDef> &list) +{ + int sum = 0; + for (int i = 0; i < list.count(); ++i) + sum += list.at(i).arguments.count() + 1; // +1 for return type + return sum; } void Generator::generateCode() @@ -135,10 +146,6 @@ void Generator::generateCode() bool isQObject = (cdef->classname == "QObject"); bool isConstructible = !cdef->constructorList.isEmpty(); -// -// build the data array -// - // filter out undeclared enumerators and sets { QList<EnumDef> enumList; @@ -156,15 +163,119 @@ void Generator::generateCode() cdef->enumList = enumList; } +// +// Register all strings used in data section +// + strreg(cdef->qualified); + registerClassInfoStrings(); + registerFunctionStrings(cdef->signalList); + registerFunctionStrings(cdef->slotList); + registerFunctionStrings(cdef->methodList); + registerFunctionStrings(cdef->constructorList); + registerPropertyStrings(); + registerEnumStrings(); QByteArray qualifiedClassNameIdentifier = cdef->qualified; qualifiedClassNameIdentifier.replace(':', '_'); +// +// Build stringdata struct +// + fprintf(out, "struct qt_meta_stringdata_%s_t {\n", qualifiedClassNameIdentifier.constData()); + fprintf(out, " QByteArrayData data[%d];\n", strings.size()); + { + int len = 0; + for (int i = 0; i < strings.size(); ++i) + len += strings.at(i).length() + 1; + fprintf(out, " char stringdata[%d];\n", len + 1); + } + fprintf(out, "};\n"); + + // Macro that expands into a QByteArrayData. The offset member is + // calculated from 1) the offset of the actual characters in the + // stringdata.stringdata member, and 2) the stringdata.data index of the + // QByteArrayData being defined. This calculation relies on the + // QByteArrayData::data() implementation returning simply "this + offset". + fprintf(out, "#define QT_MOC_LITERAL(idx, ofs, len) \\\n" + " Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \\\n" + " offsetof(qt_meta_stringdata_%s_t, stringdata) + ofs \\\n" + " - idx * sizeof(QByteArrayData) \\\n" + " )\n", + qualifiedClassNameIdentifier.constData()); + + fprintf(out, "static const qt_meta_stringdata_%s_t qt_meta_stringdata_%s = {\n", + qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData()); + fprintf(out, " {\n"); + { + int idx = 0; + for (int i = 0; i < strings.size(); ++i) { + if (i) + fprintf(out, ",\n"); + const QByteArray &str = strings.at(i); + fprintf(out, "QT_MOC_LITERAL(%d, %d, %d)", i, idx, str.length()); + idx += str.length() + 1; + for (int j = 0; j < str.length(); ++j) { + if (str.at(j) == '\\') { + int cnt = lengthOfEscapeSequence(str, j) - 1; + idx -= cnt; + j += cnt; + } + } + } + fprintf(out, "\n },\n"); + } + +// +// Build stringdata array +// + fprintf(out, " \""); + int col = 0; + int len = 0; + for (int i = 0; i < strings.size(); ++i) { + QByteArray s = strings.at(i); + len = s.length(); + if (col && col + len >= 72) { + fprintf(out, "\"\n \""); + col = 0; + } else if (len && s.at(0) >= '0' && s.at(0) <= '9') { + fprintf(out, "\"\""); + len += 2; + } + int idx = 0; + while (idx < s.length()) { + if (idx > 0) { + col = 0; + fprintf(out, "\"\n \""); + } + int spanLen = qMin(70, s.length() - idx); + // don't cut escape sequences at the end of a line + int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1); + if (backSlashPos >= idx) { + int escapeLen = lengthOfEscapeSequence(s, backSlashPos); + spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, s.length() - idx); + } + fwrite(s.constData() + idx, 1, spanLen, out); + idx += spanLen; + col += spanLen; + } + + fputs("\\0", out); + col += len + 2; + } + +// Terminate stringdata struct + fprintf(out, "\"\n};\n"); + fprintf(out, "#undef QT_MOC_LITERAL\n\n"); + +// +// build the data array +// + int index = MetaObjectPrivateFieldCount; fprintf(out, "static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData()); fprintf(out, "\n // content:\n"); fprintf(out, " %4d, // revision\n", int(QMetaObjectPrivate::OutputRevision)); - fprintf(out, " %4d, // classname\n", strreg(cdef->qualified)); + fprintf(out, " %4d, // classname\n", stridx(cdef->qualified)); fprintf(out, " %4d, %4d, // classinfo\n", cdef->classInfoList.count(), cdef->classInfoList.count() ? index : 0); index += cdef->classInfoList.count() * 2; @@ -173,6 +284,15 @@ void Generator::generateCode() index += methodCount * 5; if (cdef->revisionedMethods) index += methodCount; + int paramsIndex = index; + int totalParameterCount = aggregateParameterCount(cdef->signalList) + + aggregateParameterCount(cdef->slotList) + + aggregateParameterCount(cdef->methodList) + + aggregateParameterCount(cdef->constructorList); + index += totalParameterCount * 2 // types and parameter names + - methodCount // return "parameters" don't have names + - cdef->constructorList.count(); // "this" parameters don't have names + fprintf(out, " %4d, %4d, // properties\n", cdef->propertyList.count(), cdef->propertyList.count() ? index : 0); index += cdef->propertyList.count() * 3; if(cdef->notifyableProperties) @@ -199,17 +319,17 @@ void Generator::generateCode() // // Build signals array first, otherwise the signal indices would be wrong // - generateFunctions(cdef->signalList, "signal", MethodSignal); + generateFunctions(cdef->signalList, "signal", MethodSignal, paramsIndex); // // Build slots array // - generateFunctions(cdef->slotList, "slot", MethodSlot); + generateFunctions(cdef->slotList, "slot", MethodSlot, paramsIndex); // // Build method array // - generateFunctions(cdef->methodList, "method", MethodMethod); + generateFunctions(cdef->methodList, "method", MethodMethod, paramsIndex); // // Build method version arrays @@ -221,6 +341,15 @@ void Generator::generateCode() } // +// Build method parameters array +// + generateFunctionParameters(cdef->signalList, "signal"); + generateFunctionParameters(cdef->slotList, "slot"); + generateFunctionParameters(cdef->methodList, "method"); + if (isConstructible) + generateFunctionParameters(cdef->constructorList, "constructor"); + +// // Build property array // generateProperties(); @@ -234,7 +363,7 @@ void Generator::generateCode() // Build constructors array // if (isConstructible) - generateFunctions(cdef->constructorList, "constructor", MethodConstructor); + generateFunctions(cdef->constructorList, "constructor", MethodConstructor, paramsIndex); // // Terminate data array @@ -242,46 +371,6 @@ void Generator::generateCode() fprintf(out, "\n 0 // eod\n};\n\n"); // -// Build stringdata array -// - fprintf(out, "static const char qt_meta_stringdata_%s[] = {\n", qualifiedClassNameIdentifier.constData()); - fprintf(out, " \""); - int col = 0; - int len = 0; - for (int i = 0; i < strings.size(); ++i) { - QByteArray s = strings.at(i); - len = s.length(); - if (col && col + len >= 72) { - fprintf(out, "\"\n \""); - col = 0; - } else if (len && s.at(0) >= '0' && s.at(0) <= '9') { - fprintf(out, "\"\""); - len += 2; - } - int idx = 0; - while (idx < s.length()) { - if (idx > 0) { - col = 0; - fprintf(out, "\"\n \""); - } - int spanLen = qMin(70, s.length() - idx); - // don't cut escape sequences at the end of a line - int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1); - if (backSlashPos >= idx) { - int escapeLen = lengthOfEscapeSequence(s, backSlashPos); - spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, s.length() - idx); - } - fwrite(s.constData() + idx, 1, spanLen, out); - idx += spanLen; - col += spanLen; - } - - fputs("\\0", out); - col += len + 2; - } - fprintf(out, "\"\n};\n\n"); - -// // Generate internal qt_static_metacall() function // if (cdef->hasQObject && !isQt) @@ -293,7 +382,7 @@ void Generator::generateCode() QList<QByteArray> extraList; for (int i = 0; i < cdef->propertyList.count(); ++i) { const PropertyDef &p = cdef->propertyList.at(i); - if (!isVariantType(p.type) && !metaTypes.contains(p.type) && !p.type.contains('*') && + if (!isBuiltinType(p.type) && !metaTypes.contains(p.type) && !p.type.contains('*') && !p.type.contains('<') && !p.type.contains('>')) { int s = p.type.lastIndexOf("::"); if (s > 0) { @@ -356,8 +445,9 @@ void Generator::generateCode() fprintf(out, " { &%s::staticMetaObject, ", purestSuperClass.constData()); else fprintf(out, " { 0, "); - fprintf(out, "qt_meta_stringdata_%s,\n qt_meta_data_%s, ", - qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData()); + fprintf(out, "qt_meta_stringdata_%s.data,\n" + " qt_meta_data_%s, ", qualifiedClassNameIdentifier.constData(), + qualifiedClassNameIdentifier.constData()); if (!hasExtraData) fprintf(out, "0 }\n"); else @@ -379,7 +469,7 @@ void Generator::generateCode() // fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData()); fprintf(out, " if (!_clname) return 0;\n"); - fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s))\n" + fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata))\n" " return static_cast<void*>(const_cast< %s*>(this));\n", qualifiedClassNameIdentifier.constData(), cdef->classname.constData()); for (int i = 1; i < cdef->superclassList.size(); ++i) { // for all superclasses but the first one @@ -430,6 +520,15 @@ void Generator::generateCode() } +void Generator::registerClassInfoStrings() +{ + for (int i = 0; i < cdef->classInfoList.size(); ++i) { + const ClassInfoDef &c = cdef->classInfoList.at(i); + strreg(c.name); + strreg(c.value); + } +} + void Generator::generateClassInfos() { if (cdef->classInfoList.isEmpty()) @@ -439,32 +538,37 @@ void Generator::generateClassInfos() for (int i = 0; i < cdef->classInfoList.size(); ++i) { const ClassInfoDef &c = cdef->classInfoList.at(i); - fprintf(out, " %4d, %4d,\n", strreg(c.name), strreg(c.value)); + fprintf(out, " %4d, %4d,\n", stridx(c.name), stridx(c.value)); } } -void Generator::generateFunctions(const QList<FunctionDef>& list, const char *functype, int type) +void Generator::registerFunctionStrings(const QList<FunctionDef>& list) { - if (list.isEmpty()) - return; - fprintf(out, "\n // %ss: signature, parameters, type, tag, flags\n", functype); - for (int i = 0; i < list.count(); ++i) { const FunctionDef &f = list.at(i); - QByteArray sig = f.name + '('; - QByteArray arguments; + strreg(f.name); + if (!isBuiltinType(f.normalizedType)) + strreg(f.normalizedType); + strreg(f.tag); for (int j = 0; j < f.arguments.count(); ++j) { const ArgumentDef &a = f.arguments.at(j); - if (j) { - sig += ","; - arguments += ","; - } - sig += a.normalizedType; - arguments += a.name; + if (!isBuiltinType(a.normalizedType)) + strreg(a.normalizedType); + strreg(a.name); } - sig += ')'; + } +} + +void Generator::generateFunctions(const QList<FunctionDef>& list, const char *functype, int type, int ¶msIndex) +{ + if (list.isEmpty()) + return; + fprintf(out, "\n // %ss: name, argc, parameters, tag, flags\n", functype); + + for (int i = 0; i < list.count(); ++i) { + const FunctionDef &f = list.at(i); unsigned char flags = type; if (f.access == FunctionDef::Private) @@ -487,8 +591,12 @@ void Generator::generateFunctions(const QList<FunctionDef>& list, const char *fu flags |= MethodScriptable; if (f.revision > 0) flags |= MethodRevisioned; - fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n", strreg(sig), - strreg(arguments), strreg(f.normalizedType), strreg(f.tag), flags); + + int argc = f.arguments.count(); + fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n", + stridx(f.name), argc, paramsIndex, stridx(f.tag), flags); + + paramsIndex += 1 + argc * 2; } } @@ -502,6 +610,69 @@ void Generator::generateFunctionRevisions(const QList<FunctionDef>& list, const } } +void Generator::generateFunctionParameters(const QList<FunctionDef>& list, const char *functype) +{ + if (list.isEmpty()) + return; + fprintf(out, "\n // %ss: parameters\n", functype); + for (int i = 0; i < list.count(); ++i) { + const FunctionDef &f = list.at(i); + fprintf(out, " "); + + // Types + for (int j = -1; j < f.arguments.count(); ++j) { + if (j > -1) + fputc(' ', out); + const QByteArray &typeName = (j < 0) ? f.normalizedType : f.arguments.at(j).normalizedType; + generateTypeInfo(typeName, /*allowEmptyName=*/f.isConstructor); + fputc(',', out); + } + + // Parameter names + for (int j = 0; j < f.arguments.count(); ++j) { + const ArgumentDef &arg = f.arguments.at(j); + fprintf(out, " %4d,", stridx(arg.name)); + } + + fprintf(out, "\n"); + } +} + +void Generator::generateTypeInfo(const QByteArray &typeName, bool allowEmptyName) +{ + Q_UNUSED(allowEmptyName); + if (isBuiltinType(typeName)) { + int type; + const char *valueString; + if (typeName == "qreal") { + type = QMetaType::UnknownType; + valueString = "QReal"; + } else { + type = nameToBuiltinType(typeName); + valueString = metaTypeEnumValueString(type); + } + if (valueString) { + fprintf(out, "QMetaType::%s", valueString); + } else { + Q_ASSERT(type != QMetaType::UnknownType); + fprintf(out, "%4d", type); + } + } else { + Q_ASSERT(!typeName.isEmpty() || allowEmptyName); + fprintf(out, "0x%.8x | %d", IsUnresolvedType, stridx(typeName)); + } +} + +void Generator::registerPropertyStrings() +{ + for (int i = 0; i < cdef->propertyList.count(); ++i) { + const PropertyDef &p = cdef->propertyList.at(i); + strreg(p.name); + if (!isBuiltinType(p.type)) + strreg(p.type); + } +} + void Generator::generateProperties() { // @@ -513,11 +684,8 @@ void Generator::generateProperties() for (int i = 0; i < cdef->propertyList.count(); ++i) { const PropertyDef &p = cdef->propertyList.at(i); uint flags = Invalid; - if (!isVariantType(p.type)) { + if (!isBuiltinType(p.type)) flags |= EnumOrFlag; - } else if (!isQRealType(p.type)) { - flags |= qvariant_nameToType(p.type) << 24; - } if (!p.read.isEmpty()) flags |= Readable; if (!p.write.isEmpty()) { @@ -567,12 +735,9 @@ void Generator::generateProperties() if (p.final) flags |= Final; - fprintf(out, " %4d, %4d, ", - strreg(p.name), - strreg(p.type)); - if (!(flags >> 24) && isQRealType(p.type)) - fprintf(out, "(QMetaType::QReal << 24) | "); - fprintf(out, "0x%.8x,\n", flags); + fprintf(out, " %4d, ", stridx(p.name)); + generateTypeInfo(p.type); + fprintf(out, ", 0x%.8x,\n", flags); } if(cdef->notifyableProperties) { @@ -596,6 +761,16 @@ void Generator::generateProperties() } } +void Generator::registerEnumStrings() +{ + for (int i = 0; i < cdef->enumList.count(); ++i) { + const EnumDef &e = cdef->enumList.at(i); + strreg(e.name); + for (int j = 0; j < e.values.count(); ++j) + strreg(e.values.at(j)); + } +} + void Generator::generateEnums(int index) { if (cdef->enumDeclarations.isEmpty()) @@ -607,7 +782,7 @@ void Generator::generateEnums(int index) for (i = 0; i < cdef->enumList.count(); ++i) { const EnumDef &e = cdef->enumList.at(i); fprintf(out, " %4d, 0x%.1x, %4d, %4d,\n", - strreg(e.name), + stridx(e.name), cdef->enumDeclarations.value(e.name) ? 1 : 0, e.values.count(), index); @@ -624,7 +799,7 @@ void Generator::generateEnums(int index) code += "::" + e.name; code += "::" + val; fprintf(out, " %4d, uint(%s),\n", - strreg(val), code.constData()); + stridx(val), code.constData()); } } } @@ -926,8 +1101,9 @@ void Generator::generateStaticMetacall() fprintf(out, " switch (_id) {\n"); for (int methodindex = 0; methodindex < methodList.size(); ++methodindex) { const FunctionDef &f = methodList.at(methodindex); + Q_ASSERT(!f.normalizedType.isEmpty()); fprintf(out, " case %d: ", methodindex); - if (f.normalizedType.size()) + if (f.normalizedType != "void") fprintf(out, "{ %s _r = ", noRef(f.normalizedType).constData()); fprintf(out, "_t->"); if (f.inPrivateClass.size()) @@ -942,7 +1118,7 @@ void Generator::generateStaticMetacall() isUsed_a = true; } fprintf(out, ");"); - if (f.normalizedType.size()) { + if (f.normalizedType != "void") { fprintf(out, "\n if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = _r; } ", noRef(f.normalizedType).constData()); isUsed_a = true; @@ -1021,7 +1197,8 @@ void Generator::generateSignal(FunctionDef *def,int index) constQualifier = "const"; } - if (def->arguments.isEmpty() && def->normalizedType.isEmpty()) { + Q_ASSERT(!def->normalizedType.isEmpty()); + if (def->arguments.isEmpty() && def->normalizedType == "void") { fprintf(out, ")%s\n{\n" " QMetaObject::activate(%s, &staticMetaObject, %d, 0);\n" "}\n", constQualifier, thisPtr.constData(), index); @@ -1036,7 +1213,7 @@ void Generator::generateSignal(FunctionDef *def,int index) fprintf(out, "%s _t%d%s", a.type.name.constData(), offset++, a.rightType.constData()); } fprintf(out, ")%s\n{\n", constQualifier); - if (def->type.name.size() && def->normalizedType.size()) { + if (def->type.name.size() && def->normalizedType != "void") { QByteArray returnType = noRef(def->normalizedType); if (returnType.endsWith('*')) { fprintf(out, " %s _t0 = 0;\n", returnType.constData()); @@ -1046,7 +1223,7 @@ void Generator::generateSignal(FunctionDef *def,int index) } fprintf(out, " void *_a[] = { "); - if (def->normalizedType.isEmpty()) { + if (def->normalizedType == "void") { fprintf(out, "0"); } else { if (def->returnTypeIsVolatile) @@ -1062,7 +1239,7 @@ void Generator::generateSignal(FunctionDef *def,int index) fprintf(out, ", const_cast<void*>(reinterpret_cast<const void*>(&_t%d))", i); fprintf(out, " };\n"); fprintf(out, " QMetaObject::activate(%s, &staticMetaObject, %d, _a);\n", thisPtr.constData(), index); - if (def->normalizedType.size()) + if (def->normalizedType != "void") fprintf(out, " return _t0;\n"); fprintf(out, "}\n"); } diff --git a/src/tools/moc/generator.h b/src/tools/moc/generator.h index 46eee4ca06..8ebc00b100 100644 --- a/src/tools/moc/generator.h +++ b/src/tools/moc/generator.h @@ -55,17 +55,24 @@ public: Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, FILE *outfile = 0); void generateCode(); private: + void registerClassInfoStrings(); void generateClassInfos(); - void generateFunctions(const QList<FunctionDef> &list, const char *functype, int type); + void registerFunctionStrings(const QList<FunctionDef> &list); + void generateFunctions(const QList<FunctionDef> &list, const char *functype, int type, int ¶msIndex); void generateFunctionRevisions(const QList<FunctionDef>& list, const char *functype); + void generateFunctionParameters(const QList<FunctionDef> &list, const char *functype); + void generateTypeInfo(const QByteArray &typeName, bool allowEmptyName = false); + void registerEnumStrings(); void generateEnums(int index); + void registerPropertyStrings(); void generateProperties(); void generateMetacall(); void generateStaticMetacall(); void generateSignal(FunctionDef *def, int index); void generatePluginMetaData(); - int strreg(const QByteArray &); // registers a string and returns its id + void strreg(const QByteArray &); // registers a string + int stridx(const QByteArray &); // returns a string's id QList<QByteArray> strings; QByteArray purestSuperClass; QList<QByteArray> metaTypes; diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp index 6f67a7dddf..5e87632988 100644 --- a/src/tools/moc/main.cpp +++ b/src/tools/moc/main.cpp @@ -143,7 +143,7 @@ QByteArray composePreprocessorOutput(const Symbols &symbols) { const int padding = sym.lineNum - lineNum; if (padding > 0) { output.resize(output.size() + padding); - qMemSet(output.data() + output.size() - padding, '\n', padding); + memset(output.data() + output.size() - padding, '\n', padding); lineNum = sym.lineNum; } diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 4189c29de1..e85aadbba7 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -75,9 +75,7 @@ static QByteArray normalizeType(const QByteArray &ba, bool fixScope = false) } } *d = '\0'; - QByteArray result; - if (strncmp("void", buf, d - buf) != 0) - result = normalizeTypeInternal(buf, d, fixScope); + QByteArray result = normalizeTypeInternal(buf, d, fixScope); if (buf != stackbuf) delete [] buf; return result; @@ -822,8 +820,8 @@ void Moc::generate(FILE *out) if (classList.size() && classList.first().classname == "Qt") fprintf(out, "#include <QtCore/qobject.h>\n"); - if (mustIncludeQMetaTypeH) - fprintf(out, "#include <QtCore/qmetatype.h>\n"); + fprintf(out, "#include <QtCore/qbytearray.h>\n"); // For QByteArrayData + fprintf(out, "#include <QtCore/qmetatype.h>\n"); // For QMetaType::Type if (mustIncludeQPluginH) fprintf(out, "#include <QtCore/qplugin.h>\n"); @@ -981,8 +979,6 @@ void Moc::createPropertyDef(PropertyDef &propDef) type = "qlonglong"; else if (type == "ULongLong") type = "qulonglong"; - else if (type == "qreal") - mustIncludeQMetaTypeH = true; propDef.type = type; diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index 9e9225da0a..b12ec492ff 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -200,7 +200,7 @@ class Moc : public Parser public: Moc(Preprocessor &p) : preprocessor(p), noInclude(false), generatedCode(false), - mustIncludeQMetaTypeH(false), mustIncludeQPluginH(false) + mustIncludeQPluginH(false) {} QByteArray filename; @@ -208,7 +208,6 @@ public: Preprocessor &preprocessor; bool noInclude; bool generatedCode; - bool mustIncludeQMetaTypeH; bool mustIncludeQPluginH; QByteArray includePath; QList<QByteArray> includeFiles; diff --git a/src/tools/moc/moc.pro b/src/tools/moc/moc.pro index 5c96c96a4c..45b063e0b0 100644 --- a/src/tools/moc/moc.pro +++ b/src/tools/moc/moc.pro @@ -1,7 +1,7 @@ TEMPLATE = app TARGET = moc -DEFINES += QT_MOC QT_NO_CAST_FROM_BYTEARRAY +DEFINES += QT_MOC QT_NO_CAST_FROM_BYTEARRAY QT_NO_COMPRESS DESTDIR = ../../../bin INCLUDEPATH += . DEPENDPATH += . diff --git a/src/tools/moc/outputrevision.h b/src/tools/moc/outputrevision.h index 2ce5b9b765..cff0f98fca 100644 --- a/src/tools/moc/outputrevision.h +++ b/src/tools/moc/outputrevision.h @@ -43,6 +43,6 @@ #define OUTPUTREVISION_H // if the output revision changes, you MUST change it in qobjectdefs.h too -enum { mocOutputRevision = 64 }; // moc format output revision +enum { mocOutputRevision = 65 }; // moc format output revision #endif // OUTPUTREVISION_H diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp index 091f62b379..d88c9f2950 100644 --- a/src/tools/moc/preprocessor.cpp +++ b/src/tools/moc/preprocessor.cpp @@ -939,10 +939,15 @@ Symbols Preprocessor::preprocessed(const QByteArray &filename, FILE *file) { QFile qfile; qfile.open(file, QFile::ReadOnly); - QByteArray input = qfile.readAll(); + return preprocessed(filename, &qfile); +} + +Symbols Preprocessor::preprocessed(const QByteArray &filename, QIODevice *file) +{ + QByteArray input = file->readAll(); if (input.isEmpty()) return symbols; - + // phase 1: get rid of backslash-newlines input = cleaned(input); diff --git a/src/tools/moc/preprocessor.h b/src/tools/moc/preprocessor.h index e0707da4ee..4e0bd6343d 100644 --- a/src/tools/moc/preprocessor.h +++ b/src/tools/moc/preprocessor.h @@ -62,6 +62,7 @@ typedef SubArray MacroName; typedef QHash<MacroName, Macro> Macros; typedef QVector<MacroName> MacroSafeSet; +class QIODevice; class Preprocessor : public Parser { @@ -80,6 +81,7 @@ public: QSet<QByteArray> preprocessedIncludes; Macros macros; Symbols preprocessed(const QByteArray &filename, FILE *file); + Symbols preprocessed(const QByteArray &filename, QIODevice *device); void skipUntilEndif(); diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp new file mode 100644 index 0000000000..60fd7302e0 --- /dev/null +++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp @@ -0,0 +1,458 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QByteArray> +#include <QString> +#include <QVarLengthArray> +#include <QFile> +#include <QList> +#include <QBuffer> +#include <QRegExp> +#include <QVector> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdlib.h> + +#include "qdbusconnection.h" // for the Export* flags +#include "qdbusconnection_p.h" // for the qDBusCheckAsyncTag + +// copied from dbus-protocol.h: +static const char docTypeHeader[] = + "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" " + "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"; + +#define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply" +#define QCLASSINFO_DBUS_INTERFACE "D-Bus Interface" +#define QCLASSINFO_DBUS_INTROSPECTION "D-Bus Introspection" + +#include "qdbusmetatype_p.h" +#include "qdbusmetatype.h" +#include "qdbusutil_p.h" + +#include "moc.h" +#include "generator.h" + +#define PROGRAMNAME "qdbuscpp2xml" +#define PROGRAMVERSION "0.2" +#define PROGRAMCOPYRIGHT "Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)." + +static QString outputFile; +static int flags; + +static const char help[] = + "Usage: " PROGRAMNAME " [options...] [files...]\n" + "Parses the C++ source or header file containing a QObject-derived class and\n" + "produces the D-Bus Introspection XML." + "\n" + "Options:\n" + " -p|-s|-m Only parse scriptable Properties, Signals and Methods (slots)\n" + " -P|-S|-M Parse all Properties, Signals and Methods (slots)\n" + " -a Output all scriptable contents (equivalent to -psm)\n" + " -A Output all contents (equivalent to -PSM)\n" + " -o <filename> Write the output to file <filename>\n" + " -h Show this information\n" + " -V Show the program version and quit.\n" + "\n"; + + +int qDBusParametersForMethod(const FunctionDef &mm, QVector<int>& metaTypes) +{ + QList<QByteArray> parameterTypes; + + foreach (const ArgumentDef &arg, mm.arguments) + parameterTypes.append(arg.normalizedType); + + return qDBusParametersForMethod(parameterTypes, metaTypes); +} + + +static inline QString typeNameToXml(const char *typeName) +{ + QString plain = QLatin1String(typeName); + return plain.toHtmlEscaped(); +} + +static QString addFunction(const FunctionDef &mm, bool isSignal = false) { + + QString xml = QString::fromLatin1(" <%1 name=\"%2\">\n") + .arg(isSignal ? QLatin1String("signal") : QLatin1String("method")) + .arg(QLatin1String(mm.name)); + + // check the return type first + int typeId = QMetaType::type(mm.normalizedType.constData()); + if (typeId != QMetaType::Void) { + if (typeId) { + const char *typeName = QDBusMetaType::typeToSignature(typeId); + if (typeName) { + xml += QString::fromLatin1(" <arg type=\"%1\" direction=\"out\"/>\n") + .arg(typeNameToXml(typeName)); + + // do we need to describe this argument? + if (QDBusMetaType::signatureToType(typeName) == QVariant::Invalid) + xml += QString::fromLatin1(" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"%1\"/>\n") + .arg(typeNameToXml(mm.normalizedType.constData())); + } else { + return QString(); + } + } else if (!mm.normalizedType.isEmpty()) { + return QString(); // wasn't a valid type + } + } + QList<ArgumentDef> names = mm.arguments; + QVector<int> types; + int inputCount = qDBusParametersForMethod(mm, types); + if (inputCount == -1) + return QString(); // invalid form + if (isSignal && inputCount + 1 != types.count()) + return QString(); // signal with output arguments? + if (isSignal && types.at(inputCount) == QDBusMetaTypeId::message) + return QString(); // signal with QDBusMessage argument? + + bool isScriptable = mm.isScriptable; + for (int j = 1; j < types.count(); ++j) { + // input parameter for a slot or output for a signal + if (types.at(j) == QDBusMetaTypeId::message) { + isScriptable = true; + continue; + } + + QString name; + if (!names.at(j - 1).name.isEmpty()) + name = QString::fromLatin1("name=\"%1\" ").arg(QString::fromLatin1(names.at(j - 1).name)); + + bool isOutput = isSignal || j > inputCount; + + const char *signature = QDBusMetaType::typeToSignature(types.at(j)); + xml += QString::fromLatin1(" <arg %1type=\"%2\" direction=\"%3\"/>\n") + .arg(name) + .arg(QLatin1String(signature)) + .arg(isOutput ? QLatin1String("out") : QLatin1String("in")); + + // do we need to describe this argument? + if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) { + const char *typeName = QMetaType::typeName(types.at(j)); + xml += QString::fromLatin1(" <annotation name=\"org.qtproject.QtDBus.QtTypeName.%1%2\" value=\"%3\"/>\n") + .arg(isOutput ? QLatin1String("Out") : QLatin1String("In")) + .arg(isOutput && !isSignal ? j - inputCount : j - 1) + .arg(typeNameToXml(typeName)); + } + } + + int wantedMask; + if (isScriptable) + wantedMask = isSignal ? QDBusConnection::ExportScriptableSignals + : QDBusConnection::ExportScriptableSlots; + else + wantedMask = isSignal ? QDBusConnection::ExportNonScriptableSignals + : QDBusConnection::ExportNonScriptableSlots; + if ((flags & wantedMask) != wantedMask) + return QString(); + + if (qDBusCheckAsyncTag(mm.tag.constData())) + // add the no-reply annotation + xml += QLatin1String(" <annotation name=\"" ANNOTATION_NO_WAIT "\"" + " value=\"true\"/>\n"); + + QString retval = xml; + retval += QString::fromLatin1(" </%1>\n") + .arg(isSignal ? QLatin1String("signal") : QLatin1String("method")); + + return retval; +} + + +static QString generateInterfaceXml(const ClassDef *mo) +{ + QString retval; + + // start with properties: + if (flags & (QDBusConnection::ExportScriptableProperties | + QDBusConnection::ExportNonScriptableProperties)) { + static const char *accessvalues[] = {0, "read", "write", "readwrite"}; + foreach (const PropertyDef &mp, mo->propertyList) { + if (!((!mp.scriptable.isEmpty() && (flags & QDBusConnection::ExportScriptableProperties)) || + (!mp.scriptable.isEmpty() && (flags & QDBusConnection::ExportNonScriptableProperties)))) + continue; + + int access = 0; + if (!mp.read.isEmpty()) + access |= 1; + if (!mp.write.isEmpty()) + access |= 2; + + int typeId = QMetaType::type(mp.type.constData()); + if (!typeId) + continue; + const char *signature = QDBusMetaType::typeToSignature(typeId); + if (!signature) + continue; + + retval += QString::fromLatin1(" <property name=\"%1\" type=\"%2\" access=\"%3\"") + .arg(QLatin1String(mp.name)) + .arg(QLatin1String(signature)) + .arg(QLatin1String(accessvalues[access])); + + if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) { + retval += QString::fromLatin1(">\n <annotation name=\"org.qtproject.QtDBus.QtTypeName\" value=\"%3\"/>\n </property>\n") + .arg(typeNameToXml(mp.type.constData())); + } else { + retval += QLatin1String("/>\n"); + } + } + } + + // now add methods: + + if (flags & (QDBusConnection::ExportScriptableSignals | QDBusConnection::ExportNonScriptableSignals)) { + foreach (const FunctionDef &mm, mo->signalList) { + if (mm.wasCloned) + continue; + + retval += addFunction(mm, true); + } + } + + if (flags & (QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportNonScriptableSlots)) { + foreach (const FunctionDef &slot, mo->slotList) { + if (slot.access == FunctionDef::Public) + retval += addFunction(slot); + } + foreach (const FunctionDef &method, mo->methodList) { + if (method.access == FunctionDef::Public) + retval += addFunction(method); + } + } + return retval; +} + +QString qDBusInterfaceFromClassDef(const ClassDef *mo) +{ + QString interface; + + foreach (ClassInfoDef cid, mo->classInfoList) { + if (cid.name == QCLASSINFO_DBUS_INTERFACE) + return QString::fromUtf8(cid.value); + } + interface = QLatin1String(mo->classname); + interface.replace(QLatin1String("::"), QLatin1String(".")); + + if (interface.startsWith(QLatin1String("QDBus"))) { + interface.prepend(QLatin1String("org.qtproject.QtDBus.")); + } else if (interface.startsWith(QLatin1Char('Q')) && + interface.length() >= 2 && interface.at(1).isUpper()) { + // assume it's Qt + interface.prepend(QLatin1String("local.org.qtproject.Qt.")); + } else { + interface.prepend(QLatin1String("local.")); + } + + return interface; +} + + +QString qDBusGenerateClassDefXml(const ClassDef *cdef) +{ + foreach (const ClassInfoDef &cid, cdef->classInfoList) { + if (cid.name == QCLASSINFO_DBUS_INTROSPECTION) + return QString::fromUtf8(cid.value); + } + + // generate the interface name from the meta object + QString interface = qDBusInterfaceFromClassDef(cdef); + + QString xml = generateInterfaceXml(cdef); + + if (xml.isEmpty()) + return QString(); // don't add an empty interface + return QString::fromLatin1(" <interface name=\"%1\">\n%2 </interface>\n") + .arg(interface, xml); +} + +static void showHelp() +{ + printf("%s", help); + exit(0); +} + +static void showVersion() +{ + printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION); + printf("D-Bus QObject-to-XML converter\n"); + exit(0); +} + +static void parseCmdLine(QStringList &arguments) +{ + flags = 0; + for (int i = 0; i < arguments.count(); ++i) { + const QString arg = arguments.at(i); + + if (arg == QLatin1String("--help")) + showHelp(); + + if (!arg.startsWith(QLatin1Char('-'))) + continue; + + char c = arg.count() == 2 ? arg.at(1).toLatin1() : char(0); + switch (c) { + case 'P': + flags |= QDBusConnection::ExportNonScriptableProperties; + // fall through + case 'p': + flags |= QDBusConnection::ExportScriptableProperties; + break; + + case 'S': + flags |= QDBusConnection::ExportNonScriptableSignals; + // fall through + case 's': + flags |= QDBusConnection::ExportScriptableSignals; + break; + + case 'M': + flags |= QDBusConnection::ExportNonScriptableSlots; + // fall through + case 'm': + flags |= QDBusConnection::ExportScriptableSlots; + break; + + case 'A': + flags |= QDBusConnection::ExportNonScriptableContents; + // fall through + case 'a': + flags |= QDBusConnection::ExportScriptableContents; + break; + + case 'o': + if (arguments.count() < i + 2 || arguments.at(i + 1).startsWith(QLatin1Char('-'))) { + printf("-o expects a filename\n"); + exit(1); + } + outputFile = arguments.takeAt(i + 1); + break; + + case 'h': + case '?': + showHelp(); + break; + + case 'V': + showVersion(); + break; + + default: + printf("unknown option: \"%s\"\n", qPrintable(arg)); + exit(1); + } + } + + if (flags == 0) + flags = QDBusConnection::ExportScriptableContents + | QDBusConnection::ExportNonScriptableContents; +} + +int main(int argc, char **argv) +{ + QStringList args; + for (int n = 1; n < argc; ++n) + args.append(QString::fromLocal8Bit(argv[n])); + parseCmdLine(args); + + QList<ClassDef> classes; + + for (int i = 0; i < args.count(); ++i) { + const QString arg = args.at(i); + + if (arg.startsWith(QLatin1Char('-'))) + continue; + + QFile f(arg); + if (!f.open(QIODevice::ReadOnly|QIODevice::Text)) { + fprintf(stderr, PROGRAMNAME ": could not open '%s': %s\n", + qPrintable(arg), qPrintable(f.errorString())); + return 1; + } + + Preprocessor pp; + Moc moc(pp); + pp.macros["Q_MOC_RUN"]; + pp.macros["__cplusplus"]; + + const QByteArray filename = QFile::decodeName(argv[i]).toLatin1(); + + moc.filename = filename; + moc.currentFilenames.push(filename); + + moc.symbols = pp.preprocessed(moc.filename, &f); + moc.parse(); + + if (moc.classList.isEmpty()) + return 0; + classes = moc.classList; + + f.close(); + } + + QFile output; + if (outputFile.isEmpty()) { + output.open(stdout, QIODevice::WriteOnly); + } else { + output.setFileName(outputFile); + if (!output.open(QIODevice::WriteOnly)) { + fprintf(stderr, PROGRAMNAME ": could not open output file '%s': %s", + qPrintable(outputFile), qPrintable(output.errorString())); + return 1; + } + } + + output.write(docTypeHeader); + output.write("<node>\n"); + foreach (const ClassDef &cdef, classes) { + QString xml = qDBusGenerateClassDefXml(&cdef); + output.write(xml.toLocal8Bit()); + } + output.write("</node>\n"); + + return 0; +} + diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro b/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro new file mode 100644 index 0000000000..33f7937c5b --- /dev/null +++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.pro @@ -0,0 +1,34 @@ + +TEMPLATE = app +TARGET = qdbuscpp2xml + +DESTDIR = ../../../bin + +include(../moc/moc.pri) + +INCLUDEPATH += . +DEPENDPATH += . + +INCLUDEPATH += $$QT_BUILD_TREE/include \ + $$QT_BUILD_TREE/include/QtDBus \ + $$QT_BUILD_TREE/include/QtDBus/$$QT.dbus.VERSION \ + $$QT_BUILD_TREE/include/QtDBus/$$QT.dbus.VERSION/QtDBus \ + $$QT_SOURCE_TREE/src/dbus + +QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS + +SOURCES += qdbuscpp2xml.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusmetatype.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusutil.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusmisc.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusargument.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusmarshaller.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusextratypes.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbus_symbols.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusunixfiledescriptor.cpp + +include(../bootstrap/bootstrap.pri) + +target.path = $$[QT_HOST_BINS] +INSTALLS += target +load(qt_targets) diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp new file mode 100644 index 0000000000..8c75c8a27b --- /dev/null +++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp @@ -0,0 +1,1178 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qbytearray.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qdebug.h> +#include <QtCore/qfile.h> +#include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qtextstream.h> +#include <QtCore/qset.h> + +#include "qdbusmetatype.h" +#include "private/qdbusintrospection_p.h" + +#include <stdio.h> +#include <stdlib.h> + +#define PROGRAMNAME "qdbusxml2cpp" +#define PROGRAMVERSION "0.8" +#define PROGRAMCOPYRIGHT "Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)." + +#define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply" + +static QString globalClassName; +static QString parentClassName; +static QString proxyFile; +static QString adaptorFile; +static QString inputFile; +static bool skipNamespaces; +static bool verbose; +static bool includeMocs; +static QString commandLine; +static QStringList includes; +static QStringList wantedInterfaces; + +static const char help[] = + "Usage: " PROGRAMNAME " [options...] [xml-or-xml-file] [interfaces...]\n" + "Produces the C++ code to implement the interfaces defined in the input file.\n" + "\n" + "Options:\n" + " -a <filename> Write the adaptor code to <filename>\n" + " -c <classname> Use <classname> as the class name for the generated classes\n" + " -h Show this information\n" + " -i <filename> Add #include to the output\n" + " -l <classname> When generating an adaptor, use <classname> as the parent class\n" + " -m Generate #include \"filename.moc\" statements in the .cpp files\n" + " -N Don't use namespaces\n" + " -p <filename> Write the proxy code to <filename>\n" + " -v Be verbose.\n" + " -V Show the program version and quit.\n" + "\n" + "If the file name given to the options -a and -p does not end in .cpp or .h, the\n" + "program will automatically append the suffixes and produce both files.\n" + "You can also use a colon (:) to separate the header name from the source file\n" + "name, as in '-a filename_p.h:filename.cpp'.\n" + "\n" + "If you pass a dash (-) as the argument to either -p or -a, the output is written\n" + "to the standard output\n"; + +static const char includeList[] = + "#include <QtCore/QByteArray>\n" + "#include <QtCore/QList>\n" + "#include <QtCore/QMap>\n" + "#include <QtCore/QString>\n" + "#include <QtCore/QStringList>\n" + "#include <QtCore/QVariant>\n"; + +static const char forwardDeclarations[] = + "QT_BEGIN_NAMESPACE\n" + "class QByteArray;\n" + "template<class T> class QList;\n" + "template<class Key, class Value> class QMap;\n" + "class QString;\n" + "class QStringList;\n" + "class QVariant;\n" + "QT_END_NAMESPACE\n"; + +static void showHelp() +{ + printf("%s", help); + exit(0); +} + +static void showVersion() +{ + printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION); + printf("D-Bus binding tool for Qt\n"); + exit(0); +} + +static QString nextArg(QStringList &args, int i, char opt) +{ + QString arg = args.value(i); + if (arg.isEmpty()) { + printf("-%c needs at least one argument\n", opt); + exit(1); + } + return args.takeAt(i); +} + +static void parseCmdLine(QStringList args) +{ + args.takeFirst(); + + commandLine = QLatin1String(PROGRAMNAME " "); + commandLine += args.join(QLatin1String(" ")); + + int i = 0; + while (i < args.count()) { + + if (!args.at(i).startsWith(QLatin1Char('-'))) { + ++i; + continue; + } + QString arg = args.takeAt(i); + + char c = '\0'; + if (arg.length() == 2) + c = arg.at(1).toLatin1(); + else if (arg == QLatin1String("--help")) + c = 'h'; + + switch (c) { + case 'a': + adaptorFile = nextArg(args, i, 'a'); + break; + + case 'c': + globalClassName = nextArg(args, i, 'c'); + break; + + case 'v': + verbose = true; + break; + + case 'i': + includes << nextArg(args, i, 'i'); + break; + + case 'l': + parentClassName = nextArg(args, i, 'l'); + break; + + case 'm': + includeMocs = true; + break; + + case 'N': + skipNamespaces = true; + break; + + case '?': + case 'h': + showHelp(); + break; + + case 'V': + showVersion(); + break; + + case 'p': + proxyFile = nextArg(args, i, 'p'); + break; + + default: + printf("unknown option: '%s'\n", qPrintable(arg)); + exit(1); + } + } + + if (!args.isEmpty()) + inputFile = args.takeFirst(); + + wantedInterfaces << args; +} + +static QDBusIntrospection::Interfaces readInput() +{ + QFile input(inputFile); + if (inputFile.isEmpty() || inputFile == QLatin1String("-")) + input.open(stdin, QIODevice::ReadOnly); + else + input.open(QIODevice::ReadOnly); + + QByteArray data = input.readAll(); + + // check if the input is already XML + data = data.trimmed(); + if (data.startsWith("<!DOCTYPE ") || data.startsWith("<?xml") || + data.startsWith("<node") || data.startsWith("<interface")) + // already XML + return QDBusIntrospection::parseInterfaces(QString::fromUtf8(data)); + + fprintf(stderr, "Cannot process input: '%s'. Stop.\n", qPrintable(inputFile)); + exit(1); +} + +static void cleanInterfaces(QDBusIntrospection::Interfaces &interfaces) +{ + if (!wantedInterfaces.isEmpty()) { + QDBusIntrospection::Interfaces::Iterator it = interfaces.begin(); + while (it != interfaces.end()) + if (!wantedInterfaces.contains(it.key())) + it = interfaces.erase(it); + else + ++it; + } +} + +// produce a header name from the file name +static QString header(const QString &name) +{ + QStringList parts = name.split(QLatin1Char(':')); + QString retval = parts.first(); + + if (retval.isEmpty() || retval == QLatin1String("-")) + return retval; + + if (!retval.endsWith(QLatin1String(".h")) && !retval.endsWith(QLatin1String(".cpp")) && + !retval.endsWith(QLatin1String(".cc"))) + retval.append(QLatin1String(".h")); + + return retval; +} + +// produce a cpp name from the file name +static QString cpp(const QString &name) +{ + QStringList parts = name.split(QLatin1Char(':')); + QString retval = parts.last(); + + if (retval.isEmpty() || retval == QLatin1String("-")) + return retval; + + if (!retval.endsWith(QLatin1String(".h")) && !retval.endsWith(QLatin1String(".cpp")) && + !retval.endsWith(QLatin1String(".cc"))) + retval.append(QLatin1String(".cpp")); + + return retval; +} + +// produce a moc name from the file name +static QString moc(const QString &name) +{ + QString retval = header(name); + if (retval.isEmpty()) + return retval; + + retval.truncate(retval.length() - 1); // drop the h in .h + retval += QLatin1String("moc"); + return retval; +} + +static QTextStream &writeHeader(QTextStream &ts, bool changesWillBeLost) +{ + ts << "/*" << endl + << " * This file was generated by " PROGRAMNAME " version " PROGRAMVERSION << endl + << " * Command line was: " << commandLine << endl + << " *" << endl + << " * " PROGRAMNAME " is " PROGRAMCOPYRIGHT << endl + << " *" << endl + << " * This is an auto-generated file." << endl; + + if (changesWillBeLost) + ts << " * Do not edit! All changes made to it will be lost." << endl; + else + ts << " * This file may have been hand-edited. Look for HAND-EDIT comments" << endl + << " * before re-generating it." << endl; + + ts << " */" << endl + << endl; + + return ts; +} + +enum ClassType { Proxy, Adaptor }; +static QString classNameForInterface(const QString &interface, ClassType classType) +{ + if (!globalClassName.isEmpty()) + return globalClassName; + + QStringList parts = interface.split(QLatin1Char('.')); + + QString retval; + if (classType == Proxy) + foreach (QString part, parts) { + part[0] = part[0].toUpper(); + retval += part; + } + else { + retval = parts.last(); + retval[0] = retval[0].toUpper(); + } + + if (classType == Proxy) + retval += QLatin1String("Interface"); + else + retval += QLatin1String("Adaptor"); + + return retval; +} + +static QByteArray qtTypeName(const QString &signature, const QDBusIntrospection::Annotations &annotations, int paramId = -1, const char *direction = "Out") +{ + int type = QDBusMetaType::signatureToType(signature.toLatin1()); + if (type == QVariant::Invalid) { + QString annotationName = QString::fromLatin1("org.qtproject.QtDBus.QtTypeName"); + if (paramId >= 0) + annotationName += QString::fromLatin1(".%1%2").arg(QLatin1String(direction)).arg(paramId); + QString qttype = annotations.value(annotationName); + if (!qttype.isEmpty()) + return qttype.toLatin1(); + + QString oldAnnotationName = QString::fromLatin1("com.trolltech.QtDBus.QtTypeName"); + if (paramId >= 0) + oldAnnotationName += QString::fromLatin1(".%1%2").arg(QLatin1String(direction)).arg(paramId); + qttype = annotations.value(annotationName); + + if (qttype.isEmpty()) { + fprintf(stderr, "Got unknown type `%s'\n", qPrintable(signature)); + fprintf(stderr, "You should add <annotation name=\"%s\" value=\"<type>\"/> to the XML description\n", + qPrintable(annotationName)); + exit(1); + } + + fprintf(stderr, "Warning: deprecated annotation '%s' found; suggest updating to '%s'\n", + qPrintable(oldAnnotationName), qPrintable(annotationName)); + return qttype.toLatin1(); + } + + return QVariant::typeToName(QVariant::Type(type)); +} + +static QString nonConstRefArg(const QByteArray &arg) +{ + return QLatin1String(arg + " &"); +} + +static QString templateArg(const QByteArray &arg) +{ + if (!arg.endsWith('>')) + return QLatin1String(arg); + + return QLatin1String(arg + ' '); +} + +static QString constRefArg(const QByteArray &arg) +{ + if (!arg.startsWith('Q')) + return QLatin1String(arg + ' '); + else + return QString( QLatin1String("const %1 &") ).arg( QLatin1String(arg) ); +} + +static QStringList makeArgNames(const QDBusIntrospection::Arguments &inputArgs, + const QDBusIntrospection::Arguments &outputArgs = + QDBusIntrospection::Arguments()) +{ + QStringList retval; + for (int i = 0; i < inputArgs.count(); ++i) { + const QDBusIntrospection::Argument &arg = inputArgs.at(i); + QString name = arg.name; + if (name.isEmpty()) + name = QString( QLatin1String("in%1") ).arg(i); + while (retval.contains(name)) + name += QLatin1String("_"); + retval << name; + } + for (int i = 0; i < outputArgs.count(); ++i) { + const QDBusIntrospection::Argument &arg = outputArgs.at(i); + QString name = arg.name; + if (name.isEmpty()) + name = QString( QLatin1String("out%1") ).arg(i); + while (retval.contains(name)) + name += QLatin1String("_"); + retval << name; + } + return retval; +} + +static void writeArgList(QTextStream &ts, const QStringList &argNames, + const QDBusIntrospection::Annotations &annotations, + const QDBusIntrospection::Arguments &inputArgs, + const QDBusIntrospection::Arguments &outputArgs = QDBusIntrospection::Arguments()) +{ + // input args: + bool first = true; + int argPos = 0; + for (int i = 0; i < inputArgs.count(); ++i) { + const QDBusIntrospection::Argument &arg = inputArgs.at(i); + QString type = constRefArg(qtTypeName(arg.type, annotations, i, "In")); + + if (!first) + ts << ", "; + ts << type << argNames.at(argPos++); + first = false; + } + + argPos++; + + // output args + // yes, starting from 1 + for (int i = 1; i < outputArgs.count(); ++i) { + const QDBusIntrospection::Argument &arg = outputArgs.at(i); + QString name = arg.name; + + if (!first) + ts << ", "; + ts << nonConstRefArg(qtTypeName(arg.type, annotations, i, "Out")) + << argNames.at(argPos++); + first = false; + } +} + +static QString propertyGetter(const QDBusIntrospection::Property &property) +{ + QString getter = property.annotations.value(QLatin1String("org.qtproject.QtDBus.PropertyGetter")); + if (!getter.isEmpty()) + return getter; + + getter = property.annotations.value(QLatin1String("com.trolltech.QtDBus.propertyGetter")); + if (!getter.isEmpty()) { + fprintf(stderr, "Warning: deprecated annotation 'com.trolltech.QtDBus.propertyGetter' found;" + " suggest updating to 'org.qtproject.QtDBus.PropertyGetter'\n"); + return getter; + } + + getter = property.name; + getter[0] = getter[0].toLower(); + return getter; +} + +static QString propertySetter(const QDBusIntrospection::Property &property) +{ + QString setter = property.annotations.value(QLatin1String("org.qtproject.QtDBus.PropertySetter")); + if (!setter.isEmpty()) + return setter; + + setter = property.annotations.value(QLatin1String("com.trolltech.QtDBus.propertySetter")); + if (!setter.isEmpty()) { + fprintf(stderr, "Warning: deprecated annotation 'com.trolltech.QtDBus.propertySetter' found;" + " suggest updating to 'org.qtproject.QtDBus.PropertySetter'\n"); + return setter; + } + + setter = QLatin1String("set") + property.name; + setter[3] = setter[3].toUpper(); + return setter; +} + +static QString stringify(const QString &data) +{ + QString retval; + int i; + for (i = 0; i < data.length(); ++i) { + retval += QLatin1Char('\"'); + for ( ; i < data.length() && data[i] != QLatin1Char('\n') && data[i] != QLatin1Char('\r'); ++i) + if (data[i] == QLatin1Char('\"')) + retval += QLatin1String("\\\""); + else + retval += data[i]; + if (data[i] == QLatin1Char('\r') && data[i+1] == QLatin1Char('\n')) + i++; + retval += QLatin1String("\\n\"\n"); + } + return retval; +} + +static void openFile(const QString &fileName, QFile &file) +{ + if (fileName.isEmpty()) + return; + + bool isOk = false; + if (fileName == QLatin1String("-")) { + isOk = file.open(stdout, QIODevice::WriteOnly | QIODevice::Text); + } else { + file.setFileName(fileName); + isOk = file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text); + } + + if (!isOk) + fprintf(stderr, "Unable to open '%s': %s\n", qPrintable(fileName), + qPrintable(file.errorString())); +} + +static void writeProxy(const QString &filename, const QDBusIntrospection::Interfaces &interfaces) +{ + // open the file + QString headerName = header(filename); + QByteArray headerData; + QTextStream hs(&headerData); + + QString cppName = cpp(filename); + QByteArray cppData; + QTextStream cs(&cppData); + + // write the header: + writeHeader(hs, true); + if (cppName != headerName) + writeHeader(cs, false); + + // include guards: + QString includeGuard; + if (!headerName.isEmpty() && headerName != QLatin1String("-")) { + includeGuard = headerName.toUpper().replace(QLatin1Char('.'), QLatin1Char('_')); + int pos = includeGuard.lastIndexOf(QLatin1Char('/')); + if (pos != -1) + includeGuard = includeGuard.mid(pos + 1); + } else { + includeGuard = QLatin1String("QDBUSXML2CPP_PROXY"); + } + includeGuard = QString(QLatin1String("%1_%2")) + .arg(includeGuard) + .arg(QDateTime::currentDateTime().toTime_t()); + hs << "#ifndef " << includeGuard << endl + << "#define " << includeGuard << endl + << endl; + + // include our stuff: + hs << "#include <QtCore/QObject>" << endl + << includeList + << "#include <QtDBus/QtDBus>" << endl; + + foreach (QString include, includes) { + hs << "#include \"" << include << "\"" << endl; + if (headerName.isEmpty()) + cs << "#include \"" << include << "\"" << endl; + } + + hs << endl; + + if (cppName != headerName) { + if (!headerName.isEmpty() && headerName != QLatin1String("-")) + cs << "#include \"" << headerName << "\"" << endl << endl; + } + + foreach (const QDBusIntrospection::Interface *interface, interfaces) { + QString className = classNameForInterface(interface->name, Proxy); + + // comment: + hs << "/*" << endl + << " * Proxy class for interface " << interface->name << endl + << " */" << endl; + cs << "/*" << endl + << " * Implementation of interface class " << className << endl + << " */" << endl + << endl; + + // class header: + hs << "class " << className << ": public QDBusAbstractInterface" << endl + << "{" << endl + << " Q_OBJECT" << endl; + + // the interface name + hs << "public:" << endl + << " static inline const char *staticInterfaceName()" << endl + << " { return \"" << interface->name << "\"; }" << endl + << endl; + + // constructors/destructors: + hs << "public:" << endl + << " " << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);" << endl + << endl + << " ~" << className << "();" << endl + << endl; + cs << className << "::" << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)" << endl + << " : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)" << endl + << "{" << endl + << "}" << endl + << endl + << className << "::~" << className << "()" << endl + << "{" << endl + << "}" << endl + << endl; + + // properties: + foreach (const QDBusIntrospection::Property &property, interface->properties) { + QByteArray type = qtTypeName(property.type, property.annotations); + QString templateType = templateArg(type); + QString constRefType = constRefArg(type); + QString getter = propertyGetter(property); + QString setter = propertySetter(property); + + hs << " Q_PROPERTY(" << type << " " << property.name; + + // getter: + if (property.access != QDBusIntrospection::Property::Write) + // it's readble + hs << " READ " << getter; + + // setter + if (property.access != QDBusIntrospection::Property::Read) + // it's writeable + hs << " WRITE " << setter; + + hs << ")" << endl; + + // getter: + if (property.access != QDBusIntrospection::Property::Write) { + hs << " inline " << type << " " << getter << "() const" << endl + << " { return qvariant_cast< " << type << " >(property(\"" + << property.name << "\")); }" << endl; + } + + // setter: + if (property.access != QDBusIntrospection::Property::Read) { + hs << " inline void " << setter << "(" << constRefArg(type) << "value)" << endl + << " { setProperty(\"" << property.name + << "\", QVariant::fromValue(value)); }" << endl; + } + + hs << endl; + } + + // methods: + hs << "public Q_SLOTS: // METHODS" << endl; + foreach (const QDBusIntrospection::Method &method, interface->methods) { + bool isDeprecated = method.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) == QLatin1String("true"); + bool isNoReply = + method.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true"); + if (isNoReply && !method.outputArgs.isEmpty()) { + fprintf(stderr, "warning: method %s in interface %s is marked 'no-reply' but has output arguments.\n", + qPrintable(method.name), qPrintable(interface->name)); + continue; + } + + hs << " inline " + << (isDeprecated ? "Q_DECL_DEPRECATED " : ""); + + if (isNoReply) { + hs << "Q_NOREPLY void "; + } else { + hs << "QDBusPendingReply<"; + for (int i = 0; i < method.outputArgs.count(); ++i) + hs << (i > 0 ? ", " : "") + << templateArg(qtTypeName(method.outputArgs.at(i).type, method.annotations, i, "Out")); + hs << "> "; + } + + hs << method.name << "("; + + QStringList argNames = makeArgNames(method.inputArgs); + writeArgList(hs, argNames, method.annotations, method.inputArgs); + + hs << ")" << endl + << " {" << endl + << " QList<QVariant> argumentList;" << endl; + + if (!method.inputArgs.isEmpty()) { + hs << " argumentList"; + for (int argPos = 0; argPos < method.inputArgs.count(); ++argPos) + hs << " << QVariant::fromValue(" << argNames.at(argPos) << ')'; + hs << ";" << endl; + } + + if (isNoReply) + hs << " callWithArgumentList(QDBus::NoBlock, " + << "QLatin1String(\"" << method.name << "\"), argumentList);" << endl; + else + hs << " return asyncCallWithArgumentList(QLatin1String(\"" + << method.name << "\"), argumentList);" << endl; + + // close the function: + hs << " }" << endl; + + if (method.outputArgs.count() > 1) { + // generate the old-form QDBusReply methods with multiple incoming parameters + hs << " inline " + << (isDeprecated ? "Q_DECL_DEPRECATED " : "") + << "QDBusReply<" + << templateArg(qtTypeName(method.outputArgs.first().type, method.annotations, 0, "Out")) << "> "; + hs << method.name << "("; + + QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs); + writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs); + + hs << ")" << endl + << " {" << endl + << " QList<QVariant> argumentList;" << endl; + + int argPos = 0; + if (!method.inputArgs.isEmpty()) { + hs << " argumentList"; + for (argPos = 0; argPos < method.inputArgs.count(); ++argPos) + hs << " << QVariant::fromValue(" << argNames.at(argPos) << ')'; + hs << ";" << endl; + } + + hs << " QDBusMessage reply = callWithArgumentList(QDBus::Block, " + << "QLatin1String(\"" << method.name << "\"), argumentList);" << endl; + + argPos++; + hs << " if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == " + << method.outputArgs.count() << ") {" << endl; + + // yes, starting from 1 + for (int i = 1; i < method.outputArgs.count(); ++i) + hs << " " << argNames.at(argPos++) << " = qdbus_cast<" + << templateArg(qtTypeName(method.outputArgs.at(i).type, method.annotations, i, "Out")) + << ">(reply.arguments().at(" << i << "));" << endl; + hs << " }" << endl + << " return reply;" << endl + << " }" << endl; + } + + hs << endl; + } + + hs << "Q_SIGNALS: // SIGNALS" << endl; + foreach (const QDBusIntrospection::Signal &signal, interface->signals_) { + hs << " "; + if (signal.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) == + QLatin1String("true")) + hs << "Q_DECL_DEPRECATED "; + + hs << "void " << signal.name << "("; + + QStringList argNames = makeArgNames(signal.outputArgs); + writeArgList(hs, argNames, signal.annotations, signal.outputArgs); + + hs << ");" << endl; // finished for header + } + + // close the class: + hs << "};" << endl + << endl; + } + + if (!skipNamespaces) { + QStringList last; + QDBusIntrospection::Interfaces::ConstIterator it = interfaces.constBegin(); + do + { + QStringList current; + QString name; + if (it != interfaces.constEnd()) { + current = it->constData()->name.split(QLatin1Char('.')); + name = current.takeLast(); + } + + int i = 0; + while (i < current.count() && i < last.count() && current.at(i) == last.at(i)) + ++i; + + // i parts matched + // close last.arguments().count() - i namespaces: + for (int j = i; j < last.count(); ++j) + hs << QString((last.count() - j - 1 + i) * 2, QLatin1Char(' ')) << "}" << endl; + + // open current.arguments().count() - i namespaces + for (int j = i; j < current.count(); ++j) + hs << QString(j * 2, QLatin1Char(' ')) << "namespace " << current.at(j) << " {" << endl; + + // add this class: + if (!name.isEmpty()) { + hs << QString(current.count() * 2, QLatin1Char(' ')) + << "typedef ::" << classNameForInterface(it->constData()->name, Proxy) + << " " << name << ";" << endl; + } + + if (it == interfaces.constEnd()) + break; + ++it; + last = current; + } while (true); + } + + // close the include guard + hs << "#endif" << endl; + + QString mocName = moc(filename); + if (includeMocs && !mocName.isEmpty()) + cs << endl + << "#include \"" << mocName << "\"" << endl; + + cs.flush(); + hs.flush(); + + QFile file; + openFile(headerName, file); + file.write(headerData); + + if (headerName == cppName) { + file.write(cppData); + } else { + QFile cppFile; + openFile(cppName, cppFile); + cppFile.write(cppData); + } +} + +static void writeAdaptor(const QString &filename, const QDBusIntrospection::Interfaces &interfaces) +{ + // open the file + QString headerName = header(filename); + QByteArray headerData; + QTextStream hs(&headerData); + + QString cppName = cpp(filename); + QByteArray cppData; + QTextStream cs(&cppData); + + // write the headers + writeHeader(hs, false); + if (cppName != headerName) + writeHeader(cs, true); + + // include guards: + QString includeGuard; + if (!headerName.isEmpty() && headerName != QLatin1String("-")) { + includeGuard = headerName.toUpper().replace(QLatin1Char('.'), QLatin1Char('_')); + int pos = includeGuard.lastIndexOf(QLatin1Char('/')); + if (pos != -1) + includeGuard = includeGuard.mid(pos + 1); + } else { + includeGuard = QLatin1String("QDBUSXML2CPP_ADAPTOR"); + } + includeGuard = QString(QLatin1String("%1_%2")) + .arg(includeGuard) + .arg(QDateTime::currentDateTime().toTime_t()); + hs << "#ifndef " << includeGuard << endl + << "#define " << includeGuard << endl + << endl; + + // include our stuff: + hs << "#include <QtCore/QObject>" << endl; + if (cppName == headerName) + hs << "#include <QtCore/QMetaObject>" << endl + << "#include <QtCore/QVariant>" << endl; + hs << "#include <QtDBus/QtDBus>" << endl; + + foreach (QString include, includes) { + hs << "#include \"" << include << "\"" << endl; + if (headerName.isEmpty()) + cs << "#include \"" << include << "\"" << endl; + } + + if (cppName != headerName) { + if (!headerName.isEmpty() && headerName != QLatin1String("-")) + cs << "#include \"" << headerName << "\"" << endl; + + cs << "#include <QtCore/QMetaObject>" << endl + << includeList + << endl; + hs << forwardDeclarations; + } else { + hs << includeList; + } + + hs << endl; + + QString parent = parentClassName; + if (parentClassName.isEmpty()) + parent = QLatin1String("QObject"); + + foreach (const QDBusIntrospection::Interface *interface, interfaces) { + QString className = classNameForInterface(interface->name, Adaptor); + + // comment: + hs << "/*" << endl + << " * Adaptor class for interface " << interface->name << endl + << " */" << endl; + cs << "/*" << endl + << " * Implementation of adaptor class " << className << endl + << " */" << endl + << endl; + + // class header: + hs << "class " << className << ": public QDBusAbstractAdaptor" << endl + << "{" << endl + << " Q_OBJECT" << endl + << " Q_CLASSINFO(\"D-Bus Interface\", \"" << interface->name << "\")" << endl + << " Q_CLASSINFO(\"D-Bus Introspection\", \"\"" << endl + << stringify(interface->introspection) + << " \"\")" << endl + << "public:" << endl + << " " << className << "(" << parent << " *parent);" << endl + << " virtual ~" << className << "();" << endl + << endl; + + if (!parentClassName.isEmpty()) + hs << " inline " << parent << " *parent() const" << endl + << " { return static_cast<" << parent << " *>(QObject::parent()); }" << endl + << endl; + + // constructor/destructor + cs << className << "::" << className << "(" << parent << " *parent)" << endl + << " : QDBusAbstractAdaptor(parent)" << endl + << "{" << endl + << " // constructor" << endl + << " setAutoRelaySignals(true);" << endl + << "}" << endl + << endl + << className << "::~" << className << "()" << endl + << "{" << endl + << " // destructor" << endl + << "}" << endl + << endl; + + hs << "public: // PROPERTIES" << endl; + foreach (const QDBusIntrospection::Property &property, interface->properties) { + QByteArray type = qtTypeName(property.type, property.annotations); + QString constRefType = constRefArg(type); + QString getter = propertyGetter(property); + QString setter = propertySetter(property); + + hs << " Q_PROPERTY(" << type << " " << property.name; + if (property.access != QDBusIntrospection::Property::Write) + hs << " READ " << getter; + if (property.access != QDBusIntrospection::Property::Read) + hs << " WRITE " << setter; + hs << ")" << endl; + + // getter: + if (property.access != QDBusIntrospection::Property::Write) { + hs << " " << type << " " << getter << "() const;" << endl; + cs << type << " " + << className << "::" << getter << "() const" << endl + << "{" << endl + << " // get the value of property " << property.name << endl + << " return qvariant_cast< " << type <<" >(parent()->property(\"" << property.name << "\"));" << endl + << "}" << endl + << endl; + } + + // setter + if (property.access != QDBusIntrospection::Property::Read) { + hs << " void " << setter << "(" << constRefType << "value);" << endl; + cs << "void " << className << "::" << setter << "(" << constRefType << "value)" << endl + << "{" << endl + << " // set the value of property " << property.name << endl + << " parent()->setProperty(\"" << property.name << "\", QVariant::fromValue(value"; + if (constRefType.contains(QLatin1String("QDBusVariant"))) + cs << ".variant()"; + cs << "));" << endl + << "}" << endl + << endl; + } + + hs << endl; + } + + hs << "public Q_SLOTS: // METHODS" << endl; + foreach (const QDBusIntrospection::Method &method, interface->methods) { + bool isNoReply = + method.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true"); + if (isNoReply && !method.outputArgs.isEmpty()) { + fprintf(stderr, "warning: method %s in interface %s is marked 'no-reply' but has output arguments.\n", + qPrintable(method.name), qPrintable(interface->name)); + continue; + } + + hs << " "; + if (method.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) == + QLatin1String("true")) + hs << "Q_DECL_DEPRECATED "; + + QByteArray returnType; + if (isNoReply) { + hs << "Q_NOREPLY void "; + cs << "void "; + } else if (method.outputArgs.isEmpty()) { + hs << "void "; + cs << "void "; + } else { + returnType = qtTypeName(method.outputArgs.first().type, method.annotations, 0, "Out"); + hs << returnType << " "; + cs << returnType << " "; + } + + QString name = method.name; + hs << name << "("; + cs << className << "::" << name << "("; + + QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs); + writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs); + writeArgList(cs, argNames, method.annotations, method.inputArgs, method.outputArgs); + + hs << ");" << endl; // finished for header + cs << ")" << endl + << "{" << endl + << " // handle method call " << interface->name << "." << method.name << endl; + + // make the call + bool usingInvokeMethod = false; + if (parentClassName.isEmpty() && method.inputArgs.count() <= 10 + && method.outputArgs.count() <= 1) + usingInvokeMethod = true; + + if (usingInvokeMethod) { + // we are using QMetaObject::invokeMethod + if (!returnType.isEmpty()) + cs << " " << returnType << " " << argNames.at(method.inputArgs.count()) + << ";" << endl; + + static const char invoke[] = " QMetaObject::invokeMethod(parent(), \""; + cs << invoke << name << "\""; + + if (!method.outputArgs.isEmpty()) + cs << ", Q_RETURN_ARG(" + << qtTypeName(method.outputArgs.at(0).type, method.annotations, + 0, "Out") + << ", " + << argNames.at(method.inputArgs.count()) + << ")"; + + for (int i = 0; i < method.inputArgs.count(); ++i) + cs << ", Q_ARG(" + << qtTypeName(method.inputArgs.at(i).type, method.annotations, + i, "In") + << ", " + << argNames.at(i) + << ")"; + + cs << ");" << endl; + + if (!returnType.isEmpty()) + cs << " return " << argNames.at(method.inputArgs.count()) << ";" << endl; + } else { + if (parentClassName.isEmpty()) + cs << " //"; + else + cs << " "; + + if (!method.outputArgs.isEmpty()) + cs << "return "; + + if (parentClassName.isEmpty()) + cs << "static_cast<YourObjectType *>(parent())->"; + else + cs << "parent()->"; + cs << name << "("; + + int argPos = 0; + bool first = true; + for (int i = 0; i < method.inputArgs.count(); ++i) { + cs << (first ? "" : ", ") << argNames.at(argPos++); + first = false; + } + ++argPos; // skip retval, if any + for (int i = 1; i < method.outputArgs.count(); ++i) { + cs << (first ? "" : ", ") << argNames.at(argPos++); + first = false; + } + + cs << ");" << endl; + } + cs << "}" << endl + << endl; + } + + hs << "Q_SIGNALS: // SIGNALS" << endl; + foreach (const QDBusIntrospection::Signal &signal, interface->signals_) { + hs << " "; + if (signal.annotations.value(QLatin1String("org.freedesktop.DBus.Deprecated")) == + QLatin1String("true")) + hs << "Q_DECL_DEPRECATED "; + + hs << "void " << signal.name << "("; + + QStringList argNames = makeArgNames(signal.outputArgs); + writeArgList(hs, argNames, signal.annotations, signal.outputArgs); + + hs << ");" << endl; // finished for header + } + + // close the class: + hs << "};" << endl + << endl; + } + + // close the include guard + hs << "#endif" << endl; + + QString mocName = moc(filename); + if (includeMocs && !mocName.isEmpty()) + cs << endl + << "#include \"" << mocName << "\"" << endl; + + cs.flush(); + hs.flush(); + + QFile file; + openFile(headerName, file); + file.write(headerData); + + if (headerName == cppName) { + file.write(cppData); + } else { + QFile cppFile; + openFile(cppName, cppFile); + cppFile.write(cppData); + } +} + +int main(int argc, char **argv) +{ + QStringList arguments; + + for (int i = 0; i < argc; ++i) { + arguments.append(QString::fromLocal8Bit(argv[i])); + } + + parseCmdLine(arguments); + + QDBusIntrospection::Interfaces interfaces = readInput(); + cleanInterfaces(interfaces); + + if (!proxyFile.isEmpty() || adaptorFile.isEmpty()) + writeProxy(proxyFile, interfaces); + + if (!adaptorFile.isEmpty()) + writeAdaptor(adaptorFile, interfaces); + + return 0; +} + +/*! + \page qdbusxml2cpp.html + \title QtDBus XML compiler (qdbusxml2cpp) + \keyword qdbusxml2cpp + + The QtDBus XML compiler is a tool that can be used to parse interface descriptions and produce + static code representing those interfaces, which can then be used to make calls to remote + objects or implement said interfaces. + + \c qdbusxml2cpp has two modes of operation, that correspond to the two possible outputs it can + produce: the interface (proxy) class or the adaptor class. The latter consists of both a C++ + header and a source file, which are meant to be edited and adapted to your needs. + + The \c qdbusxml2cpp tool is not meant to be run every time you compile your + application. Instead, it's meant to be used when developing the code or when the interface + changes. + + The adaptor classes generated by \c qdbusxml2cpp are just a skeleton that must be completed. It + generates, by default, calls to slots with the same name on the object the adaptor is attached + to. However, you may modify those slots or the property accessor functions to suit your needs. +*/ diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.pro b/src/tools/qdbusxml2cpp/qdbusxml2cpp.pro new file mode 100644 index 0000000000..5c430fdfb1 --- /dev/null +++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.pro @@ -0,0 +1,33 @@ +TEMPLATE = app +TARGET = qdbusxml2cpp + +DESTDIR = ../../../bin + +INCLUDEPATH += . +DEPENDPATH += . + +include(../bootstrap/bootstrap.pri) + +INCLUDEPATH += $$QT_BUILD_TREE/include \ + $$QT_BUILD_TREE/include/QtDBus \ + $$QT_BUILD_TREE/include/QtDBus/$$QT.dbus.VERSION \ + $$QT_BUILD_TREE/include/QtDBus/$$QT.dbus.VERSION/QtDBus \ + $$QT_SOURCE_TREE/src/dbus + +QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS + +SOURCES = qdbusxml2cpp.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusintrospection.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusxmlparser.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbuserror.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusutil.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusmetatype.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusargument.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusmarshaller.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusextratypes.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbus_symbols.cpp \ + $$QT_SOURCE_TREE/src/dbus/qdbusunixfiledescriptor.cpp + +target.path = $$[QT_HOST_BINS] +INSTALLS += target +load(qt_targets) diff --git a/src/tools/qdoc/qmlparser/qqmljsmemorypool_p.h b/src/tools/qdoc/qmlparser/qqmljsmemorypool_p.h index fd52fd25e4..113166644a 100644 --- a/src/tools/qdoc/qmlparser/qqmljsmemorypool_p.h +++ b/src/tools/qdoc/qmlparser/qqmljsmemorypool_p.h @@ -60,6 +60,7 @@ #include <QtCore/qdebug.h> #include <cstring> +#include <stdlib.h> QT_QML_BEGIN_NAMESPACE @@ -84,10 +85,10 @@ public: if (_blocks) { for (int i = 0; i < _allocatedBlocks; ++i) { if (char *b = _blocks[i]) - qFree(b); + free(b); } - qFree(_blocks); + free(_blocks); } } @@ -119,7 +120,7 @@ private: else _allocatedBlocks *= 2; - _blocks = (char **) qRealloc(_blocks, sizeof(char *) * _allocatedBlocks); + _blocks = (char **) realloc(_blocks, sizeof(char *) * _allocatedBlocks); for (int index = _blockCount; index < _allocatedBlocks; ++index) _blocks[index] = 0; @@ -128,7 +129,7 @@ private: char *&block = _blocks[_blockCount]; if (! block) - block = (char *) qMalloc(BLOCK_SIZE); + block = (char *) malloc(BLOCK_SIZE); _ptr = block; _end = _ptr + BLOCK_SIZE; diff --git a/src/tools/rcc/main.cpp b/src/tools/rcc/main.cpp index 3873e74ee5..ad20b9e3ac 100644 --- a/src/tools/rcc/main.cpp +++ b/src/tools/rcc/main.cpp @@ -47,6 +47,8 @@ #include <QFile> #include <QFileInfo> #include <QTextStream> +#include <QAtomicInt> +#include <QtGlobal> QT_BEGIN_NAMESPACE @@ -254,9 +256,16 @@ int runRcc(int argc, char *argv[]) return library.output(out, errorDevice) ? 0 : 1; } +Q_CORE_EXPORT extern QBasicAtomicInt qt_qhash_seed; // from qhash.cpp + QT_END_NAMESPACE int main(int argc, char *argv[]) { + // rcc uses a QHash to store files in the resource system. + // we must force a certain hash order when testing or tst_rcc will fail, see QTBUG-25078 + if (!qgetenv("QT_RCC_TEST").isEmpty() && !qt_qhash_seed.testAndSetRelaxed(-1, 0)) + qFatal("Cannot force QHash seed for testing as requested"); + return QT_PREPEND_NAMESPACE(runRcc)(argc, argv); } diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp index 740ae91b68..2f2cfb679b 100644 --- a/src/tools/rcc/rcc.cpp +++ b/src/tools/rcc/rcc.cpp @@ -298,7 +298,7 @@ qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset) offset += 2; // write the hash - lib.writeNumber4(qHash(m_name)); + lib.writeNumber4(qt_hash(m_name)); if (text) lib.writeString("\n "); offset += 4; @@ -882,7 +882,7 @@ bool RCCResourceLibrary::writeDataNames() static bool qt_rcc_compare_hash(const RCCFileInfo *left, const RCCFileInfo *right) { - return qHash(left->m_name) < qHash(right->m_name); + return qt_hash(left->m_name) < qt_hash(right->m_name); } bool RCCResourceLibrary::writeDataStructure() diff --git a/src/tools/tools.pro b/src/tools/tools.pro index 8c2739a381..8ad30a998d 100644 --- a/src/tools/tools.pro +++ b/src/tools/tools.pro @@ -1,6 +1,7 @@ TEMPLATE = subdirs TOOLS_SUBDIRS = src_tools_bootstrap src_tools_moc src_tools_rcc src_tools_qdoc +contains(QT_CONFIG, dbus): TOOLS_SUBDIRS += src_tools_qdbusxml2cpp src_tools_qdbuscpp2xml !contains(QT_CONFIG, no-gui): TOOLS_SUBDIRS += src_tools_uic # Set subdir and respective target name src_tools_bootstrap.subdir = $$PWD/bootstrap @@ -13,6 +14,12 @@ src_tools_uic.subdir = $$PWD/uic src_tools_uic.target = sub-uic src_tools_qdoc.subdir = $$QT_SOURCE_TREE/src/tools/qdoc src_tools_qdoc.target = sub-qdoc +contains(QT_CONFIG, dbus) { + src_tools_qdbusxml2cpp.subdir = $$QT_SOURCE_TREE/src/tools/qdbusxml2cpp + src_tools_qdbusxml2cpp.target = sub-qdbusxml2cpp + src_tools_qdbuscpp2xml.subdir = $$QT_SOURCE_TREE/src/tools/qdbuscpp2xml + src_tools_qdbuscpp2xml.target = sub-qdbuscpp2xml +} !wince*:!ordered { # Set dependencies for each subdir @@ -20,6 +27,10 @@ src_tools_qdoc.target = sub-qdoc src_tools_rcc.depends = src_tools_bootstrap src_tools_uic.depends = src_tools_bootstrap src_tools_qdoc.depends = src_tools_bootstrap + contains(QT_CONFIG, dbus) { + src_tools_qdbusxml2cpp.depends = src_tools_bootstrap + src_tools_qdbuscpp2xml.depends = src_tools_bootstrap + } } # Special handling, depending on type of project, if it used debug/release or only has one configuration diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp index 5762c175cc..88636f4161 100644 --- a/src/tools/uic/cpp/cppwriteinitialization.cpp +++ b/src/tools/uic/cpp/cppwriteinitialization.cpp @@ -733,8 +733,6 @@ void WriteInitialization::acceptWidget(DomWidget *node) m_output << m_indent << parentWidget << "->addWidget(" << varName << ");\n"; } else if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QMdiArea"))) { m_output << m_indent << parentWidget << "->addSubWindow(" << varName << ");\n"; - } else if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QWorkspace"))) { - m_output << m_indent << parentWidget << "->addWindow(" << varName << ");\n"; } else if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QWizard"))) { addWizardPage(varName, node, parentWidget); } else if (m_uic->customWidgetsInfo()->extends(parentClass, QLatin1String("QToolBox"))) { diff --git a/src/tools/uic/qclass_lib_map.h b/src/tools/uic/qclass_lib_map.h index fb181e27f7..34ce374750 100644 --- a/src/tools/uic/qclass_lib_map.h +++ b/src/tools/uic/qclass_lib_map.h @@ -875,8 +875,6 @@ QT_CLASS_LIB(QStyleOptionToolBar, QtWidgets, qstyleoption.h) QT_CLASS_LIB(QStyleOptionProgressBar, QtWidgets, qstyleoption.h) QT_CLASS_LIB(QStyleOptionProgressBarV2, QtWidgets, qstyleoption.h) QT_CLASS_LIB(QStyleOptionMenuItem, QtWidgets, qstyleoption.h) -QT_CLASS_LIB(QStyleOptionQ3ListViewItem, QtWidgets, qstyleoption.h) -QT_CLASS_LIB(QStyleOptionQ3DockWindow, QtWidgets, qstyleoption.h) QT_CLASS_LIB(QStyleOptionDockWidget, QtWidgets, qstyleoption.h) QT_CLASS_LIB(QStyleOptionDockWidgetV2, QtWidgets, qstyleoption.h) QT_CLASS_LIB(QStyleOptionViewItem, QtWidgets, qstyleoption.h) @@ -889,7 +887,6 @@ QT_CLASS_LIB(QStyleOptionRubberBand, QtWidgets, qstyleoption.h) QT_CLASS_LIB(QStyleOptionComplex, QtWidgets, qstyleoption.h) QT_CLASS_LIB(QStyleOptionSlider, QtWidgets, qstyleoption.h) QT_CLASS_LIB(QStyleOptionSpinBox, QtWidgets, qstyleoption.h) -QT_CLASS_LIB(QStyleOptionQ3ListView, QtWidgets, qstyleoption.h) QT_CLASS_LIB(QStyleOptionToolButton, QtWidgets, qstyleoption.h) QT_CLASS_LIB(QStyleOptionComboBox, QtWidgets, qstyleoption.h) QT_CLASS_LIB(QStyleOptionTitleBar, QtWidgets, qstyleoption.h) @@ -1018,7 +1015,6 @@ QT_CLASS_LIB(QValidator, QtWidgets, qvalidator.h) QT_CLASS_LIB(QIntValidator, QtWidgets, qvalidator.h) QT_CLASS_LIB(QDoubleValidator, QtWidgets, qvalidator.h) QT_CLASS_LIB(QRegExpValidator, QtWidgets, qvalidator.h) -QT_CLASS_LIB(QWorkspace, QtWidgets, qworkspace.h) QT_CLASS_LIB(QScriptEngineDebugger, QtScriptTools, qscriptenginedebugger.h) QT_CLASS_LIB(QDesignerComponents, QtDesigner, qdesigner_components.h) QT_CLASS_LIB(QExtensionFactory, QtDesigner, default_extensionfactory.h) |