File indexing completed on 2024-04-28 03:52:07
0001 /* 0002 * BluezQt - Asynchronous BlueZ wrapper library 0003 * 0004 * SPDX-FileCopyrightText: 2019 Manuel Weichselbaumer <mincequi@web.de> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #include <QDebug> 0010 #include <QFile> 0011 #include <QRegularExpression> 0012 0013 #include "CppGenerator.h" 0014 0015 #include "BluezApiParser.h" 0016 #include "TypeAnnotation.h" 0017 0018 CppGenerator::CppGenerator(const Config &config) 0019 : m_config(config) 0020 { 0021 } 0022 0023 bool CppGenerator::generate(const BluezApiParser &parser) 0024 { 0025 writeAdaptorHeader(parser); 0026 writeAdaptorSource(parser); 0027 0028 return true; 0029 } 0030 0031 void CppGenerator::writeAdaptorHeader(const BluezApiParser &parser) 0032 { 0033 // Iterate interfaces 0034 for (const auto &interface : parser.interfaces()) { 0035 auto className = interfaceToClassName(interface.name()); 0036 const QString includeGuard = QLatin1String("BLUEZQT_") + className.toUpper() + QLatin1String("ADAPTOR_H"); 0037 0038 // Create file 0039 QFile file(className.toLower() + QStringLiteral("adaptor.h")); 0040 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { 0041 qWarning() << "Error opening file for writing:" << file.fileName(); 0042 return; 0043 } 0044 0045 // Write content 0046 QTextStream stream(&file); 0047 writeCopyrightHeader(stream); 0048 stream << "#ifndef " << includeGuard << "\n"; 0049 stream << "#define " << includeGuard << "\n\n"; 0050 stream << "#include <QDBusAbstractAdaptor>\n\n"; 0051 stream << "class QDBusObjectPath;\n\n"; 0052 stream << "namespace BluezQt\n{\n\n"; 0053 stream << "class " << className << ";\n\n"; 0054 stream << "class " << className << "Adaptor : public QDBusAbstractAdaptor\n{\n"; 0055 stream << " Q_OBJECT \n"; 0056 stream << " Q_CLASSINFO(\"D-Bus Interface\", \"" << interface.name() << "\")\n"; 0057 0058 // Write properties 0059 for (const auto &property : interface.properties().properties()) { 0060 // Respect config 0061 if ((property.tags().isOptional && !m_config.useOptional) || (property.tags().isExperimental && !m_config.useExperimental)) { 0062 continue; 0063 } 0064 stream << " Q_PROPERTY(" << bluezToQt(property.type()) << " " << property.name() << " READ " << lowerFirstChars(property.name()); 0065 if (!property.tags().isReadOnly) { 0066 stream << " WRITE set" << property.name(); 0067 } 0068 stream << ")\n"; 0069 } 0070 0071 stream << "\npublic:\n"; 0072 stream << " explicit " << className << "Adaptor(" << className << "* parent);\n\n"; 0073 0074 // Write property accessors 0075 for (const auto &property : interface.properties().properties()) { 0076 // Respect config 0077 if ((property.tags().isOptional && !m_config.useOptional) || (property.tags().isExperimental && !m_config.useExperimental)) { 0078 continue; 0079 } 0080 stream << " " << bluezToQt(property.type()) << " " << lowerFirstChars(property.name()) << "() const;\n"; 0081 if (!property.tags().isReadOnly) { 0082 stream << " void set" << property.name() << "(const " << bluezToQt(property.type()) << " &" << lowerFirstChars(property.name()) << ");\n"; 0083 } 0084 stream << "\n"; 0085 } 0086 0087 stream << "public Q_SLOTS:\n"; 0088 0089 // write Methods 0090 for (const auto &method : interface.methods().methods()) { 0091 // Respect config 0092 if ((method.tags().isOptional && !m_config.useOptional) || (method.tags().isExperimental && !m_config.useExperimental)) { 0093 continue; 0094 } 0095 stream << " " << bluezToQt(method.outParameter().type()) << " " << method.name() << "("; 0096 for (auto it = method.inParameters().begin(); it != method.inParameters().end(); ++it) { 0097 stream << "const " << bluezToQt(it->type()) << " &" << it->name(); 0098 if (it != std::prev(method.inParameters().end())) { 0099 stream << ", "; 0100 } 0101 } 0102 stream << ");\n"; 0103 } 0104 0105 // write private members 0106 stream << "\nprivate:\n"; 0107 stream << " " << className << " *m_" << lowerFirstChars(className) << ";\n"; 0108 stream << "};\n\n} // namespace BluezQt\n\n"; 0109 0110 // include guard 0111 stream << "#endif\n"; 0112 0113 file.close(); 0114 } 0115 } 0116 0117 void CppGenerator::writeAdaptorSource(const BluezApiParser &parser) 0118 { 0119 // Iterate interfaces 0120 for (const auto &interface : parser.interfaces()) { 0121 auto className = interfaceToClassName(interface.name()); 0122 0123 // Create file 0124 QFile file(className.toLower() + QStringLiteral("adaptor.cpp")); 0125 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { 0126 qWarning() << "Error opening file for writing:" << file.fileName(); 0127 return; 0128 } 0129 0130 // Write content 0131 QTextStream stream(&file); 0132 writeCopyrightHeader(stream); 0133 stream << "#include \"" << className << "Adaptor.h\"\n\n"; 0134 stream << "#include \"" << className << ".h\"\n\n"; 0135 stream << "namespace BluezQt\n{\n\n"; 0136 stream << className << "Adaptor::" << className << "Adaptor(" << className << " *parent)\n"; 0137 stream << " : QDBusAbstractAdaptor(parent)\n"; 0138 stream << " , m_" << lowerFirstChars(className) << "(parent)\n"; 0139 stream << "{\n}\n\n"; 0140 0141 // Write property accessors 0142 for (const auto &property : interface.properties().properties()) { 0143 // Respect config 0144 if ((property.tags().isOptional && !m_config.useOptional) || (property.tags().isExperimental && !m_config.useExperimental)) { 0145 continue; 0146 } 0147 stream << bluezToQt(property.type()) << " " << className << "Adaptor::" << lowerFirstChars(property.name()) << "() const\n"; 0148 stream << "{\n"; 0149 stream << " return m_" << lowerFirstChars(className) << "->" << lowerFirstChars(property.name()) << "();\n"; 0150 stream << "}\n\n"; 0151 if (!property.tags().isReadOnly) { 0152 stream << "void " << className << "Adaptor::set" << property.name() << "(const " << bluezToQt(property.type()) << " &" 0153 << lowerFirstChars(property.name()) << ");\n"; 0154 stream << "{\n"; 0155 stream << " m_" << lowerFirstChars(className) << "->set" << property.name() << "(" << lowerFirstChars(property.name()) << ");\n"; 0156 stream << "}\n\n"; 0157 } 0158 } 0159 0160 // write Methods 0161 for (const auto &method : interface.methods().methods()) { 0162 // Respect config 0163 if ((method.tags().isOptional && !m_config.useOptional) || (method.tags().isExperimental && !m_config.useExperimental)) { 0164 continue; 0165 } 0166 stream << bluezToQt(method.outParameter().type()) << " " << className << "Adaptor::" << method.name() << "("; 0167 for (auto it = method.inParameters().begin(); it != method.inParameters().end(); ++it) { 0168 stream << "const " << bluezToQt(it->type()) << " &" << it->name(); 0169 if (it != std::prev(method.inParameters().end())) { 0170 stream << ", "; 0171 } 0172 } 0173 stream << ")\n{\n"; 0174 stream << " return m_" << lowerFirstChars(className) << "->" << lowerFirstChars(method.name()) << "("; 0175 for (auto it = method.inParameters().begin(); it != method.inParameters().end(); ++it) { 0176 stream << it->name(); 0177 if (it != std::prev(method.inParameters().end())) { 0178 stream << ", "; 0179 } 0180 } 0181 stream << ");\n}\n\n"; 0182 } 0183 0184 stream << "} // namespace BluezQt\n"; 0185 0186 file.close(); 0187 } 0188 } 0189 0190 QString CppGenerator::interfaceToClassName(const QString &interface) 0191 { 0192 const int index = interface.lastIndexOf(QRegularExpression(QStringLiteral("\\.[A-Z]\\w+"))) + 1; 0193 auto className = interface.mid(index); 0194 while (className.back() > QLatin1Char('0') && className.back() <= QLatin1Char('9')) { 0195 className.remove(className.size() - 1, 1); 0196 } 0197 0198 return className; 0199 } 0200 0201 QString CppGenerator::lowerFirstChars(const QString &string) 0202 { 0203 QString str(string); 0204 // str.replace(0, 1, string.at(0).toLower()); 0205 0206 const QRegularExpression rx(QStringLiteral("^([A-Z]+)")); 0207 QRegularExpressionMatch match = rx.match(string); 0208 if (match.hasMatch()) { 0209 QString matchedStr = match.captured(1); 0210 for (int i = 0; i < matchedStr.size() - 1; ++i) { 0211 str.replace(i, 1, str.at(i).toLower()); 0212 } 0213 } 0214 str.replace(0, 1, string.at(0).toLower()); 0215 str.replace(string.size() - 1, 1, string.at(string.size() - 1).toLower()); 0216 0217 return str; 0218 } 0219 0220 void CppGenerator::writeCopyrightHeader(QTextStream &stream) 0221 { 0222 stream << "/*\n"; 0223 stream << " * BluezQt - Asynchronous Bluez wrapper library\n"; 0224 stream << " *\n"; 0225 stream << " * Copyright (C) " << m_config.year << " " << m_config.author << "\n"; 0226 stream << " *\n"; 0227 stream << " * This library is free software; you can redistribute it and/or\n"; 0228 stream << " * modify it under the terms of the GNU Lesser General Public\n"; 0229 stream << " * License as published by the Free Software Foundation; either\n"; 0230 stream << " * version 2.1 of the License, or (at your option) version 3, or any\n"; 0231 stream << " * later version accepted by the membership of KDE e.V. (or its\n"; 0232 stream << " * successor approved by the membership of KDE e.V.), which shall\n"; 0233 stream << " * act as a proxy defined in Section 6 of version 3 of the license.\n"; 0234 stream << " *\n"; 0235 stream << " * This library is distributed in the hope that it will be useful,\n"; 0236 stream << " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"; 0237 stream << " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"; 0238 stream << " * Lesser General Public License for more details.\n"; 0239 stream << " *\n"; 0240 stream << " * You should have received a copy of the GNU Lesser General Public\n"; 0241 stream << " * License along with this library. If not, see <http://www.gnu.org/licenses/>.\n"; 0242 stream << " */\n\n"; 0243 }