File indexing completed on 2024-12-08 12:18:20

0001 /* Copyright (C) 2004-2005 ian reinhart geiser <geiseri@sourcextreme.com> */
0002 
0003 #include <kconfig.h>
0004 #include <kmacroexpander.h>
0005 #include <kconfiggroup.h>
0006 #include <kaboutdata.h>
0007 #include <QCommandLineOption>
0008 #include <QCommandLineParser>
0009 #include <QCoreApplication>
0010 #include <QFile>
0011 #include <QFileInfo>
0012 #include <QHash>
0013 #include <QString>
0014 #include <QStringList>
0015 #include <QTextStream>
0016 
0017 static const char classHeader[] =   "/**\n"
0018                                     "* This file was autogenerated by kgendesignerplugin. Any changes will be lost!\n"
0019                                     "* The generated code in this file is licensed under the same license that the\n"
0020                                     "* input file.\n"
0021                                     "*/\n"
0022                                     "#include <QIcon>\n"
0023                                     "#include <QtDesigner/QDesignerContainerExtension>\n"
0024                                     "#if QT_VERSION >= 0x050500\n"
0025                                     "# include <QtUiPlugin/QDesignerCustomWidgetInterface>\n"
0026                                     "#else\n"
0027                                     "# include <QDesignerCustomWidgetInterface>\n"
0028                                     "#endif\n"
0029                                     "#include <qplugin.h>\n"
0030                                     "#include <qdebug.h>\n";
0031 
0032 static const char collClassDef[] = "class %CollName : public QObject, public QDesignerCustomWidgetCollectionInterface\n"
0033                                    "{\n"
0034                                    "    Q_OBJECT\n"
0035                                    "    Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)\n"
0036                                    "       Q_PLUGIN_METADATA(IID \"org.qt-project.Qt.QDesignerCustomWidgetInterface\")\n"
0037                                    "public:\n"
0038                                    "    %CollName(QObject *parent = nullptr);\n"
0039                                    "    virtual ~%CollName() {}\n"
0040                                    "    QList<QDesignerCustomWidgetInterface*> customWidgets() const Q_DECL_OVERRIDE { return m_plugins; } \n"
0041                                    "    \n"
0042                                    "private:\n"
0043                                    "    QList<QDesignerCustomWidgetInterface*> m_plugins;\n"
0044                                    "};\n\n"
0045                                    ;
0046 
0047 static const char collClassImpl[] = "%CollName::%CollName(QObject *parent)\n"
0048                                     "   : QObject(parent)"
0049                                     "{\n"
0050                                     "%CollectionAdd\n"
0051                                     "}\n\n";
0052 
0053 static const char classDef[] =  "class %PluginName : public QObject, public QDesignerCustomWidgetInterface\n"
0054                                 "{\n"
0055                                 "       Q_OBJECT\n"
0056                                 "       Q_INTERFACES(QDesignerCustomWidgetInterface)\n"
0057                                 "public:\n"
0058                                 "       %PluginName(QObject *parent = nullptr) :\n            QObject(parent), mInitialized(false) {}\n"
0059                                 "       virtual ~%PluginName() {}\n"
0060                                 "       \n"
0061                                 "       bool isContainer() const Q_DECL_OVERRIDE { return %IsContainer; }\n"
0062                                 "       bool isInitialized() const Q_DECL_OVERRIDE { return mInitialized; }\n"
0063                                 "       QIcon icon() const Q_DECL_OVERRIDE { return QIcon(QStringLiteral(\"%IconName\")); }\n"
0064                                 "       QString codeTemplate() const Q_DECL_OVERRIDE { return QStringLiteral(\"%CodeTemplate\"); }\n"
0065                                 "       QString domXml() const Q_DECL_OVERRIDE { return %DomXml; }\n"
0066                                 "       QString group() const Q_DECL_OVERRIDE { return QStringLiteral(\"%Group\"); }\n"
0067                                 "       QString includeFile() const Q_DECL_OVERRIDE { return QStringLiteral(\"%IncludeFile\"); }\n"
0068                                 "       QString name() const Q_DECL_OVERRIDE { return QStringLiteral(\"%Class\"); }\n"
0069                                 "       QString toolTip() const Q_DECL_OVERRIDE { return QStringLiteral(\"%ToolTip\"); }\n"
0070                                 "       QString whatsThis() const Q_DECL_OVERRIDE { return QStringLiteral(\"%WhatsThis\"); }\n\n"
0071                                 "       QWidget* createWidget( QWidget* parent ) Q_DECL_OVERRIDE \n       {%CreateWidget\n       }\n"
0072                                 "       void initialize(QDesignerFormEditorInterface *core) Q_DECL_OVERRIDE \n       {%Initialize\n       }\n"
0073                                 "\n"
0074                                 "private:\n"
0075                                 "       bool mInitialized;\n"
0076                                 "};\n\n";
0077 
0078 static QString denamespace(const QString &str);
0079 static QString buildCollClass(KConfig &input, const QStringList &classes, const QString &group);
0080 static QString buildWidgetClass(const QString &name, KConfig &input, const QString &group);
0081 static QString buildWidgetInclude(const QString &name, KConfig &input);
0082 static void buildFile(QTextStream &stream, const QString &group, const QString &fileName, const QString &pluginName);
0083 
0084 int main(int argc, char **argv)
0085 {
0086     QCoreApplication app(argc, argv);
0087 
0088     QString description = QCoreApplication::translate("main", "Builds Qt widget plugins from an ini style description file.");
0089     const QString version = QStringLiteral("0.5");
0090     app.setApplicationVersion(version);
0091 
0092     QCommandLineParser parser;
0093     parser.addVersionOption();
0094     parser.addHelpOption();
0095     parser.addPositionalArgument(QStringLiteral("file"), QCoreApplication::translate("main",  "Input file."));
0096     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("o"), QCoreApplication::translate("main", "Output file."), QStringLiteral("file")));
0097     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("n"), QCoreApplication::translate("main", "Name of the plugin class to generate (deprecated, use PluginName in the input file)."), QStringLiteral("name"), QStringLiteral("WidgetsPlugin")));
0098     parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("g"), QCoreApplication::translate("main", "Default widget group name to display in designer (deprecated, use DefaultGroup in the input file)."), QStringLiteral("group"), QStringLiteral("Custom")));
0099 
0100     KAboutData about(QStringLiteral("kgendesignerplugin"),
0101             QCoreApplication::translate("kgendesignerplugin about data", "kgendesignerplugin"),
0102             version,
0103             description,
0104             KAboutLicense::GPL,
0105             QCoreApplication::translate("kgendesignerplugin about data", "(C) 2004-2005 Ian Reinhart Geiser"),
0106             QString(),
0107             QString(),
0108             QStringLiteral("geiseri@kde.org"));
0109     about.addAuthor(QCoreApplication::translate("kgendesignerplugin about data", "Ian Reinhart Geiser"), QString(), QStringLiteral("geiseri@kde.org"));
0110     about.addAuthor(QCoreApplication::translate("kgendesignerplugin about data", "Daniel Molkentin"), QString(), QStringLiteral("molkentin@kde.org"));
0111     about.setupCommandLine(&parser);
0112 
0113     parser.process(app);
0114     about.processCommandLine(&parser);
0115     if (parser.positionalArguments().count() < 1) {
0116         parser.showHelp();
0117         return 1;
0118     }
0119 
0120     QFileInfo fi(parser.positionalArguments().at(0));
0121 
0122     QString outputFile = parser.value(QStringLiteral("o"));
0123     QString pluginName = parser.value(QStringLiteral("n"));
0124     QString group = parser.value(QStringLiteral("g"));
0125     QString fileName = fi.absoluteFilePath();
0126 
0127     if (parser.isSet(QStringLiteral("o"))) {
0128         QFile output(outputFile);
0129         if (output.open(QIODevice::WriteOnly)) {
0130             QTextStream ts(&output);
0131             buildFile(ts, group, fileName, pluginName);
0132             QString mocFile = output.fileName();
0133             mocFile.replace(QStringLiteral(".cpp"), QStringLiteral(".moc"));
0134             ts << QStringLiteral("#include <%1>\n").arg(mocFile) << '\n';
0135         }
0136         output.close();
0137     } else {
0138         QTextStream ts(stdout, QIODevice::WriteOnly);
0139         buildFile(ts, group, fileName, pluginName);
0140     }
0141 }
0142 
0143 void buildFile(QTextStream &ts, const QString &group, const QString &fileName, const QString &pluginName)
0144 {
0145     KConfig input(fileName, KConfig::NoGlobals);
0146     KConfigGroup cg(&input, "Global");
0147     ts << classHeader << '\n';
0148 
0149     QString defaultGroup = cg.readEntry("DefaultGroup", group);
0150     QStringList includes = cg.readEntry("Includes", QStringList());
0151     QStringList classes = input.groupList();
0152     classes.removeAll(QStringLiteral("Global"));
0153 
0154     for (const QString &myInclude : std::as_const(classes)) {
0155         includes += buildWidgetInclude(myInclude, input);
0156     }
0157 
0158     for (const QString &myInclude : std::as_const(includes)) {
0159         ts << "#include <" << myInclude << ">\n";
0160     }
0161 
0162     ts << QLatin1String("\n\n");
0163 
0164     // Autogenerate widget defs here
0165     for (const QString &myClass : std::as_const(classes)) {
0166         ts << buildWidgetClass(myClass, input, defaultGroup) << "\n";
0167     }
0168 
0169     ts << buildCollClass(input, classes, pluginName);
0170     ts.flush();
0171 
0172 }
0173 
0174 QString denamespace(const QString &str)
0175 {
0176     QString denamespaced = str;
0177     denamespaced.remove(QStringLiteral("::"));
0178     return denamespaced;
0179 }
0180 
0181 QString buildCollClass(KConfig &_input, const QStringList &classes, const QString &pluginName)
0182 {
0183     KConfigGroup input(&_input, "Global");
0184     QHash<QString, QString> defMap;
0185     const QString collName = input.readEntry("PluginName", pluginName);
0186     Q_ASSERT(!collName.isEmpty());
0187     defMap.insert(QStringLiteral("CollName"), collName);
0188     QString genCode;
0189 
0190     for (const QString &myClass : classes) {
0191         genCode += QStringLiteral("                m_plugins.append( new %1(this) );\n").arg(denamespace(myClass) + QStringLiteral("Plugin"));
0192     }
0193 
0194     defMap.insert(QStringLiteral("CollectionAdd"), genCode);
0195 
0196     QString str = KMacroExpander::expandMacros(QLatin1String(collClassDef), defMap);
0197     str += KMacroExpander::expandMacros(QLatin1String(collClassImpl), defMap);
0198     return str;
0199 }
0200 
0201 QString buildWidgetClass(const QString &name, KConfig &_input, const QString &group)
0202 {
0203     KConfigGroup input(&_input, name);
0204     QHash<QString, QString> defMap;
0205 
0206     defMap.insert(QStringLiteral("Group"), input.readEntry("Group", group).replace(QLatin1Char('\"'), QStringLiteral("\\\"")));
0207     defMap.insert(QStringLiteral("IncludeFile"), input.readEntry("IncludeFile", QString(name.toLower() + QStringLiteral(".h"))).remove(QLatin1Char(':')));
0208     defMap.insert(QStringLiteral("ToolTip"), input.readEntry("ToolTip", QString(name + QStringLiteral(" Widget"))).replace(QLatin1Char('\"'), QStringLiteral("\\\"")));
0209     defMap.insert(QStringLiteral("WhatsThis"), input.readEntry("WhatsThis", QString(name + QStringLiteral(" Widget"))).replace(QLatin1Char('\"'), QStringLiteral("\\\"")));
0210     defMap.insert(QStringLiteral("IsContainer"), input.readEntry("IsContainer", QStringLiteral("false")));
0211     defMap.insert(QStringLiteral("IconName"), input.readEntry("IconName", QString::fromLatin1(":/pics/%1.png").arg(denamespace(name).toLower())));
0212     defMap.insert(QStringLiteral("Class"), name);
0213     defMap.insert(QStringLiteral("PluginName"), denamespace(name) + QLatin1String("Plugin"));
0214 
0215     // FIXME: ### make this more useful, i.e. outsource to separate file
0216     QString domXml = input.readEntry("DomXML", QString());
0217     // If domXml is empty then we should call base class function
0218     if (domXml.isEmpty()) {
0219         domXml = QStringLiteral("QDesignerCustomWidgetInterface::domXml()");
0220     } else {
0221         domXml = QStringLiteral("QStringLiteral(\"%1\")").arg(domXml.replace(QLatin1Char('\"'), QStringLiteral("\\\"")));
0222     }
0223     defMap.insert(QStringLiteral("DomXml"), domXml);
0224     defMap.insert(QStringLiteral("CodeTemplate"), input.readEntry("CodeTemplate"));
0225     defMap.insert(QStringLiteral("CreateWidget"), input.readEntry("CreateWidget",
0226                   QStringLiteral("\n            return new %1%2;")
0227                   .arg(input.readEntry("ImplClass", name))
0228                   .arg(input.readEntry("ConstructorArgs", "( parent )"))));
0229     defMap.insert(QStringLiteral("Initialize"), input.readEntry("Initialize", "\n            Q_UNUSED(core);\n            if (mInitialized) return;\n            mInitialized=true;"));
0230 
0231     QString code = KMacroExpander::expandMacros(QLatin1String(classDef), defMap);
0232     return code.replace(QLatin1String("QStringLiteral(\"\")"), QLatin1String("QString()"));
0233 }
0234 
0235 QString buildWidgetInclude(const QString &name, KConfig &_input)
0236 {
0237     KConfigGroup input(&_input, name);
0238     return input.readEntry("IncludeFile", QString(name.toLower() + QStringLiteral(".h")));
0239 }