From 075e1da67e0ce5c276612e9eeb4ab6ffb83118e1 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 16 Jan 2019 17:56:45 +0100 Subject: [PATCH] Polish the Qt plugin wizard - Add overrides for pure virtual base class functions - Modernize C++ in the generated code - Do not build into the Qt installation directory by default - Rename misleading "Qt4Plugin" enum - Remove Qt 4 compatibility code - Remove some excess newlines Fixes: QTCREATORBUG-21207 Change-Id: I50641eddf9084ef3eb8199684aec639c5e5d71fc Reviewed-by: Alessandro Portale --- .../wizards/libraryparameters.cpp | 72 ++++++++++++------- .../wizards/libraryparameters.h | 4 +- .../wizards/librarywizard.cpp | 17 +++-- .../wizards/librarywizarddialog.cpp | 52 +++++++++----- .../wizards/qtprojectparameters.cpp | 4 +- .../wizards/qtprojectparameters.h | 2 +- 6 files changed, 98 insertions(+), 53 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/wizards/libraryparameters.cpp b/src/plugins/qmakeprojectmanager/wizards/libraryparameters.cpp index a4b9c81af08..aa46476ae03 100644 --- a/src/plugins/qmakeprojectmanager/wizards/libraryparameters.cpp +++ b/src/plugins/qmakeprojectmanager/wizards/libraryparameters.cpp @@ -27,6 +27,7 @@ #include "librarywizarddialog.h" #include +#include #include #include @@ -35,7 +36,6 @@ namespace QmakeProjectManager { namespace Internal { void LibraryParameters::generateCode(QtProjectParameters:: Type t, - const QString &projectTarget, const QString &headerName, const QString &sharedHeader, const QString &exportMacro, @@ -75,7 +75,9 @@ void LibraryParameters::generateCode(QtProjectParameters:: Type t, const QString namespaceIndent = Utils::writeOpeningNameSpaces(namespaceList, indent, headerStr); // Class declaraction - headerStr << '\n' << namespaceIndent << "class "; + if (!namespaceIndent.isEmpty()) + headerStr << '\n'; + headerStr << namespaceIndent << "class "; if (t == QtProjectParameters::SharedLibrary && !exportMacro.isEmpty()) headerStr << exportMacro << ' '; @@ -85,30 +87,37 @@ void LibraryParameters::generateCode(QtProjectParameters:: Type t, headerStr << "\n{\n"; // Is this a QObject (plugin) - const bool inheritsQObject = t == QtProjectParameters::Qt4Plugin; + const bool inheritsQObject = t == QtProjectParameters::QtPlugin; if (inheritsQObject) headerStr << namespaceIndent << indent << "Q_OBJECT\n"; - if (t == QtProjectParameters::Qt4Plugin) { // Write Qt 5 plugin meta data. + if (t == QtProjectParameters::QtPlugin) { // Write Qt plugin meta data. const QString qt5InterfaceName = LibraryWizardDialog::pluginInterface(baseClassName); - if (!qt5InterfaceName.isEmpty()) { - headerStr << "#if QT_VERSION >= 0x050000\n" - << namespaceIndent << indent << "Q_PLUGIN_METADATA(IID \"" - << qt5InterfaceName << '"'; - if (!pluginJsonFileName.isEmpty()) - headerStr << " FILE \"" << pluginJsonFileName << '"'; - headerStr << ")\n#endif // QT_VERSION >= 0x050000\n"; - } + QTC_CHECK(!qt5InterfaceName.isEmpty()); + headerStr << namespaceIndent << indent << "Q_PLUGIN_METADATA(IID \"" + << qt5InterfaceName << '"'; + QTC_CHECK(!pluginJsonFileName.isEmpty()); + headerStr << " FILE \"" << pluginJsonFileName << '"'; + headerStr << ")\n"; } headerStr << namespaceIndent << "\npublic:\n"; - if (inheritsQObject) - headerStr << namespaceIndent << indent << unqualifiedClassName << "(QObject *parent = 0);\n"; - else + if (inheritsQObject) { + headerStr << namespaceIndent << indent << "explicit " << unqualifiedClassName + << "(QObject *parent = nullptr);\n"; + } else { headerStr << namespaceIndent << indent << unqualifiedClassName << "();\n"; - headerStr << namespaceIndent << "};\n\n"; + } + if (!pureVirtualSignatures.empty()) { + headerStr << "\nprivate:\n"; + for (const QString &signature : pureVirtualSignatures) + headerStr << namespaceIndent << indent << signature << " override;\n"; + } + headerStr << namespaceIndent << "};\n"; + if (!namespaceIndent.isEmpty()) + headerStr << '\n'; Utils::writeClosingNameSpaces(namespaceList, indent, headerStr); if (!usePragmaOnce) - headerStr << "#endif // " << guard << '\n'; + headerStr << "\n#endif // " << guard << '\n'; /// 2) Source QTextStream sourceStr(source); @@ -117,8 +126,11 @@ void LibraryParameters::generateCode(QtProjectParameters:: Type t, sourceStr << '\n'; Utils::writeOpeningNameSpaces(namespaceList, indent, sourceStr); + if (!namespaceIndent.isEmpty()) + sourceStr << '\n'; + // Constructor - sourceStr << '\n' << namespaceIndent << unqualifiedClassName << "::" << unqualifiedClassName; + sourceStr << namespaceIndent << unqualifiedClassName << "::" << unqualifiedClassName; if (inheritsQObject) { sourceStr << "(QObject *parent) :\n" << namespaceIndent << indent << baseClassName << "(parent)\n"; @@ -126,14 +138,26 @@ void LibraryParameters::generateCode(QtProjectParameters:: Type t, sourceStr << "()\n"; } sourceStr << namespaceIndent << "{\n" << namespaceIndent << "}\n"; + for (const QString &signature : pureVirtualSignatures) { + const int parenIndex = signature.indexOf('('); + QTC_ASSERT(parenIndex != -1, continue); + int nameIndex = -1; + for (int i = parenIndex - 1; i > 0; --i) { + if (!signature.at(i).isLetterOrNumber()) { + nameIndex = i + 1; + break; + } + } + QTC_ASSERT(nameIndex != -1, continue); + sourceStr << '\n' << namespaceIndent << signature.left(nameIndex); + if (signature.at(nameIndex - 1) != ' ') + sourceStr << ' '; + sourceStr << unqualifiedClassName << "::" << signature.mid(nameIndex) << '\n'; + sourceStr << namespaceIndent << "{\n" << indent + << "static_assert(false, \"You need to implement this function\");\n}\n"; + } Utils::writeClosingNameSpaces(namespaceList, indent, sourceStr); - - if (t == QtProjectParameters::Qt4Plugin) { // Qt 4 plugin export - sourceStr << "\n#if QT_VERSION < 0x050000\n" - << "Q_EXPORT_PLUGIN2(" << projectTarget << ", " << className << ")\n" - << "#endif // QT_VERSION < 0x050000\n"; - } } QString LibraryParameters::generateSharedHeader(const QString &globalHeaderFileName, diff --git a/src/plugins/qmakeprojectmanager/wizards/libraryparameters.h b/src/plugins/qmakeprojectmanager/wizards/libraryparameters.h index 1f74d780dc0..4fe7d00dc16 100644 --- a/src/plugins/qmakeprojectmanager/wizards/libraryparameters.h +++ b/src/plugins/qmakeprojectmanager/wizards/libraryparameters.h @@ -27,7 +27,7 @@ #include "qtprojectparameters.h" -#include +#include namespace QmakeProjectManager { namespace Internal { @@ -38,7 +38,6 @@ struct LibraryParameters { // generate class void generateCode(QtProjectParameters:: Type t, - const QString &projectTarget, const QString &headerName, const QString &sharedHeader, const QString &exportMacro, @@ -58,6 +57,7 @@ struct LibraryParameters { QString baseClassName; QString sourceFileName; QString headerFileName; + QStringList pureVirtualSignatures; }; } // namespace Internal diff --git a/src/plugins/qmakeprojectmanager/wizards/librarywizard.cpp b/src/plugins/qmakeprojectmanager/wizards/librarywizard.cpp index 2db1313a31c..239fec9c3f5 100644 --- a/src/plugins/qmakeprojectmanager/wizards/librarywizard.cpp +++ b/src/plugins/qmakeprojectmanager/wizards/librarywizard.cpp @@ -63,12 +63,15 @@ Core::BaseFileWizard *LibraryWizard::create(QWidget *parent, const Core::WizardD return dialog; } -static void writeLinuxProFile(QTextStream &str) +static void writeLinuxProFile(QTextStream &str, const QtProjectParameters ¶ms) { str << "\n" - "unix {\n" - " target.path = /usr/lib\n" - " INSTALLS += target\n" + "unix {\n"; + if (!params.targetDirectory.isEmpty()) + str << " target.path = " << params.targetDirectory << '\n'; + else + str << " target.path = /usr/lib\n"; + str << " INSTALLS += target\n" "}\n"; } @@ -94,7 +97,7 @@ Core::GeneratedFiles LibraryWizard::generateFiles(const QWizard *w, const QString headerFileName = Utils::FileName::fromString(headerFileFullName).fileName(); QString pluginJsonFileFullName; QString pluginJsonFileName; - if (projectParams.type == QtProjectParameters::Qt4Plugin) { + if (projectParams.type == QtProjectParameters::QtPlugin) { pluginJsonFileFullName = buildFileName(projectPath, projectParams.fileName, QLatin1String("json")); pluginJsonFileName = Utils::FileName::fromString(pluginJsonFileFullName).fileName(); } @@ -114,7 +117,7 @@ Core::GeneratedFiles LibraryWizard::generateFiles(const QWizard *w, // Generate code QString headerContents, sourceContents; - params.generateCode(projectParams.type, projectParams.fileName, headerFileName, + params.generateCode(projectParams.type, headerFileName, globalHeaderFileName, sharedLibExportMacro, pluginJsonFileName, /* indentation*/ 4, usePragmaOnce, &headerContents, &sourceContents); @@ -141,7 +144,7 @@ Core::GeneratedFiles LibraryWizard::generateFiles(const QWizard *w, proStr << " \\\n " << globalHeaderFileName << " \n"; if (!pluginJsonFileName.isEmpty()) proStr << "\nDISTFILES += " << pluginJsonFileName << " \n"; - writeLinuxProFile(proStr); + writeLinuxProFile(proStr, projectParams); } profile.setContents(profileContents); rc.push_back(profile); diff --git a/src/plugins/qmakeprojectmanager/wizards/librarywizarddialog.cpp b/src/plugins/qmakeprojectmanager/wizards/librarywizarddialog.cpp index 6f9d2573a6a..0381e2670a6 100644 --- a/src/plugins/qmakeprojectmanager/wizards/librarywizarddialog.cpp +++ b/src/plugins/qmakeprojectmanager/wizards/librarywizarddialog.cpp @@ -44,27 +44,38 @@ namespace Internal { struct PluginBaseClasses { const char *name; const char *module; + QStringList pureVirtuals; + // blank separated list or 0 const char *dependentModules; const char *targetDirectory; const char *pluginInterface; }; +using QSL = QStringList; static const PluginBaseClasses pluginBaseClasses[] = { - {"QAccessiblePlugin", "QtGui", "QtCore", "accessible", "QAccessibleFactoryInterface"}, - {"QDecorationPlugin", "QtGui", "QtCore", nullptr, nullptr}, // Qt 4 only. - {"QGenericPlugin", "QtGui", "QtCore", "generic", "QGenericPluginFactoryInterface"}, - {"QIconEnginePluginV2", "QtGui", "QtCore", "imageformats", nullptr}, // Qt 4 only. - {"QIconEnginePlugin", "QtGui", "QtCore", "imageformats", "QIconEngineFactoryInterface"}, - {"QImageIOPlugin", "QtGui", "QtCore", "imageformats", "QImageIOHandlerFactoryInterface"}, - {"QScriptExtensionPlugin", "QtScript", "QtCore", nullptr, "QScriptExtensionInterface"}, - {"QSqlDriverPlugin", "QtSql", "QtCore", "sqldrivers", "QSqlDriverFactoryInterface"}, - {"QStylePlugin", "QtGui", "QtCore", "styles", "QStyleFactoryInterface"}, - {"QTextCodecPlugin", "QtCore", nullptr, "codecs", nullptr} // Qt 4 only. + {"QAccessiblePlugin", "QtGui", + QSL{"QAccessibleInterface * create(const QString &key, QObject *object)"}, + "QtCore", "accessible", "QAccessibleFactoryInterface"}, + {"QGenericPlugin", "QtGui", QSL{"QObject *create(const QString &name, const QString &spec)"}, + "QtCore", "generic", "QGenericPluginFactoryInterface"}, + {"QIconEnginePlugin", "QtGui", QSL{"QIconEngine *create(const QString &filename)"}, + "QtCore", "imageformats", "QIconEngineFactoryInterface"}, + {"QImageIOPlugin", "QtGui", + QSL{"QImageIOPlugin::Capabilities capabilities(QIODevice *device, const QByteArray &format) const", + "QImageIOHandler *create(QIODevice *device, const QByteArray &format) const"}, + "QtCore", "imageformats", "QImageIOHandlerFactoryInterface"}, + {"QScriptExtensionPlugin", "QtScript", + QSL{"void initialize(const QString &key, QScriptEngine *engine)", "QStringList keys() const"}, + "QtCore", nullptr, "QScriptExtensionInterface"}, + {"QSqlDriverPlugin", "QtSql", QSL{"QSqlDriver *create(const QString &key)"}, + "QtCore", "sqldrivers", "QSqlDriverFactoryInterface"}, + {"QStylePlugin", "QtWidgets", QSL{"QStyle *create(const QString &key)"}, + "QtCore", "styles", "QStyleFactoryInterface"}, }; -enum { defaultPluginBaseClass = 2 }; +enum { defaultPluginBaseClass = 1 }; static const PluginBaseClasses *findPluginBaseClass(const QString &name) { @@ -114,7 +125,7 @@ LibraryIntroPage::LibraryIntroPage(QWidget *parent) : m_typeCombo->addItem(LibraryWizardDialog::tr("Statically Linked Library"), QVariant(QtProjectParameters::StaticLibrary)); m_typeCombo->addItem(LibraryWizardDialog::tr("Qt Plugin"), - QVariant(QtProjectParameters::Qt4Plugin)); + QVariant(QtProjectParameters::QtPlugin)); insertControl(0, new QLabel(LibraryWizardDialog::tr("Type")), m_typeCombo); } @@ -197,7 +208,7 @@ bool LibraryWizardDialog::isModulesPageSkipped() const { // When leaving the intro or target page, the modules page is skipped // in the case of a plugin since it knows its dependencies by itself. - return type() == QtProjectParameters::Qt4Plugin; + return type() == QtProjectParameters::QtPlugin; } int LibraryWizardDialog::skipModulesPageIfNeeded() const @@ -249,7 +260,7 @@ QtProjectParameters LibraryWizardDialog::parameters() const rc.type = type(); rc.fileName = projectName(); rc.path = path(); - if (rc.type == QtProjectParameters::Qt4Plugin) { + if (rc.type == QtProjectParameters::QtPlugin) { // Plugin: Dependencies & Target directory if (const PluginBaseClasses *plb = findPluginBaseClass(m_filesPage->baseClassName())) { rc.selectedModules = pluginDependencies(plb); @@ -277,7 +288,7 @@ void LibraryWizardDialog::slotCurrentIdChanged(int id) void LibraryWizardDialog::setupFilesPage() { switch (type()) { - case QtProjectParameters::Qt4Plugin: + case QtProjectParameters::QtPlugin: if (!m_pluginBaseClassesInitialized) { if (debugLibWizard) qDebug("initializing for plugins"); @@ -309,8 +320,15 @@ LibraryParameters LibraryWizardDialog::libraryParameters() const { LibraryParameters rc; rc.className = m_filesPage->className(); - rc.baseClassName = type() == QtProjectParameters::Qt4Plugin ? - m_filesPage->baseClassName() : QString(); + if (type() == QtProjectParameters::QtPlugin) { + rc.baseClassName = m_filesPage->baseClassName(); + for (const PluginBaseClasses &c : pluginBaseClasses) { + if (QLatin1String(c.name) == rc.baseClassName) { + rc.pureVirtualSignatures = c.pureVirtuals; + break; + } + } + } rc.sourceFileName = m_filesPage->sourceFileName(); rc.headerFileName = m_filesPage->headerFileName(); return rc; diff --git a/src/plugins/qmakeprojectmanager/wizards/qtprojectparameters.cpp b/src/plugins/qmakeprojectmanager/wizards/qtprojectparameters.cpp index c11ce81d1d9..b649fc05fab 100644 --- a/src/plugins/qmakeprojectmanager/wizards/qtprojectparameters.cpp +++ b/src/plugins/qmakeprojectmanager/wizards/qtprojectparameters.cpp @@ -100,14 +100,14 @@ void QtProjectParameters::writeProFile(QTextStream &str) const case SharedLibrary: str << "TEMPLATE = lib\n\nDEFINES += " << libraryMacro(fileName) << '\n'; break; - case Qt4Plugin: + case QtPlugin: str << "TEMPLATE = lib\nCONFIG += plugin\n"; break; default: break; } - if (!targetDirectory.isEmpty()) + if (!targetDirectory.isEmpty() && !targetDirectory.contains("QT_INSTALL_")) str << "\nDESTDIR = " << targetDirectory << '\n'; if (qtVersionSupport != SupportQt4Only) { diff --git a/src/plugins/qmakeprojectmanager/wizards/qtprojectparameters.h b/src/plugins/qmakeprojectmanager/wizards/qtprojectparameters.h index eb678d1311b..2a260adf705 100644 --- a/src/plugins/qmakeprojectmanager/wizards/qtprojectparameters.h +++ b/src/plugins/qmakeprojectmanager/wizards/qtprojectparameters.h @@ -42,7 +42,7 @@ QString createMacro(const QString &name, const QString &suffix); // write a .pro-file section. struct QtProjectParameters { - enum Type { ConsoleApp, GuiApp, StaticLibrary, SharedLibrary, Qt4Plugin, EmptyProject }; + enum Type { ConsoleApp, GuiApp, StaticLibrary, SharedLibrary, QtPlugin, EmptyProject }; enum QtVersionSupport { SupportQt4And5, SupportQt4Only, SupportQt5Only }; enum Flags { WidgetsRequiredFlag = 0x1 };