summaryrefslogtreecommitdiffstats
path: root/src/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/androiddeployqt/main.cpp153
-rw-r--r--src/tools/cmake_automoc_parser/main.cpp85
-rw-r--r--src/tools/macdeployqt/shared/shared.cpp4
-rw-r--r--src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp2
-rw-r--r--src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp2
-rw-r--r--src/tools/qtpaths/qtpaths.cpp2
-rw-r--r--src/tools/uic/cpp/cppwriteinitialization.cpp9
-rw-r--r--src/tools/uic/customwidgetsinfo.cpp15
-rw-r--r--src/tools/uic/customwidgetsinfo.h3
-rw-r--r--src/tools/uic/python/pythonwriteimports.cpp27
-rw-r--r--src/tools/uic/python/pythonwriteimports.h1
-rw-r--r--src/tools/uic/shared/language.cpp18
-rw-r--r--src/tools/uic/shared/language.h8
13 files changed, 231 insertions, 98 deletions
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp
index 766af0ec31..4c79463ebf 100644
--- a/src/tools/androiddeployqt/main.cpp
+++ b/src/tools/androiddeployqt/main.cpp
@@ -135,6 +135,7 @@ struct Options
bool build;
bool auxMode;
bool noRccBundleCleanup = false;
+ bool copyDependenciesOnly = false;
QElapsedTimer timer;
// External tools
@@ -563,6 +564,9 @@ Options parseOptions()
} else if (argument.compare(QLatin1String("--no-rcc-bundle-cleanup"),
Qt::CaseInsensitive) == 0) {
options.noRccBundleCleanup = true;
+ } else if (argument.compare(QLatin1String("--copy-dependencies-only"),
+ Qt::CaseInsensitive) == 0) {
+ options.copyDependenciesOnly = true;
}
}
@@ -687,6 +691,10 @@ void printHelp()
" the resource bundle content, but it should not be used when deploying\n"
" a project, since it litters the 'assets' directory.\n"
"\n"
+ " --copy-dependencies-only: resolve application dependencies and stop\n"
+ " deploying process after all libraries and resources that the\n"
+ " application depends on have been copied.\n"
+ "\n"
" --help: Displays this information.\n",
qPrintable(QCoreApplication::arguments().at(0))
);
@@ -2049,7 +2057,7 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
qPrintable(object.value(QLatin1String("name")).toString()));
} else {
if (options->verbose)
- fprintf(stdout, " -- Adding '%s' as QML dependency\n", path.toLocal8Bit().constData());
+ fprintf(stdout, " -- Adding '%s' as QML dependency\n", qPrintable(path));
QFileInfo info(path);
@@ -2089,30 +2097,67 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
return false;
}
- QDir dir(importPathOfThisImport);
- importPathOfThisImport = dir.absolutePath() + QLatin1Char('/');
-
- const QList<QtDependency> fileNames = findFilesRecursively(*options, info, importPathOfThisImport);
- for (QtDependency fileName : fileNames) {
- if (usedDependencies->contains(fileName.absolutePath))
- continue;
-
- usedDependencies->insert(fileName.absolutePath);
-
+ importPathOfThisImport = QDir(importPathOfThisImport).absolutePath() + QLatin1Char('/');
+ QList<QtDependency> qmlImportsDependencies;
+ auto collectQmlDependency = [&usedDependencies, &qmlImportsDependencies,
+ &importPathOfThisImport](const QString &filePath) {
+ if (!usedDependencies->contains(filePath)) {
+ usedDependencies->insert(filePath);
+ qmlImportsDependencies += QtDependency(
+ QLatin1String("qml/") + filePath.mid(importPathOfThisImport.size()),
+ filePath);
+ }
+ };
+
+ QString plugin = object.value(QLatin1String("plugin")).toString();
+ bool pluginIsOptional = object.value(QLatin1String("pluginIsOptional")).toBool();
+ QFileInfo pluginFileInfo = QFileInfo(
+ path + QLatin1Char('/') + QLatin1String("lib") + plugin + QLatin1Char('_')
+ + options->currentArchitecture + QLatin1String(".so"));
+ QString pluginFilePath = pluginFileInfo.absoluteFilePath();
+ QSet<QString> remainingDependencies;
+ if (pluginFileInfo.exists() && checkArchitecture(*options, pluginFilePath)
+ && readDependenciesFromElf(options, pluginFilePath, usedDependencies,
+ &remainingDependencies)) {
+ collectQmlDependency(pluginFilePath);
+ } else if (!pluginIsOptional) {
if (options->verbose)
- fprintf(stdout, " -- Appending dependency found by qmlimportscanner: %s\n", qPrintable(fileName.absolutePath));
+ fprintf(stdout, " -- Skipping because the required plugin is missing.\n");
+ continue;
+ }
- // Put all imports in default import path in assets
- fileName.relativePath.prepend(QLatin1String("qml/"));
- options->qtDependencies[options->currentArchitecture].append(fileName);
+ QFileInfo qmldirFileInfo = QFileInfo(path + QLatin1Char('/') + QLatin1String("qmldir"));
+ if (qmldirFileInfo.exists()) {
+ collectQmlDependency(qmldirFileInfo.absoluteFilePath());
+ }
- if (fileName.absolutePath.endsWith(QLatin1String(".so")) && checkArchitecture(*options, fileName.absolutePath)) {
- QSet<QString> remainingDependencies;
- if (!readDependenciesFromElf(options, fileName.absolutePath, usedDependencies, &remainingDependencies))
- return false;
+ QString prefer = object.value(QLatin1String("prefer")).toString();
+ // If the preferred location of Qml files points to the Qt resources, this means
+ // that all Qml files has been embedded into plugin and we should not copy them to the
+ // android rcc bundle
+ if (!prefer.startsWith(QLatin1String(":/"))) {
+ QVariantList qmlFiles =
+ object.value(QLatin1String("components")).toArray().toVariantList();
+ qmlFiles.append(object.value(QLatin1String("scripts")).toArray().toVariantList());
+ bool qmlFilesMissing = false;
+ for (const auto &qmlFileEntry : qmlFiles) {
+ QFileInfo fileInfo(qmlFileEntry.toString());
+ if (!fileInfo.exists()) {
+ qmlFilesMissing = true;
+ break;
+ }
+ collectQmlDependency(fileInfo.absoluteFilePath());
+ }
+ if (qmlFilesMissing) {
+ if (options->verbose)
+ fprintf(stdout,
+ " -- Skipping because the required qml files are missing.\n");
+ continue;
}
}
+
+ options->qtDependencies[options->currentArchitecture].append(qmlImportsDependencies);
}
}
@@ -2347,7 +2392,7 @@ bool copyQtFiles(Options *options)
if (options->verbose) {
switch (options->deploymentMechanism) {
case Options::Bundled:
- fprintf(stdout, "Copying %zd dependencies from Qt into package.\n", size_t(options->qtDependencies.size()));
+ fprintf(stdout, "Copying %zd dependencies from Qt into package.\n", size_t(options->qtDependencies[options->currentArchitecture].size()));
break;
};
}
@@ -2746,7 +2791,7 @@ QString packagePath(const Options &options, PackageType pt)
path += QLatin1String(".aab");
}
}
- return shellQuote(path);
+ return path;
}
bool installApk(const Options &options)
@@ -2875,9 +2920,10 @@ bool jarSignerSignPackage(const Options &options)
auto signPackage = [&](const QString &file) {
fprintf(stdout, "Signing file %s\n", qPrintable(file));
fflush(stdout);
- QString command = jarSignerTool + QLatin1String(" %1 %2")
- .arg(file)
- .arg(shellQuote(options.keyStoreAlias));
+ QString command = jarSignerTool
+ + QLatin1String(" %1 %2")
+ .arg(shellQuote(file))
+ .arg(shellQuote(options.keyStoreAlias));
FILE *jarSignerCommand = openProcess(command);
if (jarSignerCommand == 0) {
@@ -2923,10 +2969,10 @@ bool jarSignerSignPackage(const Options &options)
}
zipAlignTool = QLatin1String("%1%2 -f 4 %3 %4")
- .arg(shellQuote(zipAlignTool),
- options.verbose ? QLatin1String(" -v") : QLatin1String(),
- packagePath(options, UnsignedAPK),
- packagePath(options, SignedAPK));
+ .arg(shellQuote(zipAlignTool),
+ options.verbose ? QLatin1String(" -v") : QLatin1String(),
+ shellQuote(packagePath(options, UnsignedAPK)),
+ shellQuote(packagePath(options, SignedAPK)));
FILE *zipAlignCommand = openProcess(zipAlignTool);
if (zipAlignCommand == 0) {
@@ -2991,10 +3037,11 @@ bool signPackage(const Options &options)
return pclose(zipAlignCommand) == 0;
};
- const QString verifyZipAlignCommandLine = QLatin1String("%1%2 -c 4 %3")
- .arg(shellQuote(zipAlignTool),
- options.verbose ? QLatin1String(" -v") : QLatin1String(),
- packagePath(options, UnsignedAPK));
+ const QString verifyZipAlignCommandLine =
+ QLatin1String("%1%2 -c 4 %3")
+ .arg(shellQuote(zipAlignTool),
+ options.verbose ? QLatin1String(" -v") : QLatin1String(),
+ shellQuote(packagePath(options, UnsignedAPK)));
if (zipalignRunner(verifyZipAlignCommandLine)) {
if (options.verbose)
@@ -3011,11 +3058,12 @@ bool signPackage(const Options &options)
if (options.verbose)
fprintf(stdout, "APK not aligned, aligning it for signing.\n");
- const QString zipAlignCommandLine = QLatin1String("%1%2 -f 4 %3 %4")
- .arg(shellQuote(zipAlignTool),
- options.verbose ? QLatin1String(" -v") : QLatin1String(),
- packagePath(options, UnsignedAPK),
- packagePath(options, SignedAPK));
+ const QString zipAlignCommandLine =
+ QLatin1String("%1%2 -f 4 %3 %4")
+ .arg(shellQuote(zipAlignTool),
+ options.verbose ? QLatin1String(" -v") : QLatin1String(),
+ shellQuote(packagePath(options, UnsignedAPK)),
+ shellQuote(packagePath(options, SignedAPK)));
if (!zipalignRunner(zipAlignCommandLine)) {
fprintf(stderr, "zipalign command failed.\n");
@@ -3040,8 +3088,7 @@ bool signPackage(const Options &options)
if (options.verbose)
apkSignCommand += QLatin1String(" --verbose");
- apkSignCommand += QLatin1String(" %1")
- .arg(packagePath(options, SignedAPK));
+ apkSignCommand += QLatin1String(" %1").arg(shellQuote(packagePath(options, SignedAPK)));
auto apkSignerRunner = [](const QString &command, bool verbose) {
FILE *apkSigner = openProcess(command);
@@ -3068,8 +3115,9 @@ bool signPackage(const Options &options)
if (!apkSignerRunner(apkSignCommand, options.verbose))
return false;
- const QString apkVerifyCommand = QLatin1String("%1 verify --verbose %2")
- .arg(shellQuote(apksignerTool), packagePath(options, SignedAPK));
+ const QString apkVerifyCommand =
+ QLatin1String("%1 verify --verbose %2")
+ .arg(shellQuote(apksignerTool), shellQuote(packagePath(options, SignedAPK)));
// Verify the package and remove the unsigned apk
return apkSignerRunner(apkVerifyCommand, true) && QFile::remove(packagePath(options, UnsignedAPK));
@@ -3102,12 +3150,19 @@ bool writeDependencyFile(const Options &options)
if (options.verbose)
fprintf(stdout, "Writing dependency file.\n");
- QFile depFile(options.depFilePath);
-
- QString relativeApkPath = QDir(options.buildDirectory).relativeFilePath(options.apkPath);
+ QString relativeTargetPath;
+ if (options.copyDependenciesOnly) {
+ // When androiddeploy Qt is running in copyDependenciesOnly mode we need to use
+ // the timestamp file as the target to collect dependencies.
+ QString timestampAbsPath = QFileInfo(options.depFilePath).absolutePath() + QLatin1String("/timestamp");
+ relativeTargetPath = QDir(options.buildDirectory).relativeFilePath(timestampAbsPath);
+ } else {
+ relativeTargetPath = QDir(options.buildDirectory).relativeFilePath(options.apkPath);
+ }
+ QFile depFile(options.depFilePath);
if (depFile.open(QIODevice::WriteOnly)) {
- depFile.write(escapeAndEncodeDependencyPath(relativeApkPath));
+ depFile.write(escapeAndEncodeDependencyPath(relativeTargetPath));
depFile.write(": ");
for (const auto &file : dependenciesForDepfile) {
@@ -3163,7 +3218,7 @@ int main(int argc, char *argv[])
options.setCurrentQtArchitecture(it.key(), it.value().qtInstallDirectory);
// All architectures have a copy of the gradle files but only one set needs to be copied.
- if (!androidTemplatetCopied && options.build && !options.auxMode) {
+ if (!androidTemplatetCopied && options.build && !options.auxMode && !options.copyDependenciesOnly) {
cleanAndroidFiles(options);
if (Q_UNLIKELY(options.timing))
fprintf(stdout, "[TIMING] %lld ns: Cleaned Android file\n", options.timer.nsecsElapsed());
@@ -3218,6 +3273,12 @@ int main(int argc, char *argv[])
fprintf(stdout, "[TIMING] %lld ns: Bundled Qt libs\n", options.timer.nsecsElapsed());
}
+ if (options.copyDependenciesOnly) {
+ if (!options.depFilePath.isEmpty())
+ writeDependencyFile(options);
+ return 0;
+ }
+
if (!createRcc(options))
return CannotCreateRcc;
diff --git a/src/tools/cmake_automoc_parser/main.cpp b/src/tools/cmake_automoc_parser/main.cpp
index 6d0214638e..70cfcb1b68 100644
--- a/src/tools/cmake_automoc_parser/main.cpp
+++ b/src/tools/cmake_automoc_parser/main.cpp
@@ -30,6 +30,7 @@
#include <cstdio>
#include <cstdlib>
+#include <limits>
#include <qcommandlineoption.h>
#include <qcommandlineparser.h>
@@ -46,6 +47,7 @@
#include <qset.h>
#include <qstring.h>
#include <qstack.h>
+#include <qdatastream.h>
QT_BEGIN_NAMESPACE
@@ -194,38 +196,52 @@ static bool readParseCache(ParseCacheMap &entries, const QString &parseCacheFile
return true;
}
-static bool readJsonFiles(QList<QString> &entries, const QString &filePath)
+static bool writeJsonFiles(const QList<QString> &fileList, const QString &fileListFilePath,
+ const QString &timestampFilePath)
{
-
- QFile file(filePath);
- if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- fprintf(stderr, "Could not open: %s\n", qPrintable(filePath));
+ QFile timestampFile(timestampFilePath);
+ if (!timestampFile.open(QIODevice::ReadWrite)) {
+ fprintf(stderr, "Could not open: %s\n", qPrintable(timestampFilePath));
return false;
}
- QTextStream textStream(&file);
- QString line;
- while (textStream.readLineInto(&line)) {
- entries.push_back(line);
+ qint64 timestamp = std::numeric_limits<qint64>::min();
+ QByteArray timestampBuffer = timestampFile.readAll();
+ if (timestampBuffer.size() == sizeof(timestamp)) {
+ QDataStream istream(&timestampBuffer, QIODevice::ReadOnly);
+ istream >> timestamp;
}
- file.close();
- return true;
-}
-static bool writeJsonFiles(const QList<QString> &fileList, const QString &fileListFilePath)
-{
- QFile file(fileListFilePath);
- if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
- fprintf(stderr, "Could not open: %s\n", qPrintable(fileListFilePath));
- return false;
+ // Check if any of the metatype json files produced by automoc is newer than the last file
+ // processed by cmake_automoc parser
+ for (const auto &jsonFile : fileList) {
+ const qint64 jsonFileLastModified =
+ QFileInfo(jsonFile).lastModified().toMSecsSinceEpoch();
+ if (jsonFileLastModified > timestamp) {
+ timestamp = jsonFileLastModified;
+ }
}
- QTextStream textStream(&file);
- for (const auto &file : fileList) {
- textStream << file << Qt::endl;
- }
+ if (timestamp != std::numeric_limits<qint64>::min() || !QFile::exists(fileListFilePath)) {
+ QFile file(fileListFilePath);
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ fprintf(stderr, "Could not open: %s\n", qPrintable(fileListFilePath));
+ return false;
+ }
- file.close();
+ QTextStream textStream(&file);
+ for (const auto &jsonFile : fileList) {
+ textStream << jsonFile << Qt::endl;
+ }
+ textStream.flush();
+
+ // Update the timestamp according the newest json file timestamp.
+ timestampBuffer.clear();
+ QDataStream ostream(&timestampBuffer, QIODevice::WriteOnly);
+ ostream << timestamp;
+ timestampFile.resize(0);
+ timestampFile.write(timestampBuffer);
+ }
return true;
}
@@ -270,6 +286,13 @@ int main(int argc, char **argv)
QStringLiteral("Set this option when using CMake with a multi-config generator"));
parser.addOption(isMultiConfigOption);
+ QCommandLineOption timestampFilePathOption(QStringLiteral("timestamp-file-path"));
+ timestampFilePathOption.setDescription(
+ QStringLiteral("The path to a timestamp file that determines whether the output"
+ " file needs to be updated."));
+ timestampFilePathOption.setValueName(QStringLiteral("timestamp file"));
+ parser.addOption(timestampFilePathOption);
+
QStringList arguments = QCoreApplication::arguments();
parser.process(arguments);
@@ -378,19 +401,9 @@ int main(int argc, char **argv)
jsonFileList.sort();
// Read Previous file list (if any)
- const QString fileListFilePath = parser.value(outputFileOption);
- QList<QString> previousList;
- QFile prev_file(fileListFilePath);
-
- // Only try to open file if it exists to avoid error messages
- if (prev_file.exists()) {
- (void)readJsonFiles(previousList, fileListFilePath);
- }
-
- if (previousList != jsonFileList || !QFile(fileListFilePath).exists()) {
- if (!writeJsonFiles(jsonFileList, fileListFilePath)) {
- return EXIT_FAILURE;
- }
+ if (!writeJsonFiles(jsonFileList, parser.value(outputFileOption),
+ parser.value(timestampFilePathOption))) {
+ return EXIT_FAILURE;
}
return EXIT_SUCCESS;
diff --git a/src/tools/macdeployqt/shared/shared.cpp b/src/tools/macdeployqt/shared/shared.cpp
index b6eeaa8e80..584b541c9a 100644
--- a/src/tools/macdeployqt/shared/shared.cpp
+++ b/src/tools/macdeployqt/shared/shared.cpp
@@ -206,7 +206,7 @@ OtoolInfo findDependencyInfo(const QString &binaryPath)
info.installName = binaryPath;
}
} else {
- LogError() << "Could not parse otool output line:" << outputLines.first();
+ LogDebug() << "Could not parse otool output line:" << outputLines.first();
outputLines.removeFirst();
}
}
@@ -220,7 +220,7 @@ OtoolInfo findDependencyInfo(const QString &binaryPath)
dylib.currentVersion = QVersionNumber::fromString(match.captured(3));
info.dependencies << dylib;
} else {
- LogError() << "Could not parse otool output line:" << outputLine;
+ LogDebug() << "Could not parse otool output line:" << outputLine;
}
}
diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
index fad92994f9..554ab0119e 100644
--- a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
+++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
@@ -60,7 +60,7 @@ static const char docTypeHeader[] =
#define PROGRAMNAME "qdbuscpp2xml"
#define PROGRAMVERSION "0.2"
-#define PROGRAMCOPYRIGHT "Copyright (C) 2021 The Qt Company Ltd."
+#define PROGRAMCOPYRIGHT "Copyright (C) 2022 The Qt Company Ltd."
static QString outputFile;
static int flags;
diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
index e6acf9e258..825ef1dec1 100644
--- a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
+++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
@@ -46,7 +46,7 @@
#define PROGRAMNAME "qdbusxml2cpp"
#define PROGRAMVERSION "0.8"
-#define PROGRAMCOPYRIGHT "Copyright (C) 2021 The Qt Company Ltd."
+#define PROGRAMCOPYRIGHT "Copyright (C) 2022 The Qt Company Ltd."
#define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply"
diff --git a/src/tools/qtpaths/qtpaths.cpp b/src/tools/qtpaths/qtpaths.cpp
index 667b594b67..f9643ad3fe 100644
--- a/src/tools/qtpaths/qtpaths.cpp
+++ b/src/tools/qtpaths/qtpaths.cpp
@@ -122,7 +122,9 @@ static const StringEnum lookupTableData[] = {
{ "MoviesLocation", QStandardPaths::MoviesLocation, false },
{ "MusicLocation", QStandardPaths::MusicLocation, false },
{ "PicturesLocation", QStandardPaths::PicturesLocation, false },
+ { "PublicShareLocation", QStandardPaths::PublicShareLocation, false },
{ "RuntimeLocation", QStandardPaths::RuntimeLocation, false },
+ { "TemplatesLocation", QStandardPaths::TemplatesLocation, false },
{ "TempLocation", QStandardPaths::TempLocation, false }
};
diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp
index 4c073987dc..7f5776b5c6 100644
--- a/src/tools/uic/cpp/cppwriteinitialization.cpp
+++ b/src/tools/uic/cpp/cppwriteinitialization.cpp
@@ -27,6 +27,7 @@
****************************************************************************/
#include "cppwriteinitialization.h"
+#include "customwidgetsinfo.h"
#include "driver.h"
#include "ui4.h"
#include "utils.h"
@@ -2640,10 +2641,14 @@ void WriteInitialization::acceptConnection(DomConnection *connection)
return;
}
const QString senderSignature = connection->elementSignal();
+ language::SignalSlotOptions signalOptions;
+ if (m_uic->customWidgetsInfo()->isAmbiguousSignal(senderDecl.className, senderSignature))
+ signalOptions.setFlag(language::SignalSlotOption::Ambiguous);
+
language::SignalSlot theSignal{senderDecl.name, senderSignature,
- senderDecl.className};
+ senderDecl.className, signalOptions};
language::SignalSlot theSlot{receiverDecl.name, connection->elementSlot(),
- receiverDecl.className};
+ receiverDecl.className, {}};
m_output << m_indent;
language::formatConnection(m_output, theSignal, theSlot,
diff --git a/src/tools/uic/customwidgetsinfo.cpp b/src/tools/uic/customwidgetsinfo.cpp
index 347c647acb..4facd2bd74 100644
--- a/src/tools/uic/customwidgetsinfo.cpp
+++ b/src/tools/uic/customwidgetsinfo.cpp
@@ -101,6 +101,21 @@ bool CustomWidgetsInfo::isCustomWidgetContainer(const QString &className) const
return false;
}
+// Is it ambiguous, resulting in different signals for Python
+// "QAbstractButton::clicked(checked=false)"
+bool CustomWidgetsInfo::isAmbiguousSignal(const QString &className,
+ const QString &signalSignature) const
+{
+ if (signalSignature.startsWith(u"triggered") && extends(className, "QAction"))
+ return true;
+ if (signalSignature.startsWith(u"clicked(")
+ && extendsOneOf(className, {u"QCommandLinkButton"_qs, u"QCheckBox"_qs,
+ u"QPushButton"_qs, u"QRadioButton"_qs, u"QToolButton"_qs})) {
+ return true;
+ }
+ return false;
+}
+
QString CustomWidgetsInfo::realClassName(const QString &className) const
{
if (className == QLatin1String("Line"))
diff --git a/src/tools/uic/customwidgetsinfo.h b/src/tools/uic/customwidgetsinfo.h
index 82b9882bef..23e5bdd14a 100644
--- a/src/tools/uic/customwidgetsinfo.h
+++ b/src/tools/uic/customwidgetsinfo.h
@@ -61,6 +61,9 @@ public:
bool isCustomWidgetContainer(const QString &className) const;
+ bool isAmbiguousSignal(const QString &className,
+ const QString &signalSignature) const;
+
private:
using NameCustomWidgetMap = QMap<QString, DomCustomWidget*>;
NameCustomWidgetMap m_customWidgets;
diff --git a/src/tools/uic/python/pythonwriteimports.cpp b/src/tools/uic/python/pythonwriteimports.cpp
index ec4968da2f..0d295b483d 100644
--- a/src/tools/uic/python/pythonwriteimports.cpp
+++ b/src/tools/uic/python/pythonwriteimports.cpp
@@ -233,16 +233,31 @@ void WriteImports::addPythonCustomWidget(const QString &className, const DomCust
void WriteImports::acceptProperty(DomProperty *node)
{
- if (node->kind() == DomProperty::Enum) {
- // Add base classes like QFrame for QLabel::frameShape()
- const QString &enumV = node->elementEnum();
- const auto colonPos = enumV.indexOf(u"::");
- if (colonPos > 0)
- addQtClass(enumV.left(colonPos));
+ switch (node->kind()) {
+ case DomProperty::Enum:
+ addEnumBaseClass(node->elementEnum());
+ break;
+ case DomProperty::Set:
+ addEnumBaseClass(node->elementSet());
+ break;
+ default:
+ break;
}
+
WriteIncludesBase::acceptProperty(node);
}
+void WriteImports::addEnumBaseClass(const QString &v)
+{
+ // Add base classes like QFrame for QLabel::frameShape()
+ const auto colonPos = v.indexOf(u"::");
+ if (colonPos > 0) {
+ const QString base = v.left(colonPos);
+ if (base.startsWith(u'Q') && base != u"Qt")
+ addQtClass(base);
+ }
+}
+
} // namespace Python
QT_END_NAMESPACE
diff --git a/src/tools/uic/python/pythonwriteimports.h b/src/tools/uic/python/pythonwriteimports.h
index c833e216a6..05cf48c1a1 100644
--- a/src/tools/uic/python/pythonwriteimports.h
+++ b/src/tools/uic/python/pythonwriteimports.h
@@ -55,6 +55,7 @@ protected:
private:
void addPythonCustomWidget(const QString &className, const DomCustomWidget *dcw);
bool addQtClass(const QString &className);
+ void addEnumBaseClass(const QString &v);
void writeImport(const QString &module);
QHash<QString, QString> m_classToModule;
diff --git a/src/tools/uic/shared/language.cpp b/src/tools/uic/shared/language.cpp
index 2f2ae3ebc6..fc1395d403 100644
--- a/src/tools/uic/shared/language.cpp
+++ b/src/tools/uic/shared/language.cpp
@@ -456,12 +456,22 @@ void formatConnection(QTextStream &str, const SignalSlot &sender, const SignalSl
break;
}
break;
- case Language::Python:
- str << sender.name << '.'
- << QStringView{sender.signature}.left(sender.signature.indexOf(QLatin1Char('(')))
- << ".connect(" << receiver.name << '.'
+ case Language::Python: {
+ const auto paren = sender.signature.indexOf(u'(');
+ auto senderSignature = QStringView{sender.signature};
+ str << sender.name << '.' << senderSignature.left(paren);
+ // Signals like "QAbstractButton::clicked(checked=false)" require
+ // the parameter if it is used.
+ if (sender.options.testFlag(SignalSlotOption::Ambiguous)) {
+ const QStringView parameters =
+ senderSignature.mid(paren + 1, senderSignature.size() - paren - 2);
+ if (!parameters.isEmpty() && !parameters.contains(u','))
+ str << "[\"" << parameters << "\"]";
+ }
+ str << ".connect(" << receiver.name << '.'
<< QStringView{receiver.signature}.left(receiver.signature.indexOf(QLatin1Char('(')))
<< ')';
+ }
break;
}
}
diff --git a/src/tools/uic/shared/language.h b/src/tools/uic/shared/language.h
index 918f25e46a..93fd0c63be 100644
--- a/src/tools/uic/shared/language.h
+++ b/src/tools/uic/shared/language.h
@@ -198,11 +198,19 @@ inline QTextStream &operator<<(QTextStream &str, const _stackVariable<withInitPa
using stackVariable = _stackVariable<false>;
using stackVariableWithInitParameters = _stackVariable<true>;
+enum class SignalSlotOption
+{
+ Ambiguous = 0x1
+};
+
+Q_DECLARE_FLAGS(SignalSlotOptions, SignalSlotOption)
+
struct SignalSlot
{
QString name;
QString signature;
QString className;
+ SignalSlotOptions options;
};
void formatConnection(QTextStream &str, const SignalSlot &sender, const SignalSlot &receiver,