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 <alessandro.portale@qt.io>
This commit is contained in:
Christian Kandeler
2019-01-16 17:56:45 +01:00
parent 18bd816161
commit 075e1da67e
6 changed files with 98 additions and 53 deletions

View File

@@ -27,6 +27,7 @@
#include "librarywizarddialog.h"
#include <utils/codegeneration.h>
#include <utils/qtcassert.h>
#include <QTextStream>
#include <QStringList>
@@ -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,

View File

@@ -27,7 +27,7 @@
#include "qtprojectparameters.h"
#include <QString>
#include <QStringList>
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

View File

@@ -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 &params)
{
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);

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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 };