Browse Source

Generator refactoring phase 2

Alexey Edelev 4 years ago
parent
commit
38db5c3218
43 changed files with 1552 additions and 2467 deletions
  1. 28 29
      src/generator/CMakeLists.txt
  2. 21 24
      src/generator/baseprinter.cpp
  3. 112 0
      src/generator/baseprinter.h
  4. 0 458
      src/generator/classgeneratorbase.cpp
  5. 0 179
      src/generator/classgeneratorbase.h
  6. 13 21
      src/generator/clientdeclarationprinter.cpp
  7. 9 12
      src/generator/clientdeclarationprinter.h
  8. 12 22
      src/generator/clientdefinitionprinter.cpp
  9. 7 12
      src/generator/clientdefinitionprinter.h
  10. 89 0
      src/generator/descriptorprinterbase.h
  11. 96 0
      src/generator/enumdeclarationprinter.cpp
  12. 13 17
      src/generator/enumdeclarationprinter.h
  13. 23 26
      src/generator/enumdefinitionprinter.cpp
  14. 7 10
      src/generator/enumdefinitionprinter.h
  15. 0 112
      src/generator/enumsgenerator.cpp
  16. 0 83
      src/generator/enumssourcegenerator.cpp
  17. 0 168
      src/generator/generator.cpp
  18. 0 141
      src/generator/generator.h
  19. 89 0
      src/generator/generatorbase.cpp
  20. 82 0
      src/generator/generatorbase.h
  21. 30 6
      src/generator/generatorcommon.cpp
  22. 14 0
      src/generator/generatorcommon.h
  23. 0 111
      src/generator/globalenumsgenerator.cpp
  24. 0 60
      src/generator/globalenumsgenerator.h
  25. 0 108
      src/generator/globalenumssourcegenerator.cpp
  26. 0 54
      src/generator/globalenumssourcegenerator.h
  27. 2 2
      src/generator/main.cpp
  28. 102 133
      src/generator/messagedeclarationprinter.cpp
  29. 20 25
      src/generator/messagedeclarationprinter.h
  30. 357 0
      src/generator/messagedefinitionprinter.cpp
  31. 20 26
      src/generator/messagedefinitionprinter.h
  32. 203 0
      src/generator/multifilegenerator.cpp
  33. 64 0
      src/generator/multifilegenerator.h
  34. 0 442
      src/generator/protobufsourcegenerator.cpp
  35. 5 14
      src/generator/serverdeclarationprinter.cpp
  36. 5 8
      src/generator/serverdeclarationprinter.h
  37. 12 21
      src/generator/servicedeclarationprinterbase.cpp
  38. 5 12
      src/generator/servicedeclarationprinterbase.h
  39. 68 101
      src/generator/singlefilegenerator.cpp
  40. 32 22
      src/generator/templates.cpp
  41. 10 6
      src/generator/templates.h
  42. 1 1
      src/protobuf/qprotobufserializer_p.h
  43. 1 1
      src/protobuf/qt_lib_protobuf.pri.in

+ 28 - 29
src/generator/CMakeLists.txt

@@ -5,40 +5,39 @@ set(TARGET_EXPORT ${TARGET}Targets)
 set(TARGET_BINDIR ${CMAKE_INSTALL_BINDIR})
 
 file(GLOB SOURCES main.cpp
-    generator.cpp
-    classgeneratorbase.cpp
-    servergenerator.cpp
-    protobufclassgenerator.cpp
-    enumsgenerator.cpp
-    enumssourcegenerator.cpp
-    servicegeneratorbase.cpp
+    generatorcommon.cpp
+    generatoroptions.cpp
     templates.cpp
-    clientgenerator.cpp
-    classsourcegeneratorbase.cpp
-    protobufsourcegenerator.cpp
-    clientsourcegenerator.cpp
-    singlefilegenerator.cpp
     generatorbase.cpp
-    generatoroptions.cpp
-    generatorcommon.cpp)
+    singlefilegenerator.cpp
+    multifilegenerator.cpp
+    baseprinter.cpp
+    messagedeclarationprinter.cpp
+    messagedefinitionprinter.cpp
+    enumdeclarationprinter.cpp
+    enumdefinitionprinter.cpp
+    servicedeclarationprinterbase.cpp
+    clientdeclarationprinter.cpp
+    clientdefinitionprinter.cpp
+    serverdeclarationprinter.cpp)
 
-file(GLOB HEADERS classgeneratorbase.h
-    classsourcegeneratorbase.h
-    clientgenerator.h
-    clientsourcegenerator.h
-    generator.h
-    enumsgenerator.h
-    enumssourcegenerator.h
-    protobufclassgenerator.h
-    protobufsourcegenerator.h
-    servergenerator.h
-    servicegeneratorbase.h
+file(GLOB HEADERS utils.h
+    generatorcommon.h
+    generatoroptions.h
     templates.h
-    utils.h
-    singlefilegenerator.h
     generatorbase.h
-    generatoroptions.h
-    generatorcommon.h)
+    singlefilegenerator.h
+    multifilegenerator.h
+    baseprinter.h
+    descriptorprinterbase.h
+    messagedeclarationprinter.h
+    messagedefinitionprinter.h
+    enumdeclarationprinter.h
+    enumdefinitionprinter.h
+    servicedeclarationprinterbase.h
+    clientdeclarationprinter.h
+    clientdefinitionprinter.h
+    serverdeclarationprinter.h)
 
 add_executable(${TARGET} ${SOURCES})
 

+ 21 - 24
src/generator/classsourcegeneratorbase.h → src/generator/baseprinter.cpp

@@ -23,34 +23,31 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#pragma once
+#include "baseprinter.h"
 
-#include <google/protobuf/io/printer.h>
-#include <memory>
-#include <unordered_set>
-#include "classgeneratorbase.h"
+#include "templates.h"
+#include "generatorcommon.h"
 
-namespace QtProtobuf {
-namespace generator {
+using namespace ::QtProtobuf::generator;
+using namespace ::google::protobuf;
+using namespace ::google::protobuf::compiler;
 
-/*!
- * \ingroup generator
- * \private
- * \brief The ClassSourceGeneratorBase class implements source generation
- */
-class ClassSourceGeneratorBase : public ClassGeneratorBase
+BasePrinter::BasePrinter(const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
+    mPrinter(printer)
 {
-public:
-    ClassSourceGeneratorBase(const std::string &className, const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out);
-    ClassSourceGeneratorBase(const std::string &fullClassName, const std::shared_ptr<::google::protobuf::io::Printer> &printer);
-    ~ClassSourceGeneratorBase() = default;
-    virtual void run() = 0;
+}
 
-protected:
-    void printClassHeaderInclude();
-    void printUsingNamespaces(const std::unordered_set<std::string> &namespaces);
+void BasePrinter::printPublicBlock()
+{
+    mPrinter->Print(Templates::PublicBlockTemplate);
+}
 
-};
+void BasePrinter::printPrivateBlock()
+{
+    mPrinter->Print(Templates::PrivateBlockTemplate);
+}
 
-} //namespace QtProtobuf
-} //namespace generator
+void BasePrinter::printSignalsBlock()
+{
+    mPrinter->Print(Templates::SignalsBlockTemplate);
+}

+ 112 - 0
src/generator/baseprinter.h

@@ -0,0 +1,112 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
+ *
+ * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies
+ * or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
+#include <memory>
+
+#include "utils.h"
+#include "generatoroptions.h"
+#include "generatorcommon.h"
+
+namespace google { namespace protobuf {
+class FieldDescriptor;
+class Descriptor;
+class MethodDescriptor;
+}}
+
+namespace QtProtobuf {
+namespace generator {
+
+using PropertyMap = std::map<std::string, std::string>;
+
+/*!
+ * \ingroup generator
+ * \private
+ * \brief The BasePrinter class is base of source code generation
+ */
+class BasePrinter
+{
+public:
+    BasePrinter(const std::shared_ptr<::google::protobuf::io::Printer> &printer);
+    virtual ~BasePrinter() = default;
+
+    void printPublicBlock();
+    void printPrivateBlock();
+    void printSignalsBlock();
+
+    template<typename T>
+    void printComments(T *descriptor) {
+        if (!GeneratorOptions::instance().generateComments()) {
+            return;
+        }
+
+        ::google::protobuf::SourceLocation loc;
+        descriptor->GetSourceLocation(&loc);
+
+        utils::trim(loc.leading_comments);
+        if (loc.leading_comments.size() > 0) {
+            auto firstEntry = loc.leading_comments.find('\n');
+            bool isSingleLine = firstEntry == std::string::npos;
+
+            if (loc.leading_comments[0] != '!' && loc.leading_comments[0] != '*' && loc.leading_comments[0] != ' ') {
+                loc.leading_comments = " " + loc.leading_comments;
+                if (!isSingleLine) {
+                    loc.leading_comments = "\n" + loc.leading_comments;
+                }
+            }
+            mPrinter->Print("\n/*");
+            if (isSingleLine) {
+                mPrinter->Print(loc.leading_comments.c_str());
+            } else {
+                utils::replace(loc.leading_comments, "\n", "\n *");
+                mPrinter->Print(loc.leading_comments.c_str());
+                if (loc.leading_comments[loc.leading_comments.size() - 1] != '\n') {
+                    mPrinter->Print("\n");
+                }
+            }
+            mPrinter->Print(" */");
+        }
+    }
+
+    void Indent() {
+        mPrinter->Indent();
+        mPrinter->Indent();
+    }
+
+    void Outdent() {
+        mPrinter->Outdent();
+        mPrinter->Outdent();
+    }
+
+protected:
+    std::shared_ptr<::google::protobuf::io::Printer> mPrinter;
+    std::vector<std::string> mNamespaces;
+};
+
+} //namespace generator
+} //namespace QtProtobuf

+ 0 - 458
src/generator/classgeneratorbase.cpp

@@ -1,458 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
- *
- * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this
- * software and associated documentation files (the "Software"), to deal in the Software
- * without restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
- * to permit persons to whom the Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies
- * or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
- * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include "classgeneratorbase.h"
-
-#include "templates.h"
-#include "generatoroptions.h"
-
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-
-#include <set>
-
-#include "generatorcommon.h"
-
-using namespace ::QtProtobuf::generator;
-using namespace ::google::protobuf;
-using namespace ::google::protobuf::io;
-using namespace ::google::protobuf::compiler;
-
-ClassGeneratorBase::ClassGeneratorBase(const std::string &fullClassName, const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
-    mPrinter(printer)
-{
-    mNamespaces = utils::split(fullClassName, '.');
-    assert(mNamespaces.size() > 0);
-    mClassName = utils::upperCaseName(mNamespaces.back());
-    mNamespaces.erase(mNamespaces.end() - 1);
-    for (size_t i = 0; i < mNamespaces.size(); i++) {
-        if (i > 0) {
-            mNamespacesColonDelimited = mNamespacesColonDelimited.append("::");
-        }
-        mNamespacesColonDelimited = mNamespacesColonDelimited.append(mNamespaces[i]);
-    }
-}
-
-ClassGeneratorBase::ClassGeneratorBase(const std::string &fullClassName, const std::shared_ptr<::google::protobuf::io::ZeroCopyOutputStream> &out) :
-  ClassGeneratorBase(fullClassName, std::shared_ptr<::google::protobuf::io::Printer>(new ::google::protobuf::io::Printer(out.get(), '$')))
-{
-    mOutput = out;
-}
-
-
-void ClassGeneratorBase::printDisclaimer()
-{
-    mPrinter->Print(Templates::DisclaimerTemplate);
-}
-
-void ClassGeneratorBase::printPreamble()
-{
-    mPrinter->Print(Templates::PreambleTemplate);
-}
-
-void ClassGeneratorBase::printNamespaces()
-{
-    printNamespaces(mNamespaces);
-}
-
-void ClassGeneratorBase::printNamespaces(const std::vector<std::string> &namespaces)
-{
-    for (auto ns: namespaces) {
-        mPrinter->Print({{"namespace", ns}}, Templates::NamespaceTemplate);
-    }
-}
-
-void ClassGeneratorBase::printClassDeclaration()
-{
-    mPrinter->Print({{"classname", mClassName}}, Templates::ProtoClassDefinitionTemplate);
-}
-
-void ClassGeneratorBase::encloseClass()
-{
-    mPrinter->Print(Templates::SemicolonBlockEnclosureTemplate);
-}
-
-void ClassGeneratorBase::encloseNamespaces(int count)
-{
-    for (int i = 0; i < count; i++) {
-        mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
-    }
-}
-
-void ClassGeneratorBase::encloseNamespaces()
-{
-    encloseNamespaces(mNamespaces.size());
-}
-
-void ClassGeneratorBase::printPublicBlock()
-{
-    mPrinter->Print(Templates::PublicBlockTemplate);
-}
-
-void ClassGeneratorBase::printPrivateBlock()
-{
-    mPrinter->Print(Templates::PrivateBlockTemplate);
-}
-
-void ClassGeneratorBase::printSignalsBlock()
-{
-    mPrinter->Print(Templates::SignalsBlockTemplate);
-}
-
-
-bool ClassGeneratorBase::isLocalMessageEnum(const google::protobuf::Descriptor *message,
-                                            const ::google::protobuf::FieldDescriptor *field)
-{
-    if (message == nullptr) {
-        return false;
-    }
-
-    assert(field->enum_type() != nullptr);
-    for (int i = 0; i < message->enum_type_count(); i++) {
-        const auto enumDescr = message->enum_type(i);
-        if (enumDescr && enumDescr->full_name() == field->enum_type()->full_name()) {
-            return true;
-        }
-    }
-    return false;
-}
-
-std::string ClassGeneratorBase::getTypeName(const FieldDescriptor *field, const Descriptor *messageFor)
-{
-    assert(field != nullptr);
-    std::string typeName;
-    std::string namespaceQtProtoDefinition("QtProtobuf::");
-
-    std::string namespaceTypeName;
-    std::vector<std::string> typeNamespace;
-
-    if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
-        const Descriptor *msg = field->message_type();
-        namespaceTypeName = getNamespacesList(msg, typeNamespace, mNamespacesColonDelimited);
-        typeName = namespaceTypeName.append(utils::upperCaseName(msg->name()));
-
-        if (field->is_map()) {
-            return mClassName + "::" + utils::upperCaseName(msg->name());
-        }
-        if (field->is_repeated()) {
-            return namespaceTypeName.append(Templates::ListSuffix);
-        }
-    } else if (field->type() == FieldDescriptor::TYPE_ENUM) {
-        const EnumDescriptor *enumType = field->enum_type();
-        namespaceTypeName = getNamespacesList(enumType, typeNamespace, mNamespacesColonDelimited);
-        EnumVisibility visibility = getEnumVisibility(field, messageFor);
-        if (visibility == LOCAL_ENUM) {
-            if (field->is_repeated()) {
-                typeName = typeName.append(mClassName + "::" + enumType->name());
-            } else {
-                //Note: For local enum classes it's impossible to use class name space in Q_PROPERTY
-                //declaration. So please avoid addition of mClassName in line bellow
-                typeName = typeName.append(enumType->name());
-            }
-        } else if (visibility == GLOBAL_ENUM) {
-            namespaceTypeName = getNamespacesList(enumType, typeNamespace, "");
-            typeName = namespaceTypeName.append(enumType->name() + Templates::EnumClassSuffix)
-                    .append("::").append(enumType->name());
-        } else {
-            typeName = namespaceTypeName.append(enumType->name());
-        }
-        if (field->is_repeated()) {
-            return typeName.append(Templates::ListSuffix);
-        }
-    } else {
-        auto it = Templates::TypeReflection.find(field->type());
-        if (it != std::end(Templates::TypeReflection)) {
-            if (field->type() != FieldDescriptor::TYPE_STRING
-                    && field->type() != FieldDescriptor::TYPE_BYTES
-                    && field->type() != FieldDescriptor::TYPE_BOOL
-                    && field->type() != FieldDescriptor::TYPE_FLOAT
-                    && field->type() != FieldDescriptor::TYPE_DOUBLE) {
-                typeName = typeName.append(namespaceQtProtoDefinition.append(it->second));
-            } else {
-                typeName = typeName.append(it->second);
-            }
-            if (field->is_repeated()) {
-                if (field->type() == FieldDescriptor::TYPE_FLOAT
-                        || field->type() == FieldDescriptor::TYPE_DOUBLE) {
-                    typeName[0] =  static_cast<char>(::toupper(typeName[0]));
-                    typeName = namespaceQtProtoDefinition.append(typeName);
-                }
-                typeName.append("List");
-            }
-        }
-    }
-
-    return typeName;
-}
-
-std::string ClassGeneratorBase::getQmlAliasTypeName(const ::google::protobuf::FieldDescriptor *field, const ::google::protobuf::Descriptor *messageFor)
-{
-    if (!field->is_repeated() && !field->is_map()) {
-        switch (field->type()) {
-        case FieldDescriptor::TYPE_INT32:
-        case FieldDescriptor::TYPE_SFIXED32:
-            return "int";
-        case FieldDescriptor::TYPE_FIXED32:
-            return "unsigned int";
-        default:
-            break;//Do nothing
-        }
-    }
-    return getTypeName(field, messageFor);
-}
-
-template<typename T>
-std::string ClassGeneratorBase::getNamespacesList(const T *message, std::vector<std::string> &container, const std::string &localNamespace)
-{
-    std::string result;
-    container = utils::split(std::string(message->full_name()), '.');
-
-    if (container.size() > 1) {
-        //delete type name -> only namespace stays
-        container.pop_back();
-
-        for (size_t i = 0; i < container.size(); i++) {
-            if (i > 0) {
-                result = result.append("::");
-            }
-            result = result.append(container[i]);
-        }
-    }
-
-    if (!container.empty()
-            && localNamespace != result) {
-        result = result.append("::");
-    } else {
-        result.clear();
-    }
-
-    return result;
-}
-
-ClassGeneratorBase::EnumVisibility ClassGeneratorBase::getEnumVisibility(const FieldDescriptor *field, const Descriptor *messageFor)
-{
-    assert(field->enum_type() != nullptr);
-
-    if (isLocalMessageEnum(messageFor, field)) {
-        return LOCAL_ENUM;
-    }
-
-    const EnumDescriptor *enumType = field->enum_type();
-    const FileDescriptor *enumFile = field->enum_type()->file();
-
-    for (int i = 0; i < enumFile->message_type_count(); i++) {
-        const Descriptor *msg = enumFile->message_type(i);
-        for (int j = 0; j < msg->enum_type_count(); j++) {
-            if (enumType->full_name() == msg->enum_type(j)->full_name()) {
-                return NEIGHBOUR_ENUM;
-            }
-        }
-    }
-
-    return GLOBAL_ENUM;
-}
-
-void ClassGeneratorBase::getMethodParameters(const MethodDescriptor *method, std::map<std::string, std::string> &parameters)
-{
-    std::string inputTypeName = method->input_type()->full_name();
-    std::string outputTypeName = method->output_type()->full_name();
-    std::string methodName = method->name();
-    std::string methodNameUpper = method->name();
-    methodNameUpper[0] =  static_cast<char>(::toupper(methodNameUpper[0]));
-    utils::replace(inputTypeName, ".", "::");
-    utils::replace(outputTypeName, ".", "::");
-    parameters = {{"classname", mClassName},
-                  {"return_type", outputTypeName},
-                  {"method_name", methodName},
-                  {"method_name_upper", methodNameUpper},
-                  {"param_type", inputTypeName},
-                  {"param_name", "arg"},
-                  {"return_name", "ret"}
-                 };
-}
-
-bool ClassGeneratorBase::hasGlobalEnum(const std::list<const FileDescriptor *> &list)
-{
-    for (auto file : list) {
-        if (file->enum_type_count() <= 0) {
-            return false;
-        }
-    }
-    return true;
-}
-
-void ClassGeneratorBase::printField(const google::protobuf::Descriptor *message, const FieldDescriptor *field, const char *fieldTemplate)
-{
-    assert(field != nullptr);
-    std::map<std::string, std::string> propertyMap;
-    if (producePropertyMap(message, field, propertyMap)) {
-        mPrinter->Print(propertyMap, fieldTemplate);
-    }
-}
-
-bool ClassGeneratorBase::producePropertyMap(const google::protobuf::Descriptor *message, const FieldDescriptor *field, PropertyMap &propertyMap)
-{
-    assert(field != nullptr);
-    std::string scriptable = "true";
-    std::string typeName = getTypeName(field, message);
-    std::string qmlAliasTypeName = getQmlAliasTypeName(field, message);
-    std::string getterType = typeName;
-
-    if (typeName.size() <= 0) {
-        std::cerr << "Type "
-                  << field->type_name()
-                  << " is not supported by Qt Generator"
-                     " please look at https://doc.qt.io/qt-5/qtqml-typesystem-basictypes.html"
-                     " for details" << std::endl;
-        return false;
-    }
-
-    std::string typeNameNoList = typeName;
-    if (field->is_repeated() && !field->is_map()) {
-        if(field->type() == FieldDescriptor::TYPE_MESSAGE
-                || field->type() == FieldDescriptor::TYPE_ENUM) {
-            typeNameNoList.resize(typeNameNoList.size() - strlen(Templates::ListSuffix));
-        } else {
-            typeNameNoList.resize(typeNameNoList.size() - strlen("List"));
-        }
-    }
-
-    if (!field->is_map() && !field->is_repeated() && (field->type() == FieldDescriptor::TYPE_INT64
-                                                      || field->type() == FieldDescriptor::TYPE_SINT64
-                                                      || field->type() == FieldDescriptor::TYPE_FIXED64
-                                                      || field->type() == FieldDescriptor::TYPE_SFIXED64)) {
-        scriptable = "false";
-    }
-
-    if (field->type() == FieldDescriptor::TYPE_INT32
-         || field->type() == FieldDescriptor::TYPE_FIXED32
-         || field->type() == FieldDescriptor::TYPE_SFIXED32
-         || field->type() == FieldDescriptor::TYPE_INT64
-         || field->type() == FieldDescriptor::TYPE_FIXED64
-         || field->type() == FieldDescriptor::TYPE_SFIXED64) {
-        getterType = "const " + getterType;
-    }
-
-    std::string fieldName = utils::lowerCaseName(field->camelcase_name());
-    fieldName = qualifiedName(fieldName);
-
-    std::string capProperty = fieldName;
-    capProperty[0] = static_cast<char>(::toupper(capProperty[0]));
-
-    propertyMap = {{"type", typeName},
-                   {"classname", utils::upperCaseName(message->name())},
-                   {"property_name", fieldName},
-                   {"property_name_cap", capProperty},
-                   {"type_nolist", typeNameNoList},
-                   {"qml_alias_type", qmlAliasTypeName},
-                   {"scriptable", scriptable},
-                   {"getter_type", getterType}
-                  };
-    return true;
-}
-
-bool ClassGeneratorBase::isComplexType(const FieldDescriptor *field)
-{
-    assert(field != nullptr);
-    return field->type() == FieldDescriptor::TYPE_MESSAGE
-            || field->type() == FieldDescriptor::TYPE_STRING
-            || field->type() == FieldDescriptor::TYPE_BYTES;
-}
-
-std::string ClassGeneratorBase::qualifiedName(const std::string &name)
-{
-    std::string fieldName(name);
-    const std::vector<std::string> &searchExeptions = Templates::ListOfQmlExeptions;
-
-    auto searchResult = std::find(searchExeptions.begin(), searchExeptions.end(), fieldName);
-    if (searchResult != searchExeptions.end()) {
-        return fieldName.append(Templates::ProtoSufix);
-    }
-    return fieldName;
-}
-
-void ClassGeneratorBase::printInclude(const google::protobuf::Descriptor *message, const FieldDescriptor *field, std::set<std::string> &existingIncludes)
-{
-    assert(field != nullptr);
-    std::string newInclude;
-    const char *includeTemplate;
-    switch (field->type()) {
-    case FieldDescriptor::TYPE_MESSAGE:
-        if ( field->is_map() ) {
-            newInclude = "QMap";
-            assert(field->message_type() != nullptr);
-            assert(field->message_type()->field_count() == 2);
-            printInclude(message, field->message_type()->field(0), existingIncludes);
-            printInclude(message, field->message_type()->field(1), existingIncludes);
-            includeTemplate = Templates::ExternalIncludeTemplate;
-        } else {
-            std::string outFileBasename = "";
-            std::string fieldPackage = field->message_type()->file()->package();
-            if (fieldPackage != message->file()->package()) {
-                std::vector<std::string> packages = utils::split(fieldPackage, '.');
-                for (auto package : packages) {
-                    outFileBasename += package + "/";
-                }
-            }
-
-            std::string typeName = field->message_type()->name();
-            utils::tolower(typeName);
-            newInclude = outFileBasename + typeName;
-            includeTemplate = Templates::InternalIncludeTemplate;
-        }
-        break;
-    case FieldDescriptor::TYPE_BYTES:
-        newInclude = "QByteArray";
-        includeTemplate = Templates::ExternalIncludeTemplate;
-        break;
-    case FieldDescriptor::TYPE_STRING:
-        newInclude = "QString";
-        includeTemplate = Templates::ExternalIncludeTemplate;
-        break;
-    case FieldDescriptor::TYPE_ENUM: {
-        EnumVisibility enumVisibily = getEnumVisibility(field, message);
-        if (enumVisibily == GLOBAL_ENUM) {
-            includeTemplate = Templates::GlobalEnumIncludeTemplate;
-        } else if (enumVisibily == NEIGHBOUR_ENUM) {
-            includeTemplate = Templates::InternalIncludeTemplate;
-            std::string fullEnumName = field->enum_type()->full_name();
-            std::vector<std::string> fullEnumNameParts = utils::split(fullEnumName, '.');
-            std::string enumTypeOwner = fullEnumNameParts.at(fullEnumNameParts.size() - 2);
-            utils::tolower(enumTypeOwner);
-            newInclude = enumTypeOwner;
-        } else {
-            return;
-        }
-    }
-        break;
-    default:
-        return;
-    }
-
-    if (existingIncludes.find(newInclude) == std::end(existingIncludes)) {
-        mPrinter->Print({{"include", newInclude}}, includeTemplate);
-        existingIncludes.insert(newInclude);
-    }
-}

+ 0 - 179
src/generator/classgeneratorbase.h

@@ -1,179 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
- *
- * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this
- * software and associated documentation files (the "Software"), to deal in the Software
- * without restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
- * to permit persons to whom the Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies
- * or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
- * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#pragma once
-
-#include <google/protobuf/io/printer.h>
-#include <memory>
-#include <list>
-
-#include "utils.h"
-#include "templates.h"
-#include "generatoroptions.h"
-
-namespace google { namespace protobuf {
-class FieldDescriptor;
-class Descriptor;
-class MethodDescriptor;
-namespace io {
-class ZeroCopyOutputStream;
-}}}
-
-namespace QtProtobuf {
-namespace generator {
-
-using PropertyMap = std::map<std::string, std::string>;
-
-/*!
- * \ingroup generator
- * \private
- * \brief The ClassGeneratorBase class is base of source code generation
- */
-class ClassGeneratorBase
-{
-public:
-    ClassGeneratorBase(const std::string &fullClassName, const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out);
-    ClassGeneratorBase(const std::string &fullClassName, const std::shared_ptr<::google::protobuf::io::Printer> &printer);
-    virtual ~ClassGeneratorBase() = default;
-    virtual void run() = 0;
-protected:
-    enum EnumVisibility {
-        GLOBAL_ENUM,
-        LOCAL_ENUM,
-        NEIGHBOUR_ENUM
-    };
-
-    std::shared_ptr<::google::protobuf::io::ZeroCopyOutputStream> mOutput;
-    std::shared_ptr<::google::protobuf::io::Printer> mPrinter;
-    std::string mClassName;
-    std::vector<std::string> mNamespaces;
-    std::string mNamespacesColonDelimited;
-
-public:
-    void printDisclaimer();
-    void printPreamble();
-    void printNamespaces();
-    void printNamespaces(const std::vector<std::string> &namespaces);
-    void printClassDeclaration();
-    void printPublicBlock();
-    void printPrivateBlock();
-    void printSignalsBlock();
-    void encloseClass();
-    void encloseNamespaces();
-    void encloseNamespaces(int count);
-    void printInclude(const google::protobuf::Descriptor *message, const google::protobuf::FieldDescriptor *field, std::set<std::string> &existingIncludes);
-    bool hasGlobalEnum(const std::list<const ::google::protobuf::FileDescriptor *> &list);
-    void printField(const google::protobuf::Descriptor *message, const ::google::protobuf::FieldDescriptor *field, const char *fieldTemplate);
-    bool producePropertyMap(const google::protobuf::Descriptor *message, const ::google::protobuf::FieldDescriptor *field, PropertyMap &propertyMap);
-    bool isComplexType(const google::protobuf::FieldDescriptor *field);
-    std::string qualifiedName(const std::string &name);
-
-    template<typename T>
-    void printQEnums(const T *message) {
-        if (message->enum_type_count() <= 0) {
-            return;
-        }
-
-        printPublicBlock();
-
-        Indent();
-        for (int i = 0; i < message->enum_type_count(); i++) {
-            const auto enumDescr = message->enum_type(i);
-            mPrinter->Print({{"enum", enumDescr->name()}}, Templates::EnumDefinitionTemplate);
-
-            Indent();
-            for (int j = 0; j < enumDescr->value_count(); j++) {
-                const auto valueDescr = enumDescr->value(j);
-                mPrinter->Print({{"enumvalue", utils::upperCaseName(valueDescr->name())},
-                                 {"value", std::to_string(valueDescr->number())}}, Templates::EnumFieldTemplate);
-            }
-            Outdent();
-            mPrinter->Print(Templates::SemicolonBlockEnclosureTemplate);
-            mPrinter->Print({{"type", enumDescr->name().c_str()}}, Templates::QEnumTemplate);
-        }
-
-        for (int i = 0; i < message->enum_type_count(); i++) {
-            const auto enumDescr = message->enum_type(i);
-            mPrinter->Print({{"enum", enumDescr->name()}}, Templates::EnumTypeRepeatedTemplate);
-        }
-        Outdent();
-    }
-
-    template<typename T>
-    void printComments(T *descriptor) {
-        if (!GeneratorOptions::instance().generateComments()) {
-            return;
-        }
-
-        ::google::protobuf::SourceLocation loc;
-        descriptor->GetSourceLocation(&loc);
-
-        utils::trim(loc.leading_comments);
-        if (loc.leading_comments.size() > 0) {
-            auto firstEntry = loc.leading_comments.find('\n');
-            bool isSingleLine = firstEntry == std::string::npos;
-
-            if (loc.leading_comments[0] != '!' && loc.leading_comments[0] != '*' && loc.leading_comments[0] != ' ') {
-                loc.leading_comments = " " + loc.leading_comments;
-                if (!isSingleLine) {
-                    loc.leading_comments = "\n" + loc.leading_comments;
-                }
-            }
-            mPrinter->Print("\n/*");
-            if (isSingleLine) {
-                mPrinter->Print(loc.leading_comments.c_str());
-            } else {
-                utils::replace(loc.leading_comments, "\n", "\n *");
-                mPrinter->Print(loc.leading_comments.c_str());
-                if (loc.leading_comments[loc.leading_comments.size() - 1] != '\n') {
-                    mPrinter->Print("\n");
-                }
-            }
-            mPrinter->Print(" */");
-        }
-    }
-
-    void Indent() {
-        mPrinter->Indent();
-        mPrinter->Indent();
-    }
-
-    void Outdent() {
-        mPrinter->Outdent();
-        mPrinter->Outdent();
-    }
-
-    std::string getTypeName(const ::google::protobuf::FieldDescriptor *field, const ::google::protobuf::Descriptor *messageFor);
-    std::string getQmlAliasTypeName(const ::google::protobuf::FieldDescriptor *field, const ::google::protobuf::Descriptor *messageFor);
-    static bool isLocalMessageEnum(const google::protobuf::Descriptor *message,
-                            const ::google::protobuf::FieldDescriptor *field);
-    template<typename T>
-    static std::string getNamespacesList(const T *message, std::vector<std::string> &container, const std::string &localNamespace);
-    static EnumVisibility getEnumVisibility(const ::google::protobuf::FieldDescriptor *field, const ::google::protobuf::Descriptor *messageFor);
-    void getMethodParameters(const ::google::protobuf::MethodDescriptor *method, std::map<std::string, std::string> &parameters);
-};
-
-} //namespace generator
-} //namespace QtProtobuf

+ 13 - 21
src/generator/clientgenerator.cpp → src/generator/clientdeclarationprinter.cpp

@@ -23,7 +23,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "clientgenerator.h"
+#include "clientdeclarationprinter.h"
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
@@ -39,33 +39,26 @@
 using namespace ::QtProtobuf::generator;
 using namespace ::google::protobuf;
 using namespace ::google::protobuf::compiler;
-
-ClientGenerator::ClientGenerator(const ServiceDescriptor *service, const std::shared_ptr<io::ZeroCopyOutputStream> &out) :
-    ServiceGeneratorBase(service, out)
-{
-    mClassName += "Client";
-}
-
-ClientGenerator::ClientGenerator(const ::google::protobuf::ServiceDescriptor *service, const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
-    ServiceGeneratorBase(service, printer)
+ClientDeclarationPrinter::ClientDeclarationPrinter(const ::google::protobuf::ServiceDescriptor *service, const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
+    ServiceDeclarationPrinterBase(service, printer)
 {
-    mClassName += "Client";
+    mName += "Client";
 }
 
-void ClientGenerator::printClientClass()
+void ClientDeclarationPrinter::printClientClass()
 {
-    mPrinter->Print({{"classname", mClassName}, {"parent_class", "QtProtobuf::QAbstractGrpcClient"}}, Templates::ClassDefinitionTemplate);
+    mPrinter->Print({{"classname", mName}, {"parent_class", "QtProtobuf::QAbstractGrpcClient"}}, Templates::ClassDefinitionTemplate);
     mPrinter->Print(Templates::QObjectMacro);
 }
 
-void ClientGenerator::printConstructor()
+void ClientDeclarationPrinter::printConstructor()
 {
     Indent();
-    mPrinter->Print({{"classname", mClassName}}, Templates::QObjectConstructorTemplate);
+    mPrinter->Print({{"classname", mName}}, Templates::QObjectConstructorTemplate);
     Outdent();
 }
 
-void ClientGenerator::printClientIncludes()
+void ClientDeclarationPrinter::printClientIncludes()
 {
     std::unordered_set<std::string> includeSet;
     includeSet.insert("QAbstractGrpcClient");
@@ -76,13 +69,12 @@ void ClientGenerator::printClientIncludes()
     }
 }
 
-void ClientGenerator::printClientMethodsDeclaration()
+void ClientDeclarationPrinter::printClientMethodsDeclaration()
 {
     Indent();
-    for (int i = 0; i < mService->method_count(); i++) {
-        const MethodDescriptor *method = mService->method(i);
-        std::map<std::string, std::string> parameters;
-        getMethodParameters(method, parameters);
+    for (int i = 0; i < mDescriptor->method_count(); i++) {
+        const MethodDescriptor *method = mDescriptor->method(i);
+        std::map<std::string, std::string> parameters = common::produceMethodMap(method, mName);
 
         if (method->server_streaming()) {
             mPrinter->Print(parameters, Templates::ClientMethodServerStreamDeclarationTemplate);

+ 9 - 12
src/generator/clientgenerator.h → src/generator/clientdeclarationprinter.h

@@ -25,7 +25,7 @@
 
 #pragma once
 
-#include "servicegeneratorbase.h"
+#include "servicedeclarationprinterbase.h"
 #include <string>
 #include <memory>
 #include <google/protobuf/io/printer.h>
@@ -41,22 +41,16 @@ namespace generator {
 /*!
  * \ingroup generator
  * \private
- * \brief The ClientGenerator class
+ * \brief The ClientDeclarationprinter class
  */
-class ClientGenerator : public ServiceGeneratorBase
+class ClientDeclarationPrinter : public ServiceDeclarationPrinterBase
 {
 public:
-    ClientGenerator(const ::google::protobuf::ServiceDescriptor *service,
-                    const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out);
-    ClientGenerator(const ::google::protobuf::ServiceDescriptor *service,
+    ClientDeclarationPrinter(const ::google::protobuf::ServiceDescriptor *service,
                     const std::shared_ptr<::google::protobuf::io::Printer> &printer);
-    ~ClientGenerator() = default;
+    ~ClientDeclarationPrinter() = default;
 
     void run() {
-        printDisclaimer();
-        printPreamble();
-        printIncludes();
-        printClientIncludes();
         printNamespaces();
         printClientClass();
         printPublicBlock();
@@ -65,9 +59,12 @@ public:
         encloseClass();
         encloseNamespaces();
     }
+
+    void printClientIncludes();
+
+private:
     void printClientClass();
     void printConstructor();
-    void printClientIncludes();
     void printClientMethodsDeclaration();
 };
 

+ 12 - 22
src/generator/clientsourcegenerator.cpp → src/generator/clientdefinitionprinter.cpp

@@ -23,40 +23,30 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "clientsourcegenerator.h"
+#include "clientdefinitionprinter.h"
 
 #include <google/protobuf/io/zero_copy_stream.h>
 
 #include "utils.h"
 #include "templates.h"
+#include "generatorcommon.h"
 
 using namespace QtProtobuf::generator;
 using namespace ::google::protobuf;
 using namespace ::google::protobuf::compiler;
 
-ClientSourceGenerator::ClientSourceGenerator(const google::protobuf::ServiceDescriptor *service,
-                                             const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out) :
-    ClassSourceGeneratorBase(service->full_name(), out)
-  , mService(service)
-{
-    mClassName += "Client";
-}
-
-
-ClientSourceGenerator::ClientSourceGenerator(const google::protobuf::ServiceDescriptor *service,
+ClientDefinitionPrinter::ClientDefinitionPrinter(const google::protobuf::ServiceDescriptor *service,
                       const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
-    ClassSourceGeneratorBase(service->full_name(), printer)
-  , mService(service)
+    DescriptorPrinterBase<google::protobuf::ServiceDescriptor>(service, printer)
 {
-    mClassName += "Client";
+    mName += "Client";
 }
 
-void ClientSourceGenerator::printMethods()
+void ClientDefinitionPrinter::printMethods()
 {
-    for (int i = 0; i < mService->method_count(); i++) {
-        const MethodDescriptor *method = mService->method(i);
-        std::map<std::string, std::string> parameters;
-        getMethodParameters(method, parameters);
+    for (int i = 0; i < mDescriptor->method_count(); i++) {
+        const MethodDescriptor *method = mDescriptor->method(i);
+        MethodMap parameters = common::produceMethodMap(method, mName);
         if (method->server_streaming()) {
             mPrinter->Print(parameters, Templates::ClientMethodServerStreamDefinitionTemplate);
             mPrinter->Print(parameters, Templates::ClientMethodServerStream2DefinitionTemplate);
@@ -68,9 +58,9 @@ void ClientSourceGenerator::printMethods()
     }
 }
 
-void ClientSourceGenerator::printConstructor()
+void ClientDefinitionPrinter::printConstructor()
 {
-    mPrinter->Print({ {"classname", mClassName},
+    mPrinter->Print({ {"classname", mName},
                      {"parent_class", "QAbstractGrpcClient"},
-                     {"service_name", mService->full_name()} }, Templates::ClientConstructorDefinitionTemplate);
+                     {"service_name", mDescriptor->full_name()} }, Templates::ClientConstructorDefinitionTemplate);
 }

+ 7 - 12
src/generator/clientsourcegenerator.h → src/generator/clientdefinitionprinter.h

@@ -25,34 +25,29 @@
 
 #pragma once
 
-#include "classsourcegeneratorbase.h"
+#include "descriptorprinterbase.h"
 
 namespace QtProtobuf {
 namespace generator {
 /*!
  * \ingroup generator
  * \private
- * \brief The ClientSourceGenerator class
+ * \brief The ClientDefinitionPrinter class
  */
-class ClientSourceGenerator : public ClassSourceGeneratorBase
+class ClientDefinitionPrinter : public DescriptorPrinterBase<google::protobuf::ServiceDescriptor>
 {
 public:
-    ClientSourceGenerator(const google::protobuf::ServiceDescriptor *service,
-                          const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out);
-    ClientSourceGenerator(const google::protobuf::ServiceDescriptor *service,
+    ClientDefinitionPrinter(const google::protobuf::ServiceDescriptor *service,
                           const std::shared_ptr<::google::protobuf::io::Printer> &printer);
-    void run() override {
-        printDisclaimer();
-        printClassHeaderInclude();
-        printUsingNamespaces({"QtProtobuf", mNamespacesColonDelimited});
+    void run() {
+        printNamespaces();
         printConstructor();
         printMethods();
+        encloseNamespaces();
     }
 
     void printMethods();
     void printConstructor();
-protected:
-    const ::google::protobuf::ServiceDescriptor *mService;
 };
 
 } //namespace QtProtobuf

+ 89 - 0
src/generator/descriptorprinterbase.h

@@ -0,0 +1,89 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
+ *
+ * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies
+ * or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "baseprinter.h"
+
+#include "utils.h"
+#include "templates.h"
+#include "generatoroptions.h"
+#include "generatorcommon.h"
+
+namespace QtProtobuf {
+namespace generator {
+
+using PropertyMap = std::map<std::string, std::string>;
+
+/*!
+ * \ingroup generator
+ * \private
+ * \brief The DescriptorPrinterBase class is base of source code generation
+ */
+
+template<typename T>
+class DescriptorPrinterBase : public BasePrinter
+{
+public:
+    DescriptorPrinterBase(const T* descriptor, const std::shared_ptr<::google::protobuf::io::Printer> &printer) : BasePrinter(printer)
+      , mDescriptor(descriptor)
+      , mName(utils::upperCaseName(descriptor->name()))
+    {}
+    virtual ~DescriptorPrinterBase() = default;
+public:
+    void printClassDeclaration() {
+        mPrinter->Print({{"classname", mName}}, Templates::ProtoClassDefinitionTemplate);
+    }
+
+    void encloseClass() {
+        mPrinter->Print(Templates::SemicolonBlockEnclosureTemplate);
+        mPrinter->Print("\n");
+    }
+
+    void printNamespaces() {
+        auto namespaces = common::getNamespaces(mDescriptor);
+        mPrinter->Print("\n");
+        for (auto ns : namespaces) {
+            mPrinter->Print({{"namespace", ns}}, Templates::NamespaceTemplate);
+        }
+    }
+
+    void encloseNamespaces() {
+        auto namespaces = common::getNamespaces(mDescriptor);
+        mPrinter->Print("\n");
+        for (size_t i = 0; i < namespaces.size(); ++i) {
+            mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
+        }
+        mPrinter->Print("\n");
+    }
+
+protected:
+    const T* mDescriptor;
+    std::string mName;
+    TypeMap mTypeMap;
+};
+
+} //namespace generator
+} //namespace QtProtobuf

+ 96 - 0
src/generator/enumdeclarationprinter.cpp

@@ -0,0 +1,96 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
+ *
+ * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies
+ * or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "enumdeclarationprinter.h"
+#include "generatorcommon.h"
+
+using namespace ::QtProtobuf::generator;
+using namespace ::google::protobuf;
+
+EnumDeclarationPrinter::EnumDeclarationPrinter(const EnumDescriptor *descriptor, const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
+    DescriptorPrinterBase<google::protobuf::EnumDescriptor>(descriptor, printer)
+{
+    mTypeMap = common::produceEnumTypeMap(descriptor, nullptr);
+    mName += Templates::EnumClassSuffix;
+}
+
+void EnumDeclarationPrinter::startEnum()
+{
+    printNamespaces();
+    printEnumClass();
+    printPublicBlock();
+    Indent();
+    mPrinter->Print({{"classname", mName}}, Templates::ManualRegistrationDeclaration);
+    Outdent();
+    printPrivateBlock();
+    printConstructor();
+}
+
+void EnumDeclarationPrinter::printEnum()
+{
+    auto typeMap = common::produceEnumTypeMap(mDescriptor, nullptr);
+    printPublicBlock();
+
+    Indent();
+    mPrinter->Print(typeMap, Templates::EnumDefinitionTemplate);
+
+    Indent();
+    for (int j = 0; j < mDescriptor->value_count(); j++) {
+        const auto valueDescr = mDescriptor->value(j);
+        mPrinter->Print({{"enumvalue", utils::upperCaseName(valueDescr->name())},
+                         {"value", std::to_string(valueDescr->number())}}, Templates::EnumFieldTemplate);
+    }
+    Outdent();
+    mPrinter->Print(Templates::SemicolonBlockEnclosureTemplate);
+    mPrinter->Print(typeMap, Templates::QEnumTemplate);
+    mPrinter->Print(typeMap, Templates::EnumTypeRepeatedTemplate);
+    Outdent();
+}
+
+void EnumDeclarationPrinter::printConstructor()
+{
+    Indent();
+    mPrinter->Print({{"classname", mName}}, Templates::ConstructorHeaderTemplate);
+    mPrinter->Print({{"classname", mName}}, Templates::DeletedCopyConstructorTemplate);
+    mPrinter->Print({{"classname", mName}}, Templates::DeletedMoveConstructorTemplate);
+    Outdent();
+}
+
+void EnumDeclarationPrinter::printMetatype()
+{
+    mPrinter->Print(mTypeMap,
+                   Templates::DeclareMetaTypeListTemplate);
+}
+
+void EnumDeclarationPrinter::encloseEnum()
+{
+    encloseClass();
+    encloseNamespaces();
+}
+
+void EnumDeclarationPrinter::printEnumClass()
+{
+    mPrinter->Print({{"classname", mName}}, Templates::ClassDeclarationTemplate);
+}

+ 13 - 17
src/generator/enumsgenerator.h → src/generator/enumdeclarationprinter.h

@@ -1,7 +1,7 @@
 /*
  * MIT License
  *
- * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
+ * Copyright (c) 2020 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
  *
  * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
  *
@@ -25,40 +25,36 @@
 
 #pragma once
 
-#include "classgeneratorbase.h"
-#include "utils.h"
-#include "generatorcommon.h"
+#include "descriptorprinterbase.h"
 
-namespace google {
-namespace protobuf {
-class EnumDescriptor;
-}}
 namespace QtProtobuf {
 namespace generator {
 
 /*!
  * \ingroup generator
  * \private
- * \brief The EnumsGenerator class
+ * \brief The EnumDeclarationPrinter class
  */
-class EnumsGenerator : public ClassGeneratorBase
+class EnumDeclarationPrinter : public DescriptorPrinterBase<google::protobuf::EnumDescriptor>
 {
-    const google::protobuf::EnumDescriptor *mEnumDescriptor;
 public:
-    EnumsGenerator(const google::protobuf::EnumDescriptor *enumDesctiptor, const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out);
-    EnumsGenerator(const google::protobuf::EnumDescriptor *enumDesctiptor, const std::shared_ptr<::google::protobuf::io::Printer> &printer);
-    virtual ~EnumsGenerator() = default;
+    EnumDeclarationPrinter(const google::protobuf::EnumDescriptor *descriptor, const std::shared_ptr<::google::protobuf::io::Printer> &printer);
+    virtual ~EnumDeclarationPrinter() = default;
 
-    void run();
+    void run() {
+        startEnum();
+        printEnum();
+        encloseEnum();
+        printMetatype();
+    }
 
+private:
     void startEnum();
     void printEnum();
     void encloseEnum();
     void printMetatype();
     void printEnumClass();
     void printConstructor();
-private:
-    TypeMap mTypeMap;
 };
 
 } //namespace generator

+ 23 - 26
src/generator/classsourcegeneratorbase.cpp → src/generator/enumdefinitionprinter.cpp

@@ -1,7 +1,7 @@
 /*
  * MIT License
  *
- * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
+ * Copyright (c) 2020 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
  *
  * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
  *
@@ -23,45 +23,42 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "classsourcegeneratorbase.h"
+#include "enumdefinitionprinter.h"
 
-#include <google/protobuf/io/zero_copy_stream.h>
-
-#include "templates.h"
-#include "utils.h"
 #include "generatoroptions.h"
 
-using namespace QtProtobuf::generator;
+using namespace ::QtProtobuf::generator;
 using namespace ::google::protobuf;
 using namespace ::google::protobuf::io;
 using namespace ::google::protobuf::compiler;
 
-ClassSourceGeneratorBase::ClassSourceGeneratorBase(const std::string &fullClassName,
-                                                   const std::shared_ptr<::google::protobuf::io::ZeroCopyOutputStream> &out) :
-    ClassGeneratorBase(fullClassName, out)
+EnumDefinitionPrinter::EnumDefinitionPrinter(const google::protobuf::EnumDescriptor *descriptor, const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
+    DescriptorPrinterBase<google::protobuf::EnumDescriptor>(descriptor, printer)
 {
-
+    mTypeMap = common::produceEnumTypeMap(descriptor, nullptr);
+    mName += Templates::EnumClassSuffix;
 }
 
-ClassSourceGeneratorBase::ClassSourceGeneratorBase(const std::string &fullClassName, const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
-    ClassGeneratorBase(fullClassName, printer)
-{
-
+void EnumDefinitionPrinter::run() {
+    printNamespaces();
+    printRegisterBody();
+    encloseNamespaces();
 }
 
-void ClassSourceGeneratorBase::printClassHeaderInclude()
+void EnumDefinitionPrinter::printRegisterBody()
 {
-    std::string includeFileName = mClassName;
-    utils::tolower(includeFileName);
-    mPrinter->Print({{"include", includeFileName}}, Templates::InternalIncludeTemplate);
+    auto typeMap = mTypeMap;
+    typeMap["classname"] = mName;
+    mPrinter->Print(typeMap, Templates::EnumRegistrarTemplate);
+    mPrinter->Print(typeMap, Templates::ManualRegistrationGlobalEnumDefinition);
+    Indent();
     if (GeneratorOptions::instance().hasQml()) {
-        mPrinter->Print({{"include", "QQmlEngine"}}, Templates::ExternalIncludeTemplate);
+        mPrinter->Print(typeMap, Templates::QmlRegisterEnumTypeTemplate);
     }
-}
 
-void ClassSourceGeneratorBase::printUsingNamespaces(const std::unordered_set<std::string> &namespaces)
-{
-    for (auto ns : namespaces) {
-        mPrinter->Print({{"namespace", ns}}, Templates::UsingNamespaceTemplate);
-    }
+    mPrinter->Print(typeMap, Templates::ComplexGlobalEnumFieldRegistrationTemplate);
+    mPrinter->Print(typeMap, Templates::RegisterGlobalEnumMetaTypeTemplate);
+    mPrinter->Print(typeMap, Templates::RegisterEnumSerializersTemplate);
+    Outdent();
+    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
 }

+ 7 - 10
src/generator/enumssourcegenerator.h → src/generator/enumdefinitionprinter.h

@@ -1,7 +1,7 @@
 /*
  * MIT License
  *
- * Copyright (c) 2019 Tatyana Borisova <tanusshhka@mail.ru>
+ * Copyright (c) 2020 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
  *
  * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
  *
@@ -25,8 +25,7 @@
 
 #pragma once
 
-#include "classgeneratorbase.h"
-#include "utils.h"
+#include "descriptorprinterbase.h"
 
 namespace QtProtobuf {
 namespace generator {
@@ -34,17 +33,15 @@ namespace generator {
 /*!
  * \ingroup generator
  * \private
- * \brief The EnumsSourceGenerator class
+ * \brief The EnumDefinitionPrinter class
  */
-class EnumsSourceGenerator : public ClassGeneratorBase
+class EnumDefinitionPrinter : public DescriptorPrinterBase<google::protobuf::EnumDescriptor>
 {
-    const google::protobuf::EnumDescriptor *mEnumDescriptor;
 public:
-    EnumsSourceGenerator(const google::protobuf::EnumDescriptor *enumDesctiptor, const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out);
-    EnumsSourceGenerator(const google::protobuf::EnumDescriptor *enumDesctiptor, const std::shared_ptr<::google::protobuf::io::Printer> &printer);
-    virtual ~EnumsSourceGenerator() = default;
+    EnumDefinitionPrinter(const google::protobuf::EnumDescriptor *descriptor, const std::shared_ptr<::google::protobuf::io::Printer> &printer);
+    virtual ~EnumDefinitionPrinter() = default;
 
-    void run() override;
+    void run();
     void printRegisterBody();
 };
 

+ 0 - 112
src/generator/enumsgenerator.cpp

@@ -1,112 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
- *
- * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this
- * software and associated documentation files (the "Software"), to deal in the Software
- * without restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
- * to permit persons to whom the Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies
- * or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
- * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include "enumsgenerator.h"
-
-#include <google/protobuf/io/zero_copy_stream.h>
-
-using namespace ::QtProtobuf::generator;
-using namespace ::google::protobuf;
-using namespace ::google::protobuf::io;
-using namespace ::google::protobuf::compiler;
-
-EnumsGenerator::EnumsGenerator(const EnumDescriptor *enumDesctiptor, const std::shared_ptr<io::ZeroCopyOutputStream> &out) :
-    ClassGeneratorBase(enumDesctiptor->full_name() + Templates::EnumClassSuffix, out)
-  , mEnumDescriptor(enumDesctiptor)
-  , mTypeMap(common::produceEnumTypeMap(enumDesctiptor, nullptr))
-{}
-
-
-EnumsGenerator::EnumsGenerator(const EnumDescriptor *enumDesctiptor, const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
-    ClassGeneratorBase(enumDesctiptor->full_name() + Templates::EnumClassSuffix, printer)
-  , mEnumDescriptor(enumDesctiptor)
-  , mTypeMap(common::produceEnumTypeMap(enumDesctiptor, nullptr))
-{}
-
-void EnumsGenerator::startEnum()
-{
-    printNamespaces(mNamespaces);
-    printEnumClass();
-    printPublicBlock();
-    Indent();
-    mPrinter->Print({{"classname", mClassName}}, Templates::ManualRegistrationDeclaration);
-    Outdent();
-    printPrivateBlock();
-    printConstructor();
-}
-
-void EnumsGenerator::printEnum()
-{
-    printPublicBlock();
-
-    Indent();
-    mPrinter->Print({{"enum", mEnumDescriptor->name()}}, Templates::EnumDefinitionTemplate);
-
-    Indent();
-    for (int j = 0; j < mEnumDescriptor->value_count(); j++) {
-        const auto valueDescr = mEnumDescriptor->value(j);
-        mPrinter->Print({{"enumvalue", utils::upperCaseName(valueDescr->name())},
-                         {"value", std::to_string(valueDescr->number())}}, Templates::EnumFieldTemplate);
-    }
-    Outdent();
-    mPrinter->Print(Templates::SemicolonBlockEnclosureTemplate);
-    mPrinter->Print({{"type", mEnumDescriptor->name()}}, Templates::QEnumTemplate);
-    mPrinter->Print({{"enum", mEnumDescriptor->name()}}, Templates::EnumTypeRepeatedTemplate);
-    Outdent();
-}
-
-void EnumsGenerator::printConstructor()
-{
-    Indent();
-    mPrinter->Print({{"classname", mClassName}}, Templates::ConstructorHeaderTemplate);
-    mPrinter->Print({{"classname", mClassName}}, Templates::DeletedCopyConstructorTemplate);
-    mPrinter->Print({{"classname", mClassName}}, Templates::DeletedMoveConstructorTemplate);
-    Outdent();
-}
-
-void EnumsGenerator::run()
-{
-    startEnum();
-    printEnum();
-    encloseEnum();
-    printMetatype();
-}
-
-void EnumsGenerator::printMetatype()
-{
-    mPrinter->Print(mTypeMap,
-                   Templates::DeclareMetaTypeListTemplate);
-}
-
-void EnumsGenerator::encloseEnum()
-{
-    encloseClass();
-    encloseNamespaces();
-}
-
-void EnumsGenerator::printEnumClass()
-{
-    mPrinter->Print({{"classname", mClassName}}, Templates::NonProtoClassDefinitionTemplate);
-}

+ 0 - 83
src/generator/enumssourcegenerator.cpp

@@ -1,83 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) Tatyana Borisova <tanusshhka@mail.ru>
- *
- * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this
- * software and associated documentation files (the "Software"), to deal in the Software
- * without restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
- * to permit persons to whom the Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies
- * or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
- * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include "enumssourcegenerator.h"
-
-#include "generatoroptions.h"
-
-#include <google/protobuf/io/zero_copy_stream.h>
-
-using namespace ::QtProtobuf::generator;
-using namespace ::google::protobuf;
-using namespace ::google::protobuf::io;
-using namespace ::google::protobuf::compiler;
-
-EnumsSourceGenerator::EnumsSourceGenerator(const google::protobuf::EnumDescriptor *enumDesctiptor, const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out) :
-    ClassGeneratorBase(enumDesctiptor->full_name() + Templates::EnumClassSuffix, out)
-  , mEnumDescriptor(enumDesctiptor) {}
-
-
-EnumsSourceGenerator::EnumsSourceGenerator(const google::protobuf::EnumDescriptor *enumDesctiptor, const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
-    ClassGeneratorBase(enumDesctiptor->full_name() + Templates::EnumClassSuffix, printer)
-  , mEnumDescriptor(enumDesctiptor) {}
-
-void EnumsSourceGenerator::run() {
-    printNamespaces(mNamespaces);
-    printRegisterBody();
-    encloseNamespaces();
-}
-
-void EnumsSourceGenerator::printRegisterBody()
-{
-    std::string packageName;
-    for (auto name : mNamespaces) {
-        if (packageName.empty()) {
-            packageName.append(name);
-            continue;
-        }
-        packageName.append(".").append(name);
-    }
-
-    const std::map<std::string, std::string> registrationProperties = {{"classname", mClassName},
-                                                                       {"type", mClassName},
-                                                                       {"namespaces", mNamespacesColonDelimited},
-                                                                       {"package", packageName}};
-    mPrinter->Print(registrationProperties, Templates::EnumRegistrarTemplate);
-    mPrinter->Print(registrationProperties, Templates::ManualRegistrationGlobalEnumDefinition);
-    Indent();
-    if (GeneratorOptions::instance().hasQml()) {
-        mPrinter->Print(registrationProperties, Templates::QmlRegisterTypeUncreatableTemplate);
-    }
-
-    const std::map<std::string, std::string> properties = {{"classname", mClassName},
-                                                           {"type", mClassName + "::" + mEnumDescriptor->name()},
-                                                           {"enum", mEnumDescriptor->name() + Templates::ListSuffix},
-                                                           {"namespaces", mNamespacesColonDelimited}};
-    mPrinter->Print(properties, Templates::ComplexGlobalEnumFieldRegistrationTemplate);
-    mPrinter->Print(properties, Templates::RegisterMetaTypeTemplate);
-    mPrinter->Print(properties, Templates::RegisterEnumSerializersTemplate);
-    Outdent();
-    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
-}

+ 0 - 168
src/generator/generator.cpp

@@ -1,168 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
- *
- * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this
- * software and associated documentation files (the "Software"), to deal in the Software
- * without restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
- * to permit persons to whom the Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies
- * or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
- * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include "generator.h"
-#include "templates.h"
-#include "classgeneratorbase.h"
-#include "protobufclassgenerator.h"
-#include "protobufsourcegenerator.h"
-#include "enumsgenerator.h"
-#include "enumssourcegenerator.h"
-#include "servergenerator.h"
-#include "clientgenerator.h"
-#include "clientsourcegenerator.h"
-#include "utils.h"
-#include "generatoroptions.h"
-
-#include <iostream>
-#include <set>
-#include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#include <google/protobuf/descriptor.h>
-
-using namespace ::QtProtobuf::generator;
-using namespace ::google::protobuf;
-using namespace ::google::protobuf::compiler;
-
-QtGenerator::QtGenerator() : GeneratorBase(GeneratorBase::MultiMode)
-{}
-
-bool QtGenerator::Generate(const FileDescriptor *file,
-                           const std::string &parameter,
-                           GeneratorContext *generatorContext,
-                           std::string *error) const
-{
-    // the variable contains only the relative path to ouput dir which is unused in this method
-    UNUSED(parameter);
-
-    if (file->syntax() != FileDescriptor::SYNTAX_PROTO3) {
-        *error = "Invalid proto used. This plugin only supports 'proto3' syntax";
-        return false;
-    }
-
-    for (int i = 0; i < file->message_type_count(); i++) {
-        const Descriptor *message = file->message_type(i);
-
-        //Detect nested fields and filter maps fields
-        int mapsFieldsCount = 0;
-        for (int j = 0; j < message->nested_type_count(); j++) {
-            for (int k = 0; k < message->field_count(); k++) {
-                if (message->field(k)->is_map() && message->field(k)->message_type() == message->nested_type(j)) {
-                    ++mapsFieldsCount;
-                }
-            }
-        }
-
-        if (message->nested_type_count() > 0 && message->nested_type_count() > mapsFieldsCount) {
-            std::cerr << file->name() << ":" << (message->index() + 1) << ": " << " Error: Meta object features not supported for nested classes in " << message->full_name() << std::endl;
-            continue;
-        }
-
-        std::string baseFilename(message->name());
-        utils::tolower(baseFilename);
-        baseFilename = generateBaseName(file, baseFilename);
-
-        std::string filename = baseFilename + ".h";
-        ProtobufClassGenerator classGen(message,
-                                        std::shared_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(filename)));
-        classGen.run();
-
-        filename = baseFilename + ".cpp";
-        ProtobufSourceGenerator classSourceGen(message,
-                                               std::shared_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(filename)));
-        classSourceGen.run();
-    }
-
-    for (int i = 0; i < file->service_count(); i++) {
-        const ServiceDescriptor *service = file->service(i);
-        std::string baseFilename(service->name());
-        utils::tolower(baseFilename);
-        baseFilename = generateBaseName(file, baseFilename);
-
-        std::string fullFilename = baseFilename + "server.h";
-        ServerGenerator serverGen(service,
-                                  std::shared_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(fullFilename)));
-        serverGen.run();
-
-        fullFilename = baseFilename + "client.h";
-        ClientGenerator clientGen(service,
-                                  std::shared_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(fullFilename)));
-        clientGen.run();
-
-        fullFilename = baseFilename + "client.cpp";
-        ClientSourceGenerator clientSrcGen(service,
-                                           std::shared_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(fullFilename)));
-        clientSrcGen.run();
-    }
-    return true;
-}
-
-bool QtGenerator::GenerateAll(const std::vector<const FileDescriptor *> &files, const string &parameter, GeneratorContext *generatorContext, string *error) const
-{
-    std::string globalEnumsFilename = "globalenums";
-
-    std::shared_ptr<io::ZeroCopyOutputStream> outHeader(generatorContext->Open(globalEnumsFilename + ".h"));
-    std::shared_ptr<io::ZeroCopyOutputStream> outSource(generatorContext->Open(globalEnumsFilename + ".cpp"));
-    std::shared_ptr<::google::protobuf::io::Printer> outHeaderPrinter(new ::google::protobuf::io::Printer(outHeader.get(), '$'));
-    std::shared_ptr<::google::protobuf::io::Printer> outSourcePrinter(new ::google::protobuf::io::Printer(outSource.get(), '$'));
-
-    PackagesList packageList;
-    for (auto file : files) {
-        packageList[file->package()].push_back(file);
-    }
-
-    outHeaderPrinter->Print(Templates::DisclaimerTemplate);
-    outHeaderPrinter->Print(Templates::PreambleTemplate);
-    outHeaderPrinter->Print(Templates::DefaultProtobufIncludesTemplate);
-
-    outSourcePrinter->Print(Templates::DisclaimerTemplate);
-    outSourcePrinter->Print({{"include", globalEnumsFilename}}, Templates::InternalIncludeTemplate);
-    if (GeneratorOptions::instance().hasQml()) {
-        outSourcePrinter->Print({{"include", "QQmlEngine"}}, Templates::ExternalIncludeTemplate);
-    }
-
-    for (auto file : files) { //TODO: Each should be printed to separate file
-        for(int i = 0; i < file->enum_type_count(); i++) {
-            auto enumType = file->enum_type(i);
-            EnumsGenerator enumGen2(enumType,
-                                    outHeaderPrinter);
-            enumGen2.run();
-        }
-    }
-
-    for (auto file : files) { //TODO: Each should be printed to separate file
-        for(int i = 0; i < file->enum_type_count(); i++) {
-            auto enumType = file->enum_type(i);
-            EnumsSourceGenerator enumSourceGen2(enumType,
-                                    outSourcePrinter);
-            enumSourceGen2.run();
-        }
-    }
-
-    return GeneratorBase::GenerateAll(files, parameter, generatorContext, error);
-}
-

+ 0 - 141
src/generator/generator.h

@@ -1,141 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
- *
- * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this
- * software and associated documentation files (the "Software"), to deal in the Software
- * without restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
- * to permit persons to whom the Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies
- * or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
- * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#pragma once
-
-#include <google/protobuf/compiler/code_generator.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#include <string>
-#include <memory>
-
-#include "generatorbase.h"
-
-namespace google { namespace protobuf {
-class FileDescriptor;
-namespace compiler {
-class GeneratorContext;
-}}}
-
-namespace QtProtobuf {
-namespace generator {
-/*!
- * \defgroup generator
- *
- * \brief QtProtobuf code generator for protobuf messages and grpc services
- *
- * \details QtProtobuf code generator is program to be used in conjunction with proto compiler aka protoc.
- *
- * It might be used in few ways:
- *  - manualy
- *  - \ref cmake "CMake macro"
- *  - \ref qmake "qmake macro"
- *
- * \section Manual usage
- *
- * \code
- * [QT_PROTOBUF_OPTIONS="[SINGLE|MULTI]:QML:COMMENTS:FOLDER"] protoc --plugin=protoc-gen-qtprotobuf=<path/to/bin/>qtprotobufgen --qtprotobuf_out=<output_dir> [-I/extra/proto/include/path] <protofile>.proto
- * \endcode
- *
- * Generator supports options that could be provided as environment variable to tune generation.
- * Following options are supported:
- *
- * *SINGLE* - enables single-file generation when for each *.proto* file single pair of *.h* *.cpp* files is generated
- *
- * \note Enabled by default. Excluded by SINGLE
- *
- * *MULTI* - enables multi-file generation when for each message separate pair of *.h* *.cpp*
- *
- * \note Has higher priority than SINGLE
- *
- * *QML* - enables QML code generation in protobuf classes. If is set QML-related code for lists and QML registration to be generated.
- *
- * *COMMENTS* - enables comments copying from .proto files
- *
- * *FOLDER* - enables folder-based generation
- *
- * \section cmake CMake
- *
- * For CMake based project QtProtobuf has macroses those should be used to generate code and in link it to your project:
- *
- * - \ref cmake_qtprotobuf_generate
- * - \ref cmake_qtprotobuf_link_target
- *
- *
- * \subsection cmake_qtprotobuf_generate qtprotobuf_generate
- *
- * \brief qtprotobuf_generate is cmake helper function that automatically generates STATIC library target from your .proto files
- *
- * \param TARGET name of you target that generated code archive will be linked to
- * \param GENERATED_TARGET name that will be used for generated archive library target. It's usefull when you supposed to have multiple generated targets to be linked to single one.
- * \param OUT_DIR output directory that will contain generated artifacts. Usually subfolder in build directory should be used
- * \param GENERATED_HEADERS List of header files expected after generator job finished
- * \param EXCLUDE_HEADERS List of header files to be excluded from pre-parsed list of expected header files (e.g. nested messages that are not supported by QtProtobuf generator)
- * \param PROTO_FILES List of .proto files that will be used in generation procedure
- * \param MULTI Enables multi-files generation mode. If provided in parameter list generator will create pair of header/source files for each message
- *        \note multi-files generation mode is defined as deprecated by QtProtobuf team, and might have poor support in future
- * \param QML Enables QML code generation in protobuf classes. If provided in parameter list QML related code for lists and QML registration to be generated.
- * \param COMMENTS Enables comments copying from .proto files. If provided in parameter list message and field related comments will be copied to generated header files.
- * \param FOLDER Enables folder based generation. If provided in parameter list generator will place generated artifacts to folder structure according to package of corresponding .proto file
- *
- * \subsection cmake_qtprotobuf_link_target qtprotobuf_link_target
- *
- * \brief qtprotobuf_link_target is cmake helper function that links generated protobuf target to your binary
- *
- * \details It's useful when you try to link generated target to shared library or/and to executable that doesn't utilize all protobuf generated classes directly from C++ code, but requires them from QML.
- *
- * \param TARGET name of target to link to
- * \param GENERATED_TARGET protobuf generated target name
- *
- * \section qmake
- *  - \ref qmake_qtprotobuf_generate
- *
- * \subsection qmake_qtprotobuf_generate qtprotobuf_generate
- *
- * \brief qtprotobuf_generate is qmake helper <a href="https://doc.qt.io/qt-5/qmake-language.html#test-functions">test function</a> that generates QtProtobuf source code based on files provided by PROTO_FILES global context variable
- * \param generate_qml generate_qml enables/disables QML code generation in protobuf classes. If set to `true` QML-related code for lists and QML registration to be generated.
- */
-
-/*!
- * \ingroup generator
- * \private
- * \brief The QtGenerator class
- */
-class QtGenerator : public GeneratorBase
-{
-public:
-    QtGenerator();
-    bool Generate(const ::google::protobuf::FileDescriptor *file,
-                          const std::string &parameter,
-                          ::google::protobuf::compiler::GeneratorContext *generatorContext,
-                          std::string *error) const override;
-
-    bool GenerateAll(const std::vector<const ::google::protobuf::FileDescriptor *> &files,
-                             const std::string &parameter,
-                             ::google::protobuf::compiler::GeneratorContext *generatorContext,
-                             std::string *error) const override;
-};
-
-} //namespace generator
-} // namespace QtProtobuf

+ 89 - 0
src/generator/generatorbase.cpp

@@ -34,6 +34,7 @@
 #include "utils.h"
 #include "templates.h"
 #include "generatoroptions.h"
+#include "generatorcommon.h"
 
 using namespace ::QtProtobuf::generator;
 using namespace ::google::protobuf;
@@ -86,3 +87,91 @@ std::string GeneratorBase::generateBaseName(const ::google::protobuf::FileDescri
 
     return outFileBasename;
 }
+
+
+void GeneratorBase::printDisclaimer(const std::shared_ptr<::google::protobuf::io::Printer> printer)
+{
+    printer->Print(Templates::DisclaimerTemplate);
+}
+
+void GeneratorBase::printPreamble(const std::shared_ptr<::google::protobuf::io::Printer> printer)
+{
+    printer->Print(Templates::PreambleTemplate);
+}
+
+void GeneratorBase::printInclude(const std::shared_ptr<::google::protobuf::io::Printer> printer, const google::protobuf::Descriptor *message, const FieldDescriptor *field, std::set<std::string> &existingIncludes)
+{
+    assert(field != nullptr);
+    std::string newInclude;
+    const char *includeTemplate;
+    switch (field->type()) {
+    case FieldDescriptor::TYPE_MESSAGE:
+        if (field->is_map()) {
+            newInclude = "QMap";
+            assert(field->message_type() != nullptr);
+            assert(field->message_type()->field_count() == 2);
+            printInclude(printer, message, field->message_type()->field(0), existingIncludes);
+            printInclude(printer, message, field->message_type()->field(1), existingIncludes);
+            includeTemplate = Templates::ExternalIncludeTemplate;
+        } else {
+            std::string outFileBasename = "";
+            std::string fieldPackage = field->message_type()->file()->package();
+            if (fieldPackage != message->file()->package()) {
+                std::vector<std::string> packages = utils::split(fieldPackage, '.');
+                for (auto package : packages) {
+                    outFileBasename += package + "/";
+                }
+            }
+
+            std::string typeName = field->message_type()->name();
+            utils::tolower(typeName);
+            newInclude = outFileBasename + typeName;
+            includeTemplate = Templates::InternalIncludeTemplate;
+        }
+        break;
+    case FieldDescriptor::TYPE_BYTES:
+        newInclude = "QByteArray";
+        includeTemplate = Templates::ExternalIncludeTemplate;
+        break;
+    case FieldDescriptor::TYPE_STRING:
+        newInclude = "QString";
+        includeTemplate = Templates::ExternalIncludeTemplate;
+        break;
+    case FieldDescriptor::TYPE_ENUM: {
+        common::EnumVisibility enumVisibily = common::enumVisibility(field->enum_type(), message);
+        if (enumVisibily == common::GLOBAL_ENUM) {
+            includeTemplate = Templates::GlobalEnumIncludeTemplate;
+        } else if (enumVisibily == common::NEIGHBOR_ENUM) {
+            includeTemplate = Templates::InternalIncludeTemplate;
+            std::string fullEnumName = field->enum_type()->full_name();
+            std::vector<std::string> fullEnumNameParts = utils::split(fullEnumName, '.');
+            std::string enumTypeOwner = fullEnumNameParts.at(fullEnumNameParts.size() - 2);
+            utils::tolower(enumTypeOwner);
+            newInclude = enumTypeOwner;
+        } else {
+            return;
+        }
+    }
+        break;
+    default:
+        return;
+    }
+
+    if (existingIncludes.find(newInclude) == std::end(existingIncludes)) {
+        printer->Print({{"include", newInclude}}, includeTemplate);
+        existingIncludes.insert(newInclude);
+    }
+}
+
+void GeneratorBase::printQtProtobufUsingNamespace(const std::shared_ptr<::google::protobuf::io::Printer> printer)
+{
+    printer->Print({{"namespace", "QtProtobuf"}}, Templates::UsingNamespaceTemplate);
+}
+
+void GeneratorBase::printNamespaces(const std::shared_ptr<::google::protobuf::io::Printer> printer, const std::vector<std::string> namespaces) {
+    printer->Print("\n");
+    for (auto ns : namespaces) {
+        printer->Print({{"namespace", ns}}, Templates::NamespaceTemplate);
+    }
+}
+

+ 82 - 0
src/generator/generatorbase.h

@@ -42,6 +42,83 @@ class GeneratorContext;
 namespace QtProtobuf {
 namespace generator {
 
+/*!
+ * \defgroup generator
+ *
+ * \brief QtProtobuf code generator for protobuf messages and grpc services
+ *
+ * \details QtProtobuf code generator is program to be used in conjunction with proto compiler aka protoc.
+ *
+ * It might be used in few ways:
+ *  - manualy
+ *  - \ref cmake "CMake macro"
+ *  - \ref qmake "qmake macro"
+ *
+ * \section Manual usage
+ *
+ * \code
+ * [QT_PROTOBUF_OPTIONS="[SINGLE|MULTI]:QML:COMMENTS:FOLDER"] protoc --plugin=protoc-gen-qtprotobuf=<path/to/bin/>qtprotobufgen --qtprotobuf_out=<output_dir> [-I/extra/proto/include/path] <protofile>.proto
+ * \endcode
+ *
+ * Generator supports options that could be provided as environment variable to tune generation.
+ * Following options are supported:
+ *
+ * *SINGLE* - enables single-file generation when for each *.proto* file single pair of *.h* *.cpp* files is generated
+ *
+ * \note Enabled by default. Excluded by SINGLE
+ *
+ * *MULTI* - enables multi-file generation when for each message separate pair of *.h* *.cpp*
+ *
+ * \note Has higher priority than SINGLE
+ *
+ * *QML* - enables QML code generation in protobuf classes. If is set QML-related code for lists and QML registration to be generated.
+ *
+ * *COMMENTS* - enables comments copying from .proto files
+ *
+ * *FOLDER* - enables folder-based generation
+ *
+ * \section cmake CMake
+ *
+ * For CMake based project QtProtobuf has macroses those should be used to generate code and in link it to your project:
+ *
+ * - \ref cmake_qtprotobuf_generate
+ * - \ref cmake_qtprotobuf_link_target
+ *
+ *
+ * \subsection cmake_qtprotobuf_generate qtprotobuf_generate
+ *
+ * \brief qtprotobuf_generate is cmake helper function that automatically generates STATIC library target from your .proto files
+ *
+ * \param TARGET name of you target that generated code archive will be linked to
+ * \param GENERATED_TARGET name that will be used for generated archive library target. It's usefull when you supposed to have multiple generated targets to be linked to single one.
+ * \param OUT_DIR output directory that will contain generated artifacts. Usually subfolder in build directory should be used
+ * \param GENERATED_HEADERS List of header files expected after generator job finished
+ * \param EXCLUDE_HEADERS List of header files to be excluded from pre-parsed list of expected header files (e.g. nested messages that are not supported by QtProtobuf generator)
+ * \param PROTO_FILES List of .proto files that will be used in generation procedure
+ * \param MULTI Enables multi-files generation mode. If provided in parameter list generator will create pair of header/source files for each message
+ *        \note multi-files generation mode is defined as deprecated by QtProtobuf team, and might have poor support in future
+ * \param QML Enables QML code generation in protobuf classes. If provided in parameter list QML related code for lists and QML registration to be generated.
+ * \param COMMENTS Enables comments copying from .proto files. If provided in parameter list message and field related comments will be copied to generated header files.
+ * \param FOLDER Enables folder based generation. If provided in parameter list generator will place generated artifacts to folder structure according to package of corresponding .proto file
+ *
+ * \subsection cmake_qtprotobuf_link_target qtprotobuf_link_target
+ *
+ * \brief qtprotobuf_link_target is cmake helper function that links generated protobuf target to your binary
+ *
+ * \details It's useful when you try to link generated target to shared library or/and to executable that doesn't utilize all protobuf generated classes directly from C++ code, but requires them from QML.
+ *
+ * \param TARGET name of target to link to
+ * \param GENERATED_TARGET protobuf generated target name
+ *
+ * \section qmake
+ *  - \ref qmake_qtprotobuf_generate
+ *
+ * \subsection qmake_qtprotobuf_generate qtprotobuf_generate
+ *
+ * \brief qtprotobuf_generate is qmake helper <a href="https://doc.qt.io/qt-5/qmake-language.html#test-functions">test function</a> that generates QtProtobuf source code based on files provided by PROTO_FILES global context variable
+ * \param generate_qml generate_qml enables/disables QML code generation in protobuf classes. If set to `true` QML-related code for lists and QML registration to be generated.
+ */
+
 /*!
  * \ingroup generator
  * \private
@@ -63,6 +140,11 @@ public:
                              std::string *error) const override;
     bool HasGenerateAll() const override { return true; }
 
+    static void printDisclaimer(const std::shared_ptr<::google::protobuf::io::Printer> printer);
+    static void printPreamble(const std::shared_ptr<::google::protobuf::io::Printer> printer);
+    static void printInclude(const std::shared_ptr<::google::protobuf::io::Printer> printer, const google::protobuf::Descriptor *message, const google::protobuf::FieldDescriptor *field, std::set<std::string> &existingIncludes);
+    static void printQtProtobufUsingNamespace(const std::shared_ptr<::google::protobuf::io::Printer> printer);
+    static void printNamespaces(const std::shared_ptr<::google::protobuf::io::Printer> printer, const std::vector<std::string> namespaces);
 protected:
     void iterateNonNestedFileds(const ::google::protobuf::FileDescriptor *file, std::function<void(const ::google::protobuf::Descriptor *)> callback) const;
     static std::string generateBaseName(const ::google::protobuf::FileDescriptor *file, std::string name);

+ 30 - 6
src/generator/generatorcommon.cpp

@@ -35,7 +35,7 @@ using namespace ::google::protobuf;
 std::string common::getNamespacesString(const std::vector<std::string> &namespacesList, const std::string &separator)
 {
     std::string namespaces;
-    for(auto namespacePart : namespacesList) {
+    for (auto namespacePart : namespacesList) {
         namespaces += namespacePart + separator;
     }
 
@@ -96,15 +96,19 @@ TypeMap common::produceEnumTypeMap(const EnumDescriptor *type, const Descriptor
 {
     EnumVisibility visibility = enumVisibility(type, scope);
     std::vector<std::string> namespaceList = getNamespaces(type);
+
+    std::string name = utils::upperCaseName(type->name());
+    std::string qmlPackage = getNamespacesString(namespaceList, ".");//qml package should consist only from proto spackage
+    std::string enumGadget = scope != nullptr ? utils::upperCaseName(scope->name()) : "";//Not used
     if(visibility == GLOBAL_ENUM) {
-        namespaceList.push_back(type->name() + Templates::EnumClassSuffix);//Global enums are stored in helper Gadget
+        enumGadget = name + Templates::EnumClassSuffix;
+        namespaceList.push_back(enumGadget);//Global enums are stored in helper Gadget
     }
 
     std::string namespaces = getNamespacesString(namespaceList, "::");
     std::string scopeNamespaces = getScopeNamespacesString(namespaces, getNamespacesString(getNamespaces(scope), "::"));
-    std::string qmlPackage = getNamespacesString(namespaceList, ".");
 
-    std::string name = type->name();
+
     std::string fullName = namespaces.empty() ? name : (namespaces + "::" + name);
     std::string scopeName = scopeNamespaces.empty() ? name : (scopeNamespaces + "::" + name);
 
@@ -131,7 +135,8 @@ TypeMap common::produceEnumTypeMap(const EnumDescriptor *type, const Descriptor
         {"property_type", propertyType},
         {"property_list_type", fullListName},
         {"getter_type", scopeName},
-        {"setter_type", scopeName}
+        {"setter_type", scopeName},
+        {"enum_gadget", enumGadget}
     };
 }
 
@@ -222,7 +227,7 @@ TypeMap common::produceTypeMap(const FieldDescriptor *field, const Descriptor *s
     std::string namespaceTypeName;
     std::vector<std::string> typeNamespace;
 
-    switch(field->type()) {
+    switch (field->type()) {
     case FieldDescriptor::TYPE_MESSAGE:
         typeMap = produceMessageTypeMap(field->message_type(), scope);
         break;
@@ -335,3 +340,22 @@ bool common::hasQmlAlias(const ::google::protobuf::FieldDescriptor *field)
                 || field->type() == FieldDescriptor::TYPE_FIXED32)
             && GeneratorOptions::instance().hasQml();
 }
+
+MethodMap common::produceMethodMap(const MethodDescriptor *method, const std::string& scope)
+{
+    std::string inputTypeName = method->input_type()->full_name();
+    std::string outputTypeName = method->output_type()->full_name();
+    std::string methodName = method->name();
+    std::string methodNameUpper = method->name();
+    methodNameUpper[0] =  static_cast<char>(::toupper(methodNameUpper[0]));
+    utils::replace(inputTypeName, ".", "::");
+    utils::replace(outputTypeName, ".", "::");
+    return {{"classname", scope},
+                  {"return_type", outputTypeName},
+                  {"method_name", methodName},
+                  {"method_name_upper", methodNameUpper},
+                  {"param_type", inputTypeName},
+                  {"param_name", "arg"},
+                  {"return_name", "ret"}
+                 };
+}

+ 14 - 0
src/generator/generatorcommon.h

@@ -28,6 +28,7 @@
 #include <vector>
 #include <map>
 #include <string>
+#include <functional>
 
 #include "utils.h"
 
@@ -38,6 +39,8 @@ namespace generator {
 
 using TypeMap = std::map<std::string, std::string>;
 using PropertyMap = std::map<std::string, std::string>;
+using MethodMap = std::map<std::string, std::string>;
+
 struct common {
     enum EnumVisibility {
         GLOBAL_ENUM,
@@ -69,6 +72,17 @@ struct common {
     static bool isLocalEnum(const ::google::protobuf::EnumDescriptor *type, const google::protobuf::Descriptor *scope);
     static EnumVisibility enumVisibility(const ::google::protobuf::EnumDescriptor *type, const ::google::protobuf::Descriptor *scope);
     static bool hasQmlAlias(const ::google::protobuf::FieldDescriptor *field);
+
+    using InterateMessageLogic = std::function<void(const ::google::protobuf::FieldDescriptor *, PropertyMap &)>;
+    static void iterateMessageFields(const ::google::protobuf::Descriptor *message, InterateMessageLogic callback) {
+        for (int i = 0; i < message->field_count(); i++) {
+            const ::google::protobuf::FieldDescriptor *field = message->field(i);
+            auto propertyMap = common::producePropertyMap(field, message);
+            callback(field, propertyMap);
+        }
+    }
+
+    static MethodMap produceMethodMap(const ::google::protobuf::MethodDescriptor *method, const std::string &scope); //TODO: scope should be ServiceDescriptor
 };
 
 }

+ 0 - 111
src/generator/globalenumsgenerator.cpp

@@ -1,111 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
- *
- * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this
- * software and associated documentation files (the "Software"), to deal in the Software
- * without restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
- * to permit persons to whom the Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies
- * or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
- * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include "globalenumsgenerator.h"
-
-#include <google/protobuf/io/zero_copy_stream.h>
-
-using namespace ::QtProtobuf::generator;
-using namespace ::google::protobuf;
-using namespace ::google::protobuf::io;
-using namespace ::google::protobuf::compiler;
-
-GlobalEnumsGenerator::GlobalEnumsGenerator(const PackagesList &packageList, const std::shared_ptr<io::ZeroCopyOutputStream> &out) :
-    ClassGeneratorBase(Templates::GlobalEnumClassNameTemplate, out)
-  , mPackageList(packageList) {}
-
-
-GlobalEnumsGenerator::GlobalEnumsGenerator(const PackagesList &packageList, const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
-    ClassGeneratorBase(Templates::GlobalEnumClassNameTemplate, printer)
-  , mPackageList(packageList) {}
-
-void GlobalEnumsGenerator::startEnum(const std::vector<std::string>& namespaces) {
-    printNamespaces(namespaces);
-    printEnumClass();
-    printPublic();
-    Indent();
-    mPrinter->Print({{"classname", mClassName}}, Templates::ManualRegistrationDeclaration);
-    Outdent();
-    printPrivate();
-    printConstructor();
-}
-
-void GlobalEnumsGenerator::printConstructor()
-{
-    Indent();
-    mPrinter->Print({{"classname", mClassName}}, Templates::ConstructorHeaderTemplate);
-    mPrinter->Print({{"classname", mClassName}}, Templates::DeletedCopyConstructorTemplate);
-    mPrinter->Print({{"classname", mClassName}}, Templates::DeletedMoveConstructorTemplate);
-    Outdent();
-}
-
-void GlobalEnumsGenerator::run() {
-    std::vector<std::string> namespaces;
-    for (auto package : mPackageList) {
-        if (!hasGlobalEnum(package.second)) {
-            continue;
-        }
-        utils::split(package.first, namespaces, '.');
-        startEnum(namespaces);
-        for (auto file : package.second) {
-            run(file);
-        }
-        encloseEnum(namespaces);
-        for (auto file : package.second) {
-            printMetatype(file, namespaces);
-        }
-    }
-}
-
-void GlobalEnumsGenerator::run(const FileDescriptor *file) {
-    printQEnums(file);
-}
-
-void GlobalEnumsGenerator::printMetatype(const google::protobuf::FileDescriptor *file,
-                                         const std::vector<std::string>& namespaces) {
-    std::string fullNamespace;
-    for (auto name : namespaces) {
-        if (fullNamespace.empty()) {
-            fullNamespace.append(name);
-            continue;
-        }
-        fullNamespace.append("::").append(name);
-    }
-    fullNamespace.append("::").append(Templates::GlobalEnumClassNameTemplate);
-    for (int i = 0; i < file->enum_type_count(); i++) {
-        const auto enumDescr = file->enum_type(i);
-        mPrinter->Print({{"classname", enumDescr->name()}, {"namespaces", fullNamespace}},
-                       Templates::DeclareMetaTypeListTemplate);
-    }
-}
-
-void GlobalEnumsGenerator::encloseEnum(const std::vector<std::string>& namespaces) {
-    encloseClass();
-    encloseNamespaces(static_cast<int>(namespaces.size()));
-}
-
-void GlobalEnumsGenerator::printEnumClass() {
-    mPrinter->Print({{"classname", mClassName}}, Templates::NonProtoClassDefinitionTemplate);
-}

+ 0 - 60
src/generator/globalenumsgenerator.h

@@ -1,60 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
- *
- * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this
- * software and associated documentation files (the "Software"), to deal in the Software
- * without restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
- * to permit persons to whom the Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies
- * or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
- * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#pragma once
-
-#include "classgeneratorbase.h"
-#include "utils.h"
-
-namespace QtProtobuf {
-namespace generator {
-
-/*!
- * \ingroup generator
- * \private
- * \brief The GlobalEnumsGenerator class
- */
-class GlobalEnumsGenerator : public ClassGeneratorBase
-{
-    PackagesList mPackageList;
-public:
-    GlobalEnumsGenerator(const PackagesList &packageList, const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out);
-    GlobalEnumsGenerator(const PackagesList &packageList, const std::shared_ptr<::google::protobuf::io::Printer> &printer);
-    virtual ~GlobalEnumsGenerator() = default;
-
-    void run();
-
-    void startEnum(const std::vector<std::string>& namespaces);
-    void run(const ::google::protobuf::FileDescriptor *file);
-    void encloseEnum(const std::vector<std::string>& namespaces);
-    void printMetatype(const google::protobuf::FileDescriptor *file,
-                       const std::vector<std::string>& namespaces);
-    void printEnumClass();
-    void printConstructor();
-};
-
-} //namespace generator
-} //namespace QtProtobuf
-

+ 0 - 108
src/generator/globalenumssourcegenerator.cpp

@@ -1,108 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) Tatyana Borisova <tanusshhka@mail.ru>
- *
- * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this
- * software and associated documentation files (the "Software"), to deal in the Software
- * without restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
- * to permit persons to whom the Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies
- * or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
- * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include "globalenumssourcegenerator.h"
-
-#include "generatoroptions.h"
-
-#include <google/protobuf/io/zero_copy_stream.h>
-
-using namespace ::QtProtobuf::generator;
-using namespace ::google::protobuf;
-using namespace ::google::protobuf::io;
-using namespace ::google::protobuf::compiler;
-
-GlobalEnumsSourceGenerator::GlobalEnumsSourceGenerator(const PackagesList &packageList, const std::shared_ptr<io::ZeroCopyOutputStream> &out) :
-    ClassGeneratorBase(Templates::GlobalEnumClassNameTemplate, out)
-  , mPackageList(packageList) {}
-
-
-GlobalEnumsSourceGenerator::GlobalEnumsSourceGenerator(const PackagesList &packageList, const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
-    ClassGeneratorBase(Templates::GlobalEnumClassNameTemplate, printer)
-  , mPackageList(packageList) {}
-
-
-void  GlobalEnumsSourceGenerator::printHeaders() {
-    mPrinter->Print("#include \"globalenums.h\"\n\n"
-                    "#include <QProtobufObject>\n\n");
-    if (GeneratorOptions::instance().hasQml()) {
-        mPrinter->Print("#include <QQmlEngine>");
-    }
-}
-
-void GlobalEnumsSourceGenerator::run() {
-    std::vector<std::string> namespaces;
-    for (auto package : mPackageList) {
-        if (!hasGlobalEnum(package.second)) {
-            continue;
-        }
-        utils::split(package.first, namespaces, '.');
-
-        printNamespaces(namespaces);
-        printRegisterBody(package.second, namespaces);
-        encloseNamespaces(static_cast<int>(namespaces.size()));
-    }
-}
-
-void GlobalEnumsSourceGenerator::printRegisterBody(const std::list<const FileDescriptor *> &list,
-                                                   const std::vector<std::string> &namespaces)
-{
-    assert(!list.empty());
-
-    std::string fullNamespace;
-    for (auto name : namespaces) {
-        if (fullNamespace.empty()) {
-            fullNamespace.append(name);
-            continue;
-        }
-        fullNamespace.append("::").append(name);
-    }
-
-    const std::map<std::string, std::string> registrationProperties = {{"classname", mClassName},
-                                                                       {"type", mClassName},
-                                                                       {"namespaces", fullNamespace},
-                                                                       {"package", list.front()->package()}};
-
-    mPrinter->Print(registrationProperties, Templates::ManualRegistrationGlobalEnumDefinition);
-    Indent();
-    if (GeneratorOptions::instance().hasQml()) {
-        mPrinter->Print(registrationProperties, Templates::QmlRegisterTypeUncreatableTemplate);
-    }
-
-    for (auto file : list) {
-        for (int i = 0; i < file->enum_type_count(); i++) {
-            const auto enumDescr = file->enum_type(i);
-            const std::map<std::string, std::string> properties = {{"classname", mClassName},
-                                                                   {"type", mClassName + "::" + enumDescr->name()},
-                                                                   {"enum", enumDescr->name() + Templates::ListSuffix},
-                                                                   {"namespaces", fullNamespace}};
-            mPrinter->Print(properties, Templates::ComplexGlobalEnumFieldRegistrationTemplate);
-            mPrinter->Print(properties, Templates::RegisterMetaTypeTemplate);
-            mPrinter->Print(properties, Templates::RegisterEnumSerializersTemplate);
-        }
-    }
-    Outdent();
-    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
-}

+ 0 - 54
src/generator/globalenumssourcegenerator.h

@@ -1,54 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 Tatyana Borisova <tanusshhka@mail.ru>
- *
- * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this
- * software and associated documentation files (the "Software"), to deal in the Software
- * without restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
- * to permit persons to whom the Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies
- * or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
- * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#pragma once
-
-#include "classgeneratorbase.h"
-#include "utils.h"
-
-namespace QtProtobuf {
-namespace generator {
-/*!
- * \ingroup generator
- * \private
- * \brief The GlobalEnumsSourceGenerator class
- */
-class GlobalEnumsSourceGenerator : public ClassGeneratorBase
-{
-    PackagesList mPackageList;
-public:
-    GlobalEnumsSourceGenerator(const PackagesList &packageList, const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out);
-    GlobalEnumsSourceGenerator(const PackagesList &packageList, const std::shared_ptr<::google::protobuf::io::Printer> &printer);
-    virtual ~GlobalEnumsSourceGenerator() = default;
-
-    void run() override;
-    void printHeaders();
-    void printRegisterBody(const std::list<const ::google::protobuf::FileDescriptor *> &list,
-                           const std::vector<std::string> &namespaces);
-};
-
-} //namespace generator
-} //namespace QtProtobuf
-

+ 2 - 2
src/generator/main.cpp

@@ -25,7 +25,7 @@
 
 #include <google/protobuf/compiler/plugin.h>
 
-#include "generator.h"
+#include "multifilegenerator.h"
 #include "singlefilegenerator.h"
 #include "generatoroptions.h"
 #include "utils.h"
@@ -57,7 +57,7 @@ int main(int argc, char *argv[])
         GeneratorOptions::instance().parseFromEnv(optionsPtr);
     }
     if (GeneratorOptions::instance().isMulti()) {
-        QtProtobuf::generator::QtGenerator generator;
+        QtProtobuf::generator::MultiFileGenerator generator;
         return ::google::protobuf::compiler::PluginMain(argc, argv, &generator);
     }
     QtProtobuf::generator::SingleFileGenerator generator;

+ 102 - 133
src/generator/protobufclassgenerator.cpp → src/generator/messagedeclarationprinter.cpp

@@ -1,7 +1,7 @@
 /*
  * MIT License
  *
- * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
+ * Copyright (c) 2020 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
  *
  * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
  *
@@ -23,14 +23,13 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "protobufclassgenerator.h"
+#include "messagedeclarationprinter.h"
 #include "utils.h"
 #include "generatoroptions.h"
 #include "generatorcommon.h"
 
 #include <iostream>
 #include <google/protobuf/descriptor.h>
-#include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/descriptor.pb.h>
 
 using namespace ::QtProtobuf::generator;
@@ -38,77 +37,53 @@ using namespace ::google::protobuf;
 using namespace ::google::protobuf::io;
 using namespace ::google::protobuf::compiler;
 
-ProtobufClassGenerator::ProtobufClassGenerator(const Descriptor *message, const std::shared_ptr<::google::protobuf::io::ZeroCopyOutputStream> &out)
-    : ClassGeneratorBase(message->full_name(), out)
-    , mMessage(message)
-    , mTypeMap(common::produceMessageTypeMap(message, nullptr))
+MessageDeclarationPrinter::MessageDeclarationPrinter(const Descriptor *message, const std::shared_ptr<::google::protobuf::io::Printer> &printer)
+    : DescriptorPrinterBase<google::protobuf::Descriptor>(message, printer)
 {
+    mTypeMap = common::produceMessageTypeMap(message, nullptr);
 }
 
-ProtobufClassGenerator::ProtobufClassGenerator(const ::google::protobuf::Descriptor *message, const std::shared_ptr<::google::protobuf::io::Printer> &printer)
-    : ClassGeneratorBase(message->full_name(), printer)
-    , mMessage(message)
-    , mTypeMap(common::produceMessageTypeMap(message, nullptr))
+void MessageDeclarationPrinter::printCopyFunctionality()
 {
-
-}
-
-void ProtobufClassGenerator::printCopyFunctionality()
-{
-    assert(mMessage != nullptr);
-    mPrinter->Print({{"classname", mClassName}},
+    assert(mDescriptor != nullptr);
+    mPrinter->Print({{"classname", mName}},
                     Templates::CopyConstructorDeclarationTemplate);
 
-    mPrinter->Print({{"classname", mClassName}},
+    mPrinter->Print({{"classname", mName}},
                     Templates::AssignmentOperatorDeclarationTemplate);
 }
 
-void ProtobufClassGenerator::printMoveSemantic()
+void MessageDeclarationPrinter::printMoveSemantic()
 {
-    assert(mMessage != nullptr);
-    mPrinter->Print({{"classname", mClassName}},
+    assert(mDescriptor != nullptr);
+    mPrinter->Print({{"classname", mName}},
                     Templates::MoveConstructorDeclarationTemplate);
 
-    mPrinter->Print({{"classname", mClassName}},
+    mPrinter->Print({{"classname", mName}},
                     Templates::MoveAssignmentOperatorDeclarationTemplate);
 }
 
-void ProtobufClassGenerator::printComparisonOperators()
+void MessageDeclarationPrinter::printComparisonOperators()
 {
-    assert(mMessage != nullptr);
-    mPrinter->Print({{"classname", mClassName}}, Templates::EqualOperatorDeclarationTemplate);
+    assert(mDescriptor != nullptr);
+    mPrinter->Print({{"classname", mName}}, Templates::EqualOperatorDeclarationTemplate);
 
-    mPrinter->Print({{"classname", mClassName}}, Templates::NotEqualOperatorDeclarationTemplate);
+    mPrinter->Print({{"classname", mName}}, Templates::NotEqualOperatorDeclarationTemplate);
 }
 
-void ProtobufClassGenerator::printIncludes()
+void MessageDeclarationPrinter::printConstructors()
 {
-    assert(mMessage != nullptr);
-
-    mPrinter->Print(Templates::DefaultProtobufIncludesTemplate);
-    if (GeneratorOptions::instance().hasQml()) {
-        mPrinter->Print(Templates::QmlProtobufIncludesTemplate);
-    }
-
-    std::set<std::string> existingIncludes;
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        printInclude(mMessage, mMessage->field(i), existingIncludes);
-    }
-}
-
-void ProtobufClassGenerator::printConstructors()
-{
-    for (int i = 0; i <= mMessage->field_count(); i++) {
+    for (int i = 0; i <= mDescriptor->field_count(); i++) {
         printConstructor(i);
     }
 }
 
-void ProtobufClassGenerator::printConstructor(int fieldCount)
+void MessageDeclarationPrinter::printConstructor(int fieldCount)
 {
     std::vector<std::string> parameterList;
-    mPrinter->Print({{"classname", mClassName}}, Templates::ProtoConstructorBeginTemplate);
+    mPrinter->Print({{"classname", mName}}, Templates::ProtoConstructorBeginTemplate);
     for (int i = 0; i < fieldCount; i++) {
-        const FieldDescriptor *field = mMessage->field(i);
+        const FieldDescriptor *field = mDescriptor->field(i);
         const char *parameterTemplate = Templates::ConstructorParameterTemplate;
         FieldDescriptor::Type fieldType = field->type();
         if (field->is_repeated() && !field->is_map()) {
@@ -119,28 +94,27 @@ void ProtobufClassGenerator::printConstructor(int fieldCount)
                   || field->is_map()) {
             parameterTemplate = Templates::ConstructorMessageParameterTemplate;
         }
-        mPrinter->Print(common::producePropertyMap(field, mMessage), parameterTemplate);
+        mPrinter->Print(common::producePropertyMap(field, mDescriptor), parameterTemplate);
     }
 
-    mPrinter->Print({{"classname", mClassName}}, Templates::ProtoConstructorEndTemplate);
-    mPrinter->Print("\n");
+    mPrinter->Print({{"classname", mName}}, Templates::ProtoConstructorEndTemplate);
 }
 
-void ProtobufClassGenerator::printMaps()
+void MessageDeclarationPrinter::printMaps()
 {
     Indent();
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        const FieldDescriptor *field = mMessage->field(i);        
+    for (int i = 0; i < mDescriptor->field_count(); i++) {
+        const FieldDescriptor *field = mDescriptor->field(i);
         if (field->is_map()) {
             const Descriptor *type = field->message_type();
             const char *mapTemplate = type->field(1)->type() == FieldDescriptor::TYPE_MESSAGE ? Templates::MessageMapTypeUsingTemplate : Templates::MapTypeUsingTemplate;
-            mPrinter->Print(common::producePropertyMap(field, mMessage), mapTemplate);
+            mPrinter->Print(common::producePropertyMap(field, mDescriptor), mapTemplate);
         }
     }
     Outdent();
 }
 
-void ProtobufClassGenerator::printMetaTypesDeclaration()
+void MessageDeclarationPrinter::printMetaTypesDeclaration()
 {
     mPrinter->Print(mTypeMap,
                    Templates::DeclareMetaTypeTemplate);
@@ -151,33 +125,31 @@ void ProtobufClassGenerator::printMetaTypesDeclaration()
         mPrinter->Print(mTypeMap,
                         Templates::DeclareComplexQmlListTypeTemplate);
     }
-
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        const FieldDescriptor *field = mMessage->field(i);
-        auto fieldMap = common::producePropertyMap(field, nullptr);
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, PropertyMap &propertyMap) {
         if (field->type() == FieldDescriptor::TYPE_ENUM
-                && common::isLocalEnum(field->enum_type(), mMessage)) {
-            mPrinter->Print(fieldMap, Templates::DeclareMetaTypeTemplate);
+                && common::isLocalEnum(field->enum_type(), mDescriptor)) {
+            mPrinter->Print(propertyMap, Templates::DeclareMetaTypeTemplate);
+            mPrinter->Print(propertyMap, Templates::DeclareMetaTypeListTemplate);
         } else if (field->is_map()) {
-            fieldMap["key_type_underscore"] = fieldMap["key_type"];
-            utils::replace(fieldMap["key_type_underscore"], "::", "_");
+            propertyMap["key_type_underscore"] = propertyMap["key_type"];
+            utils::replace(propertyMap["key_type_underscore"], "::", "_");
 
-            fieldMap["value_type_underscore"] = fieldMap["key_type"];
-            utils::replace(fieldMap["value_type_underscore"], "::", "_");
+            propertyMap["value_type_underscore"] = propertyMap["key_type"];
+            utils::replace(propertyMap["value_type_underscore"], "::", "_");
 
-            mPrinter->Print(fieldMap, Templates::DeclareMetaTypeMapTemplate);
+            mPrinter->Print(propertyMap, Templates::DeclareMetaTypeMapTemplate);
         }
-    }
+    });
 }
 
-void ProtobufClassGenerator::printProperties()
+void MessageDeclarationPrinter::printProperties()
 {
-    assert(mMessage != nullptr);
+    assert(mDescriptor != nullptr);
     //private section
     Indent();
 
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        const FieldDescriptor *field = mMessage->field(i);
+    for (int i = 0; i < mDescriptor->field_count(); i++) {
+        const FieldDescriptor *field = mDescriptor->field(i);
         const char *propertyTemplate = Templates::PropertyTemplate;
         if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() && !field->is_repeated()) {
             propertyTemplate = Templates::MessagePropertyTemplate;
@@ -186,32 +158,30 @@ void ProtobufClassGenerator::printProperties()
         } else if (field->is_repeated() && !field->is_map()) {
             propertyTemplate = Templates::RepeatedPropertyTemplate;
         }
-        mPrinter->Print(common::producePropertyMap(field, mMessage), propertyTemplate);
+        mPrinter->Print(common::producePropertyMap(field, mDescriptor), propertyTemplate);
     }
 
     //Generate extra QmlListProperty that is mapped to list
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        const FieldDescriptor *field = mMessage->field(i);
+    for (int i = 0; i < mDescriptor->field_count(); i++) {
+        const FieldDescriptor *field = mDescriptor->field(i);
         if (field->type() == FieldDescriptor::TYPE_MESSAGE && field->is_repeated() && !field->is_map()
                 && GeneratorOptions::instance().hasQml()) {
-            mPrinter->Print(common::producePropertyMap(field, mMessage), Templates::QmlListPropertyTemplate);
+            mPrinter->Print(common::producePropertyMap(field, mDescriptor), Templates::QmlListPropertyTemplate);
         } else if (common::hasQmlAlias(field)) {
-            mPrinter->Print(common::producePropertyMap(field, mMessage), Templates::NonScriptableAliasPropertyTemplate);
+            mPrinter->Print(common::producePropertyMap(field, mDescriptor), Templates::NonScriptableAliasPropertyTemplate);
         }
     }
 
     Outdent();
 }
 
-void ProtobufClassGenerator::printGetters()
+void MessageDeclarationPrinter::printGetters()
 {
     Indent();
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        const FieldDescriptor *field = mMessage->field(i);
+
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
         printComments(field);
         mPrinter->Print("\n");
-
-        PropertyMap propertyMap = common::producePropertyMap(field, mMessage);
         if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() && !field->is_repeated()) {
             mPrinter->Print(propertyMap, Templates::GetterPrivateMessageDeclarationTemplate);
             mPrinter->Print(propertyMap, Templates::GetterMessageDeclarationTemplate);
@@ -226,16 +196,14 @@ void ProtobufClassGenerator::printGetters()
                 mPrinter->Print(propertyMap, Templates::GetterQmlListDeclarationTemplate);
             }
         }
-    }
+    });
     Outdent();
 }
 
-void ProtobufClassGenerator::printSetters()
+void MessageDeclarationPrinter::printSetters()
 {
     Indent();
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        auto field = mMessage->field(i);
-        PropertyMap propertyMap = common::producePropertyMap(field, mMessage);
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
         switch (field->type()) {
         case FieldDescriptor::TYPE_MESSAGE:
             if (!field->is_map() && !field->is_repeated()) {
@@ -253,38 +221,68 @@ void ProtobufClassGenerator::printSetters()
             mPrinter->Print(propertyMap, Templates::SetterTemplate);
             break;
         }
-    }
+    });
     Outdent();
 }
 
-void ProtobufClassGenerator::printSignals()
+void MessageDeclarationPrinter::printSignals()
 {
     Indent();
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        mPrinter->Print(common::producePropertyMap(mMessage->field(i), mMessage), Templates::SignalTemplate);
+    for (int i = 0; i < mDescriptor->field_count(); i++) {
+        mPrinter->Print(common::producePropertyMap(mDescriptor->field(i), mDescriptor), Templates::SignalTemplate);
     }
     Outdent();
 }
 
 
-void ProtobufClassGenerator::printPrivateMethods()
+void MessageDeclarationPrinter::printPrivateMethods()
 {
     Indent();
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        auto field = mMessage->field(i);
-        auto propertyMap = common::producePropertyMap(field, mMessage);
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
         if (common::hasQmlAlias(field)) {
             mPrinter->Print(propertyMap, Templates::NonScriptableGetterTemplate);
             mPrinter->Print(propertyMap, Templates::NonScriptableSetterTemplate);
         }
+    });
+    Outdent();
+}
+
+void MessageDeclarationPrinter::printQEnums() {
+    if (mDescriptor->enum_type_count() <= 0) {
+        return;
+    }
+
+    printPublicBlock();
+
+    Indent();
+    for (int i = 0; i < mDescriptor->enum_type_count(); i++) {
+        const auto enumDescr = mDescriptor->enum_type(i);
+        auto typeMap = common::produceEnumTypeMap(enumDescr, mDescriptor);
+        mPrinter->Print(typeMap, Templates::EnumDefinitionTemplate);
+
+        Indent();
+        for (int j = 0; j < enumDescr->value_count(); j++) {
+            const auto valueDescr = enumDescr->value(j);
+            mPrinter->Print({{"enumvalue", utils::upperCaseName(valueDescr->name())},
+                             {"value", std::to_string(valueDescr->number())}}, Templates::EnumFieldTemplate);
+        }
+        Outdent();
+        mPrinter->Print(Templates::SemicolonBlockEnclosureTemplate);
+        mPrinter->Print(typeMap, Templates::QEnumTemplate);
+    }
+
+    for (int i = 0; i < mDescriptor->enum_type_count(); i++) {
+        const auto enumDescr = mDescriptor->enum_type(i);
+        auto typeMap = common::produceEnumTypeMap(enumDescr, mDescriptor);
+        mPrinter->Print(typeMap, Templates::EnumTypeRepeatedTemplate);
     }
     Outdent();
 }
 
-void ProtobufClassGenerator::printClassBody()
+void MessageDeclarationPrinter::printClassBody()
 {
     printProperties();
-    printQEnums(mMessage);
+    printQEnums();
 
     printPublicBlock();
     printMaps();
@@ -303,7 +301,7 @@ void ProtobufClassGenerator::printClassBody()
     printSetters();
 
     Indent();
-    mPrinter->Print({{"classname", mClassName}}, Templates::ManualRegistrationDeclaration);
+    mPrinter->Print({{"classname", mName}}, Templates::ManualRegistrationDeclaration);
     Outdent();
 
     printSignalsBlock();
@@ -316,17 +314,15 @@ void ProtobufClassGenerator::printClassBody()
     printClassMembers();
 }
 
-void ProtobufClassGenerator::printListType()
+void MessageDeclarationPrinter::printListType()
 {
-    mPrinter->Print({{"classname", mClassName}}, Templates::ComplexListTypeUsingTemplate);
+    mPrinter->Print({{"classname", mName}}, Templates::ComplexListTypeUsingTemplate);
 }
 
-void ProtobufClassGenerator::printClassMembers()
+void MessageDeclarationPrinter::printClassMembers()
 {
     Indent();
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        auto field = mMessage->field(i);
-        auto propertyMap = common::producePropertyMap(field, mMessage);
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
         if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() && !field->is_repeated()) {
             mPrinter->Print(propertyMap, Templates::ComplexMemberTemplate);
         } else if(field->is_repeated() && !field->is_map()){
@@ -334,38 +330,11 @@ void ProtobufClassGenerator::printClassMembers()
         } else {
             mPrinter->Print(propertyMap, Templates::MemberTemplate);
         }
-    }
+    });
     Outdent();
 }
 
-void ProtobufClassGenerator::run()
+void MessageDeclarationPrinter::printDestructor()
 {
-    printDisclaimer();
-    printPreamble();
-    printIncludes();
-    printNamespaces();
-    printFieldClassDeclaration();
-    printComments(mMessage);
-    printClassDeclaration();
-    printClassBody();
-    encloseClass();
-    printListType();
-    encloseNamespaces();
-    printMetaTypesDeclaration();
-}
-
-void ProtobufClassGenerator::printDestructor()
-{
-    mPrinter->Print({{"classname", mClassName}}, "virtual ~$classname$();\n");
-}
-
-void ProtobufClassGenerator::printFieldClassDeclaration()
-{
-    for(int i = 0; i < mMessage->field_count(); i++) {
-        auto field = mMessage->field(i);
-        if (field->type() == FieldDescriptor::TYPE_MESSAGE
-                && !field->is_map() && !field->is_repeated()) {
-            mPrinter->Print({{"classname", utils::upperCaseName(field->message_type()->name())}}, Templates::ProtoClassDeclarationTemplate);
-        }
-    }
+    mPrinter->Print({{"classname", mName}}, "virtual ~$classname$();\n");
 }

+ 20 - 25
src/generator/protobufclassgenerator.h → src/generator/messagedeclarationprinter.h

@@ -1,7 +1,7 @@
 /*
  * MIT License
  *
- * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
  *
  * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
  *
@@ -25,19 +25,7 @@
 
 #pragma once
 
-#include "classgeneratorbase.h"
-#include <google/protobuf/io/printer.h>
-#include <memory>
-
-#include "templates.h"
-#include "generatorcommon.h"
-
-namespace google { namespace protobuf {
-class FieldDescriptor;
-class Descriptor;
-namespace io {
-class ZeroCopyOutputStream;
-}}}
+#include "descriptorprinterbase.h"
 
 namespace QtProtobuf {
 namespace generator {
@@ -45,19 +33,27 @@ namespace generator {
 /*!
  * \ingroup generator
  * \private
- * \brief The ProtobufClassGenerator class
+ * \brief The MessageDeclarationPrinter class
  */
-class ProtobufClassGenerator : public ClassGeneratorBase
+
+class MessageDeclarationPrinter : public DescriptorPrinterBase<google::protobuf::Descriptor>
 {
-    const ::google::protobuf::Descriptor *mMessage;
 public:
-    ProtobufClassGenerator(const ::google::protobuf::Descriptor *message, const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out);
-    ProtobufClassGenerator(const ::google::protobuf::Descriptor *message, const std::shared_ptr<::google::protobuf::io::Printer> &printer);
-    virtual ~ProtobufClassGenerator() = default;
+    MessageDeclarationPrinter(const ::google::protobuf::Descriptor *message, const std::shared_ptr<::google::protobuf::io::Printer> &printer);
+    virtual ~MessageDeclarationPrinter() = default;
 
-    void run();
+    void run() {
+        printNamespaces();
+        printComments(mDescriptor);
+        printClassDeclaration();
+        printClassBody();
+        encloseClass();
+        printListType();
+        encloseNamespaces();
+        printMetaTypesDeclaration();
+    }
 
-    void printIncludes();
+private:
     void printCopyFunctionality();
     void printMoveSemantic();
     void printComparisonOperators();
@@ -75,9 +71,8 @@ public:
     void printMaps();
 
     void printMetaTypesDeclaration();
-    void printFieldClassDeclaration();
-private:
-    TypeMap mTypeMap;
+
+    void printQEnums();
 };
 
 }

+ 357 - 0
src/generator/messagedefinitionprinter.cpp

@@ -0,0 +1,357 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
+ *
+ * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies
+ * or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "messagedefinitionprinter.h"
+
+#include <google/protobuf/descriptor.h>
+#include "generatoroptions.h"
+
+using namespace QtProtobuf::generator;
+using namespace ::google::protobuf;
+
+MessageDefinitionPrinter::MessageDefinitionPrinter(const Descriptor *message, const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
+    DescriptorPrinterBase<Descriptor>(message, printer)
+{
+    mTypeMap = common::produceMessageTypeMap(message, nullptr);
+}
+
+void MessageDefinitionPrinter::printRegisterBody()
+{
+    mPrinter->Print(mTypeMap,
+                    Templates::ManualRegistrationComplexTypeDefinition);
+    Indent();
+    if (GeneratorOptions::instance().hasQml()) {
+        mPrinter->Print(mTypeMap, Templates::RegisterQmlListPropertyMetaTypeTemplate);
+        mPrinter->Print(mTypeMap, Templates::QmlRegisterTypeTemplate);
+    }
+
+    common::iterateMessageFields(mDescriptor, [this](const FieldDescriptor *field, const PropertyMap &propertyMap) {
+        if (field->type() == FieldDescriptor::TYPE_ENUM
+                && common::isLocalEnum(field->enum_type(), mDescriptor)) {
+            mPrinter->Print(propertyMap, Templates::RegisterLocalEnumTemplate);
+        } else if (field->is_map()) {
+            mPrinter->Print(propertyMap, Templates::RegisterMapTemplate);
+        }
+    });
+
+    Outdent();
+    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
+}
+
+void MessageDefinitionPrinter::printFieldsOrdering() {
+    mPrinter->Print({{"type", mName}}, Templates::FieldsOrderingContainerTemplate);
+    Indent();
+    for (int i = 0; i < mDescriptor->field_count(); i++) {
+        const FieldDescriptor *field = mDescriptor->field(i);
+        if (i != 0) {
+            mPrinter->Print("\n,");
+        }
+        //property_number is incremented by 1 because user properties stating from 1.
+        //Property with index 0 is "objectName"
+        mPrinter->Print({{"field_number", std::to_string(field->number())},
+                         {"property_number", std::to_string(i + 1)}}, Templates::FieldOrderTemplate);
+    }
+    Outdent();
+    mPrinter->Print(Templates::SemicolonBlockEnclosureTemplate);
+    mPrinter->Print("\n");
+}
+
+void MessageDefinitionPrinter::printConstructors() {
+    for (int i = 0; i <= mDescriptor->field_count(); i++) {
+        mPrinter->Print(mTypeMap, Templates::ProtoConstructorDefinitionBeginTemplate);
+        printConstructor(i);
+        mPrinter->Print(mTypeMap, Templates::ProtoConstructorDefinitionEndTemplate);
+        printInitializationList(i);
+        mPrinter->Print(Templates::ConstructorContentTemplate);
+    }
+}
+
+void MessageDefinitionPrinter::printConstructor(int fieldCount)
+{
+    for (int i = 0; i < fieldCount; i++) {
+        const FieldDescriptor *field = mDescriptor->field(i);
+        const char *parameterTemplate = Templates::ConstructorParameterTemplate;
+        FieldDescriptor::Type fieldType = field->type();
+        if (field->is_repeated() && !field->is_map()) {
+            parameterTemplate = Templates::ConstructorRepeatedParameterTemplate;
+        } else if(fieldType == FieldDescriptor::TYPE_BYTES
+                  || fieldType == FieldDescriptor::TYPE_STRING
+                  || fieldType == FieldDescriptor::TYPE_MESSAGE
+                  || field->is_map()) {
+            parameterTemplate = Templates::ConstructorMessageParameterTemplate;
+        }
+        mPrinter->Print(common::producePropertyMap(field, mDescriptor), parameterTemplate);
+    }
+}
+
+void MessageDefinitionPrinter::printInitializationList(int fieldCount)
+{
+    for (int i = 0; i < mDescriptor->field_count(); i++) {
+        const FieldDescriptor *field = mDescriptor->field(i);
+        auto propertyMap = common::producePropertyMap(field, mDescriptor);
+        propertyMap["initializer"] = "";
+        if (!field->is_repeated() && !field->is_map()) {
+            switch (field->type()) {
+            case FieldDescriptor::TYPE_DOUBLE:
+            case FieldDescriptor::TYPE_FLOAT:
+                propertyMap["initializer"] = "0.0";
+                break;
+            case FieldDescriptor::TYPE_FIXED32:
+            case FieldDescriptor::TYPE_FIXED64:
+            case FieldDescriptor::TYPE_INT32:
+            case FieldDescriptor::TYPE_INT64:
+            case FieldDescriptor::TYPE_SINT32:
+            case FieldDescriptor::TYPE_SINT64:
+            case FieldDescriptor::TYPE_UINT32:
+            case FieldDescriptor::TYPE_UINT64:
+                propertyMap["initializer"] = "0";
+                break;
+            case FieldDescriptor::TYPE_BOOL:
+                propertyMap["initializer"] = "false";
+                break;
+            case FieldDescriptor::TYPE_ENUM:
+                propertyMap["initializer"] = propertyMap["scope_type"] + "::" + field->enum_type()->value(0)->name();
+                break;
+            default:
+                break;
+            }
+        }
+
+        if (field->type() == FieldDescriptor::TYPE_MESSAGE
+                && !field->is_map() && !field->is_repeated()) {
+            if (i < fieldCount) {
+                mPrinter->Print(propertyMap, Templates::MessagePropertyInitializerTemplate);
+            } else {
+                mPrinter->Print(propertyMap, Templates::MessagePropertyDefaultInitializerTemplate);
+            }
+        } else {
+            if (i < fieldCount) {
+                mPrinter->Print(propertyMap, Templates::PropertyInitializerTemplate);
+            } else {
+                if (!propertyMap["initializer"].empty()) {
+                    mPrinter->Print(propertyMap, Templates::PropertyDefaultInitializerTemplate);
+                }
+            }
+        }
+    }
+}
+
+void MessageDefinitionPrinter::printCopyFunctionality()
+{
+    assert(mDescriptor != nullptr);
+
+    const char *constructorTemplate = Templates::CopyConstructorDefinitionTemplate;
+    const char *assignmentOperatorTemplate = Templates::AssignmentOperatorDefinitionTemplate;
+    if (mDescriptor->field_count() <= 0) {
+        constructorTemplate = Templates::EmptyCopyConstructorDefinitionTemplate;
+        assignmentOperatorTemplate = Templates::EmptyAssignmentOperatorDefinitionTemplate;
+    }
+
+    mPrinter->Print({{"classname", mName}},
+                    constructorTemplate);
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
+        if (field->type() == FieldDescriptor::TYPE_MESSAGE
+                && !field->is_map() && !field->is_repeated()) {
+            mPrinter->Print(propertyMap, Templates::MessagePropertyDefaultInitializerTemplate);
+        }
+    });
+    mPrinter->Print("\n{\n");
+
+    Indent();
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
+        if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() && !field->is_repeated()) {
+            mPrinter->Print(propertyMap, Templates::CopyComplexFieldTemplate);
+        } else {
+            mPrinter->Print(propertyMap, Templates::CopyFieldTemplate);
+        }
+    });
+    Outdent();
+    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
+
+    mPrinter->Print({{"classname", mName}}, assignmentOperatorTemplate);
+    Indent();
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
+        if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() && !field->is_repeated()) {
+            mPrinter->Print(propertyMap, Templates::CopyComplexFieldTemplate);
+        } else {
+            mPrinter->Print(propertyMap, Templates::CopyFieldTemplate);
+        }
+    });
+    mPrinter->Print(Templates::AssignmentOperatorReturnTemplate);
+    Outdent();
+    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
+}
+
+void MessageDefinitionPrinter::printMoveSemantic()
+{
+    assert(mDescriptor != nullptr);
+
+    const char *constructorTemplate = Templates::MoveConstructorDefinitionTemplate;
+    const char *assignmentOperatorTemplate = Templates::MoveAssignmentOperatorDefinitionTemplate;
+    if (mDescriptor->field_count() <= 0) {
+        constructorTemplate = Templates::EmptyMoveConstructorDefinitionTemplate;
+        assignmentOperatorTemplate = Templates::EmptyMoveAssignmentOperatorDefinitionTemplate;
+    }
+
+    mPrinter->Print({{"classname", mName}},
+                    constructorTemplate);
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
+        if (field->type() == FieldDescriptor::TYPE_MESSAGE
+                && !field->is_map() && !field->is_repeated()) {
+            mPrinter->Print(propertyMap, Templates::MessagePropertyDefaultInitializerTemplate);
+        }
+    });
+    mPrinter->Print("\n{\n");
+
+    Indent();
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
+        if (field->type() == FieldDescriptor::TYPE_MESSAGE
+                || field->type() == FieldDescriptor::TYPE_STRING
+                || field->type() == FieldDescriptor::TYPE_BYTES
+                || field->is_repeated()) {
+            if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() && !field->is_repeated()) {
+                mPrinter->Print(propertyMap, Templates::MoveMessageFieldTemplate);
+            } else {
+                mPrinter->Print(propertyMap, Templates::MoveComplexFieldConstructorTemplate);
+            }
+        } else {
+            if (field->type() != FieldDescriptor::TYPE_ENUM) {
+                mPrinter->Print(propertyMap, Templates::MoveFieldTemplate);
+            }
+            else {
+                mPrinter->Print(propertyMap, Templates::EnumMoveFieldTemplate);
+            }
+        }
+    });
+    Outdent();
+    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
+
+    mPrinter->Print({{"classname", mName}}, assignmentOperatorTemplate);
+    Indent();
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
+        if (field->type() == FieldDescriptor::TYPE_MESSAGE
+                || field->type() == FieldDescriptor::TYPE_STRING
+                || field->type() == FieldDescriptor::TYPE_BYTES
+                || field->is_repeated()) {
+            if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() && !field->is_repeated()) {
+                mPrinter->Print(propertyMap, Templates::MoveMessageFieldTemplate);
+            } else {
+                mPrinter->Print(propertyMap, Templates::MoveComplexFieldTemplate);
+            }
+        } else {
+            if (field->type() != FieldDescriptor::TYPE_ENUM) {
+                mPrinter->Print(propertyMap, Templates::MoveFieldTemplate);
+            }
+            else {
+                mPrinter->Print(propertyMap, Templates::EnumMoveFieldTemplate);
+            }
+        }
+    });
+    mPrinter->Print(Templates::AssignmentOperatorReturnTemplate);
+    Outdent();
+    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
+}
+
+void MessageDefinitionPrinter::printComparisonOperators()
+{
+    assert(mDescriptor != nullptr);
+    if (mDescriptor->field_count() <= 0) {
+        mPrinter->Print({{"classname", mName}}, Templates::EmptyEqualOperatorDefinitionTemplate);
+        mPrinter->Print({{"classname", mName}}, Templates::NotEqualOperatorDefinitionTemplate);
+        return;
+    }
+
+    mPrinter->Print({{"classname", mName}}, Templates::EqualOperatorDefinitionTemplate);
+
+    bool isFirst = true;
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, PropertyMap &propertyMap) {
+        if (!isFirst) {
+            mPrinter->Print("\n&& ");
+        } else {
+            Indent();
+            Indent();
+            isFirst = false;
+        }
+        if (field->type() == FieldDescriptor::TYPE_MESSAGE
+                && !field->is_map() && !field->is_repeated()) {
+            mPrinter->Print(propertyMap, Templates::EqualOperatorMessagePropertyTemplate);
+        } else {
+            mPrinter->Print(propertyMap, Templates::EqualOperatorPropertyTemplate);
+        }
+    });
+
+    //Only if at least one field "copied"
+    if (!isFirst) {
+        Outdent();
+        Outdent();
+    }
+
+    mPrinter->Print(";\n");
+    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
+
+    mPrinter->Print({{"classname", mName}}, Templates::NotEqualOperatorDefinitionTemplate);
+}
+
+void MessageDefinitionPrinter::printGetters()
+{
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, PropertyMap &propertyMap) {
+        if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() && !field->is_repeated()) {
+            mPrinter->Print(propertyMap, Templates::GetterPrivateMessageDefinitionTemplate);
+            mPrinter->Print(propertyMap, Templates::GetterMessageDefinitionTemplate);
+        }
+        if (field->is_repeated()) {
+            if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map()
+                    && GeneratorOptions::instance().hasQml()) {
+                mPrinter->Print(propertyMap, Templates::GetterQmlListDefinitionTemplate);
+            }
+        }
+    });
+
+    common::iterateMessageFields(mDescriptor, [&](const FieldDescriptor *field, PropertyMap &propertyMap) {
+        switch (field->type()) {
+        case FieldDescriptor::TYPE_MESSAGE:
+            if (!field->is_map() && !field->is_repeated()) {
+                mPrinter->Print(propertyMap, Templates::SetterPrivateTemplateDefinitionMessageType);
+                mPrinter->Print(propertyMap, Templates::SetterTemplateDefinitionMessageType);
+            } else {
+                mPrinter->Print(propertyMap, Templates::SetterTemplateDefinitionComplexType);
+            }
+            break;
+        case FieldDescriptor::FieldDescriptor::TYPE_STRING:
+        case FieldDescriptor::FieldDescriptor::TYPE_BYTES:
+            mPrinter->Print(propertyMap, Templates::SetterTemplateDefinitionComplexType);
+            break;
+        default:
+            break;
+        }
+    });
+}
+
+void MessageDefinitionPrinter::printDestructor()
+{
+    mPrinter->Print({{"classname", mName}}, Templates::RegistrarTemplate);
+    mPrinter->Print({{"classname", mName}}, "$classname$::~$classname$()\n"
+                                                 "{}\n\n");
+}

+ 20 - 26
src/generator/protobufsourcegenerator.h → src/generator/messagedefinitionprinter.h

@@ -25,9 +25,7 @@
 
 #pragma once
 
-#include "classsourcegeneratorbase.h"
-
-#include "generatorcommon.h"
+#include "descriptorprinterbase.h"
 
 namespace QtProtobuf {
 namespace generator {
@@ -35,42 +33,38 @@ namespace generator {
 /*!
  * \ingroup generator
  * \private
- * \brief The ProtobufSourceGenerator class
+ * \brief The MessageDefinitionPrinter class
  */
-class ProtobufSourceGenerator : public ClassSourceGeneratorBase
+
+class MessageDefinitionPrinter : public DescriptorPrinterBase<google::protobuf::Descriptor>
 {
-    const google::protobuf::Descriptor *mMessage;
-    TypeMap mTypeMap;
 public:
-    ProtobufSourceGenerator(const google::protobuf::Descriptor *message, const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out);
-    ProtobufSourceGenerator(const google::protobuf::Descriptor *message, const std::shared_ptr<::google::protobuf::io::Printer> &printer);
-
-    void printRegisterBody();
-    void printFieldsOrdering();
-    void printConstructor();
-    void printCopyFunctionality();
-    void printMoveSemantic();
-    void printComparisonOperators();
-    void printGetters();
-    void printDestructor();
-    void printIncludes();
+    MessageDefinitionPrinter(const google::protobuf::Descriptor *message, const std::shared_ptr<::google::protobuf::io::Printer> &printer);
 
-    void run() override {
-        printDisclaimer();
-        printClassHeaderInclude();
-        printIncludes();
+    void run() {
         printNamespaces();
         printDestructor();
         printFieldsOrdering();
         printRegisterBody();
-        printConstructor();
+        printConstructors();
         printCopyFunctionality();
         printMoveSemantic();
         printComparisonOperators();
         printGetters();
         encloseNamespaces();
     }
+
+private:
+    void printRegisterBody();
+    void printFieldsOrdering();
+    void printConstructors();
+    void printConstructor(int fieldCount);
+    void printInitializationList(int fieldCount);
+    void printCopyFunctionality();
+    void printMoveSemantic();
+    void printComparisonOperators();
+    void printGetters();
+    void printDestructor();
 };
 
-} //namespace QtProtobuf
-} //namespace generator
+}}

+ 203 - 0
src/generator/multifilegenerator.cpp

@@ -0,0 +1,203 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
+ *
+ * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies
+ * or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "multifilegenerator.h"
+#include "templates.h"
+
+#include "messagedeclarationprinter.h"
+#include "messagedefinitionprinter.h"
+#include "enumdeclarationprinter.h"
+#include "enumdefinitionprinter.h"
+
+#include "serverdeclarationprinter.h"
+#include "clientdeclarationprinter.h"
+#include "clientdefinitionprinter.h"
+#include "utils.h"
+#include "generatoroptions.h"
+
+#include <iostream>
+#include <set>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.h>
+
+using namespace ::QtProtobuf::generator;
+using namespace ::google::protobuf;
+using namespace ::google::protobuf::compiler;
+
+MultiFileGenerator::MultiFileGenerator() : GeneratorBase(GeneratorBase::MultiMode)
+{}
+
+bool MultiFileGenerator::Generate(const FileDescriptor *file,
+                           const std::string &,
+                           GeneratorContext *generatorContext,
+                           std::string *error) const
+{
+    if (file->syntax() != FileDescriptor::SYNTAX_PROTO3) {
+        *error = "Invalid proto used. This plugin only supports 'proto3' syntax";
+        return false;
+    }
+
+    for (int i = 0; i < file->message_type_count(); i++) {
+        const Descriptor *message = file->message_type(i);
+
+        //Detect nested fields and filter maps fields
+        int mapsFieldsCount = 0;
+        for (int j = 0; j < message->nested_type_count(); j++) {
+            for (int k = 0; k < message->field_count(); k++) {
+                if (message->field(k)->is_map() && message->field(k)->message_type() == message->nested_type(j)) {
+                    ++mapsFieldsCount;
+                }
+            }
+        }
+
+        if (message->nested_type_count() > 0 && message->nested_type_count() > mapsFieldsCount) {
+            std::cerr << file->name() << ":" << (message->index() + 1) << ": " << " Error: Meta object features not supported for nested classes in " << message->full_name() << std::endl;
+            continue;
+        }
+
+        std::string baseFilename(message->name());
+        utils::tolower(baseFilename);
+        baseFilename = generateBaseName(file, baseFilename);
+
+        std::unique_ptr<io::ZeroCopyOutputStream> headerStream(generatorContext->Open(baseFilename + ".h"));
+        std::unique_ptr<io::ZeroCopyOutputStream> sourceStream(generatorContext->Open(baseFilename + ".cpp"));
+
+        std::shared_ptr<::google::protobuf::io::Printer> headerPrinter(new ::google::protobuf::io::Printer(headerStream.get(), '$'));
+        std::shared_ptr<::google::protobuf::io::Printer> sourcePrinter(new ::google::protobuf::io::Printer(sourceStream.get(), '$'));
+
+        MessageDeclarationPrinter messageDecl(message, headerPrinter);
+
+        printDisclaimer(headerPrinter);
+        printPreamble(headerPrinter);
+
+        headerPrinter->Print(Templates::DefaultProtobufIncludesTemplate);
+        if (GeneratorOptions::instance().hasQml()) {
+            headerPrinter->Print(Templates::QmlProtobufIncludesTemplate);
+        }
+
+        std::set<std::string> existingIncludes;
+        for (int i = 0; i < message->field_count(); i++) {
+            printInclude(headerPrinter, message, message->field(i), existingIncludes);
+        }
+
+        for (int i = 0; i < message->field_count(); i++) {
+            auto field = message->field(i);
+            if (field->type() == FieldDescriptor::TYPE_MESSAGE
+                    && !field->is_map() && !field->is_repeated()) {
+                auto dependency = field->message_type();
+                auto namespaces = common::getNamespaces(dependency);
+                printNamespaces(headerPrinter, namespaces);
+                headerPrinter->Print({{"classname", utils::upperCaseName(dependency->name())}}, Templates::ProtoClassDeclarationTemplate);
+                headerPrinter->Print("\n");
+                for (size_t i = 0; i < namespaces.size(); ++i) {
+                    headerPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
+                }
+                headerPrinter->Print("\n");
+            }
+        }
+
+        messageDecl.run();
+
+        printDisclaimer(sourcePrinter);
+        std::string includeFileName = message->name();
+        utils::tolower(includeFileName);
+        sourcePrinter->Print({{"include", includeFileName}}, Templates::InternalIncludeTemplate);
+        if (GeneratorOptions::instance().hasQml()) {
+            sourcePrinter->Print({{"include", "QQmlEngine"}}, Templates::ExternalIncludeTemplate);
+        }
+
+        MessageDefinitionPrinter messageDef(message, sourcePrinter);
+        messageDef.run();
+    }
+
+    for (int i = 0; i < file->service_count(); i++) {
+        const ServiceDescriptor *service = file->service(i);
+        std::string baseFilename(service->name());
+        utils::tolower(baseFilename);
+        baseFilename = generateBaseName(file, baseFilename);
+
+        std::unique_ptr<io::ZeroCopyOutputStream> headerStream(generatorContext->Open(baseFilename + "client.h"));
+        std::unique_ptr<io::ZeroCopyOutputStream> sourceStream(generatorContext->Open(baseFilename + "client.cpp"));
+        std::shared_ptr<::google::protobuf::io::Printer> headerPrinter(new ::google::protobuf::io::Printer(headerStream.get(), '$'));
+        std::shared_ptr<::google::protobuf::io::Printer> sourcePrinter(new ::google::protobuf::io::Printer(sourceStream.get(), '$'));
+
+        printDisclaimer(headerPrinter);
+        printPreamble(headerPrinter);
+        ClientDeclarationPrinter clientGen(service, headerPrinter);
+        clientGen.printIncludes();
+        clientGen.printClientIncludes();
+        clientGen.run();
+
+        printDisclaimer(sourcePrinter);
+        std::string includeFileName = service->name();
+        utils::tolower(includeFileName);
+        sourcePrinter->Print({{"include", includeFileName}}, Templates::InternalIncludeTemplate);
+        if (GeneratorOptions::instance().hasQml()) {
+            sourcePrinter->Print({{"include", "QQmlEngine"}}, Templates::ExternalIncludeTemplate);
+        }
+
+        printQtProtobufUsingNamespace(sourcePrinter);
+        ClientDefinitionPrinter clientSrcGen(service, sourcePrinter);
+        clientSrcGen.run();
+    }
+    return true;
+}
+
+bool MultiFileGenerator::GenerateAll(const std::vector<const FileDescriptor *> &files, const string &parameter, GeneratorContext *generatorContext, string *error) const
+{
+    std::string globalEnumsFilename = "globalenums";
+
+    std::unique_ptr<io::ZeroCopyOutputStream> headerStream(generatorContext->Open(globalEnumsFilename + ".h"));
+    std::unique_ptr<io::ZeroCopyOutputStream> sourceStream(generatorContext->Open(globalEnumsFilename + ".cpp"));
+    std::shared_ptr<::google::protobuf::io::Printer> headerPrinter(new ::google::protobuf::io::Printer(headerStream.get(), '$'));
+    std::shared_ptr<::google::protobuf::io::Printer> sourcePrinter(new ::google::protobuf::io::Printer(sourceStream.get(), '$'));
+
+    printDisclaimer(headerPrinter);
+    printPreamble(headerPrinter);
+    headerPrinter->Print(Templates::DefaultProtobufIncludesTemplate);
+
+    printDisclaimer(sourcePrinter);
+    sourcePrinter->Print({{"include", globalEnumsFilename}}, Templates::InternalIncludeTemplate);
+    if (GeneratorOptions::instance().hasQml()) {
+        sourcePrinter->Print({{"include", "QQmlEngine"}}, Templates::ExternalIncludeTemplate);
+    }
+
+    for (auto file : files) { //TODO: Each should be printed to separate file
+        for (int i = 0; i < file->enum_type_count(); i++) {
+            auto enumType = file->enum_type(i);
+            EnumDeclarationPrinter enumDecl(enumType, headerPrinter);
+            enumDecl.run();
+
+            EnumDefinitionPrinter enumDef(enumType, sourcePrinter);
+            enumDef.run();
+        }
+    }
+
+    return GeneratorBase::GenerateAll(files, parameter, generatorContext, error);
+}
+

+ 64 - 0
src/generator/multifilegenerator.h

@@ -0,0 +1,64 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
+ *
+ * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
+ * software and associated documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies
+ * or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <string>
+#include <memory>
+
+#include "generatorbase.h"
+
+namespace google { namespace protobuf {
+class FileDescriptor;
+namespace compiler {
+class GeneratorContext;
+}}}
+
+namespace QtProtobuf {
+namespace generator {
+/*!
+ * \ingroup generator
+ * \private
+ * \brief The MultiFileGenerator class
+ */
+class MultiFileGenerator : public GeneratorBase
+{
+public:
+    MultiFileGenerator();
+    bool Generate(const ::google::protobuf::FileDescriptor *file,
+                          const std::string &parameter,
+                          ::google::protobuf::compiler::GeneratorContext *generatorContext,
+                          std::string *error) const override;
+
+    bool GenerateAll(const std::vector<const ::google::protobuf::FileDescriptor *> &files,
+                             const std::string &parameter,
+                             ::google::protobuf::compiler::GeneratorContext *generatorContext,
+                             std::string *error) const override;
+};
+
+} //namespace generator
+} // namespace QtProtobuf

+ 0 - 442
src/generator/protobufsourcegenerator.cpp

@@ -1,442 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
- *
- * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this
- * software and associated documentation files (the "Software"), to deal in the Software
- * without restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
- * to permit persons to whom the Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies
- * or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
- * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include "protobufsourcegenerator.h"
-#include "utils.h"
-
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#include "generatoroptions.h"
-
-using namespace QtProtobuf::generator;
-using namespace ::google::protobuf;
-using namespace ::google::protobuf::io;
-using namespace ::google::protobuf::compiler;
-
-ProtobufSourceGenerator::ProtobufSourceGenerator(const google::protobuf::Descriptor *message,
-                                                 const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out) :
-    ClassSourceGeneratorBase(message->full_name(), out)
-  , mMessage(message)
-  , mTypeMap(common::produceMessageTypeMap(message, nullptr))
-{
-}
-
-ProtobufSourceGenerator::ProtobufSourceGenerator(const google::protobuf::Descriptor *message, const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
-    ClassSourceGeneratorBase(message->full_name(), printer)
-  , mMessage(message)
-  , mTypeMap(common::produceMessageTypeMap(message, nullptr))
-{
-}
-
-void ProtobufSourceGenerator::printRegisterBody()
-{
-    mPrinter->Print(mTypeMap,
-                    Templates::ManualRegistrationComplexTypeDefinition);
-    Indent();
-    if (GeneratorOptions::instance().hasQml()) {
-        mPrinter->Print(mTypeMap, Templates::RegisterQmlListPropertyMetaTypeTemplate);
-        mPrinter->Print(mTypeMap, Templates::QmlRegisterTypeTemplate);
-    }
-
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        const FieldDescriptor *field = mMessage->field(i);
-        if (field->type() == FieldDescriptor::TYPE_ENUM
-                && common::isLocalEnum(field->enum_type(), mMessage)) {
-            mPrinter->Print({{"type", mClassName + "::" + field->enum_type()->name() + Templates::ListSuffix},
-                             {"namespaces", mNamespacesColonDelimited}},
-                            Templates::RegisterMetaTypeTemplateNoNamespace);
-            mPrinter->Print({{"type", mClassName + "::" + field->enum_type()->name() + Templates::ListSuffix},
-                             {"namespaces", mNamespacesColonDelimited}},
-                            Templates::RegisterMetaTypeTemplate);
-            mPrinter->Print({{"type", mClassName + "::" + field->enum_type()->name()},
-                             {"namespaces", mNamespacesColonDelimited}},
-                            Templates::RegisterMetaTypeTemplateNoNamespace);
-            mPrinter->Print({{"type", mClassName + "::" + field->enum_type()->name()},
-                             {"namespaces", mNamespacesColonDelimited}},
-                            Templates::RegisterMetaTypeTemplate);
-            mPrinter->Print({{"type", mClassName + "::" + field->enum_type()->name()}},
-                            Templates::RegisterEnumSerializersTemplate);
-        } else if (field->is_map()) {
-            mPrinter->Print({{"type", field->message_type()->name()},
-                             {"namespaces", mClassName}},
-                            Templates::RegisterMetaTypeTemplate);
-            mPrinter->Print({{"type", field->message_type()->name()},
-                             {"namespaces", mNamespacesColonDelimited + "::" + mClassName}},
-                            Templates::RegisterMetaTypeTemplate);
-
-            mPrinter->Print({{"classname", mClassName},
-                             {"type", field->message_type()->name()},
-                             {"key_type", getTypeName(field->message_type()->field(0), mMessage)},
-                             {"value_type", getTypeName(field->message_type()->field(1), mMessage)}},
-                            Templates::MapSerializationRegisterTemplate);
-        }
-    }
-
-    Outdent();
-    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
-}
-
-void ProtobufSourceGenerator::printFieldsOrdering() {
-    mPrinter->Print({{"type", mClassName}}, Templates::FieldsOrderingContainerTemplate);
-    Indent();
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        const FieldDescriptor *field = mMessage->field(i);
-        if (i != 0) {
-            mPrinter->Print("\n,");
-        }
-        //property_number is incremented by 1 because user properties stating from 1.
-        //Property with index 0 is "objectName"
-        mPrinter->Print({{"field_number", std::to_string(field->number())},
-                         {"property_number", std::to_string(i + 1)}}, Templates::FieldOrderTemplate);
-    }
-    Outdent();
-    mPrinter->Print(Templates::SemicolonBlockEnclosureTemplate);
-    mPrinter->Print("\n");
-}
-
-void ProtobufSourceGenerator::printConstructor()
-{
-    std::vector<std::string> parameterList;
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        const FieldDescriptor *field = mMessage->field(i);
-        std::string fieldTypeName = getTypeName(field, mMessage);
-        std::string fieldName = utils::lowerCaseName(field->camelcase_name());
-        fieldName = qualifiedName(fieldName);
-
-        if (field->is_repeated() || field->is_map()) {
-            parameterList.push_back("const " + fieldTypeName + " &" + fieldName);
-        } else {
-            switch (field->type()) {
-            case FieldDescriptor::TYPE_DOUBLE:
-            case FieldDescriptor::TYPE_FLOAT:
-                parameterList.push_back(fieldTypeName + " " + fieldName);
-                break;
-            case FieldDescriptor::TYPE_FIXED32:
-            case FieldDescriptor::TYPE_FIXED64:
-            case FieldDescriptor::TYPE_INT32:
-            case FieldDescriptor::TYPE_INT64:
-            case FieldDescriptor::TYPE_SINT32:
-            case FieldDescriptor::TYPE_SINT64:
-            case FieldDescriptor::TYPE_UINT32:
-            case FieldDescriptor::TYPE_UINT64:
-                parameterList.push_back(fieldTypeName + " " + fieldName);
-                break;
-            case FieldDescriptor::TYPE_BOOL:
-                parameterList.push_back(fieldTypeName + " " + fieldName);
-                break;
-            case FieldDescriptor::TYPE_BYTES:
-            case FieldDescriptor::TYPE_STRING:
-            case FieldDescriptor::TYPE_MESSAGE:
-                parameterList.push_back("const " + fieldTypeName + " &" + fieldName);
-                break;
-            default:
-                parameterList.push_back(fieldTypeName + " " + fieldName);
-                break;
-            }
-        }
-    }
-
-    for (size_t i = 0; i <= parameterList.size(); i++) {
-        std::string parameters = "";
-        for (size_t j = 0; j < i; j++) {
-            parameters += parameterList[j] + ", ";
-        }
-        mPrinter->Print({{"classname", mClassName},
-                         {"parameter_list", parameters}}, Templates::ProtoConstructorDefinitionTemplate);
-        for (size_t j = 0; j < parameterList.size(); j++) {
-            const FieldDescriptor *field = mMessage->field(j);
-            std::string fieldName = utils::lowerCaseName(field->camelcase_name());
-            auto fieldTypeName = getTypeName(field, mMessage);
-            fieldName = qualifiedName(fieldName);
-            if (field->type() == FieldDescriptor::TYPE_MESSAGE
-                    && !field->is_map() && !field->is_repeated()) {
-                if (j < i) {
-                    mPrinter->Print({{"property_name", fieldName}, {"type", fieldTypeName}}, Templates::MessagePropertyInitializerTemplate);
-                } else {
-                    mPrinter->Print({{"property_name", fieldName}, {"type", fieldTypeName}}, Templates::MessagePropertyEmptyInitializerTemplate);
-                }
-            } else {
-                if (j < i) {
-                    mPrinter->Print({{"property_name", fieldName}}, Templates::PropertyInitializerTemplate);
-                } else {
-                    std::string initializer = "";
-                    if (!field->is_repeated() && !field->is_map()) {
-                        switch (field->type()) {
-                        case FieldDescriptor::TYPE_DOUBLE:
-                        case FieldDescriptor::TYPE_FLOAT:
-                            initializer = "0.0";
-                            break;
-                        case FieldDescriptor::TYPE_FIXED32:
-                        case FieldDescriptor::TYPE_FIXED64:
-                        case FieldDescriptor::TYPE_INT32:
-                        case FieldDescriptor::TYPE_INT64:
-                        case FieldDescriptor::TYPE_SINT32:
-                        case FieldDescriptor::TYPE_SINT64:
-                        case FieldDescriptor::TYPE_UINT32:
-                        case FieldDescriptor::TYPE_UINT64:
-                            initializer = "0";
-                            break;
-                        case FieldDescriptor::TYPE_BOOL:
-                            initializer = "false";
-                            break;
-                        case FieldDescriptor::TYPE_ENUM:
-                            initializer = fieldTypeName + "::" + field->enum_type()->value(0)->name();
-                            break;
-                        default:
-                            break;
-                        }
-                    }
-                    if (initializer != "") {
-                        mPrinter->Print({{"property_name", fieldName}, {"initializer", initializer}}, Templates::PropertyEmptyInitializerTemplate);
-                    }
-                }
-            }
-        }
-        mPrinter->Print(Templates::ConstructorContentTemplate);
-        mPrinter->Print("\n");
-    }
-}
-
-void ProtobufSourceGenerator::printCopyFunctionality()
-{
-    assert(mMessage != nullptr);
-
-    const char *constructorTemplate = Templates::CopyConstructorDefinitionTemplate;
-    const char *assignmentOperatorTemplate = Templates::AssignmentOperatorDefinitionTemplate;
-    if (mMessage->field_count() <= 0) {
-        constructorTemplate = Templates::EmptyCopyConstructorDefinitionTemplate;
-        assignmentOperatorTemplate = Templates::EmptyAssignmentOperatorDefinitionTemplate;
-    }
-
-    mPrinter->Print({{"classname", mClassName}},
-                    constructorTemplate);
-    for (int j = 0; j < mMessage->field_count(); j++) {
-        const FieldDescriptor *field = mMessage->field(j);
-        std::string fieldName = utils::lowerCaseName(field->camelcase_name());
-        auto fieldTypeName = getTypeName(field, mMessage);
-        fieldName = qualifiedName(fieldName);
-
-        if (field->type() == FieldDescriptor::TYPE_MESSAGE
-                && !field->is_map() && !field->is_repeated()) {
-            mPrinter->Print({{"property_name", fieldName}, {"type", fieldTypeName}}, Templates::MessagePropertyEmptyInitializerTemplate);
-        }
-    }
-    mPrinter->Print("\n{\n");
-
-    Indent();
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        auto field = mMessage->field(i);
-        if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() && !field->is_repeated()) {
-            printField(mMessage, field, Templates::CopyComplexFieldTemplate);
-        } else {
-            printField(mMessage, field, Templates::CopyFieldTemplate);
-        }
-    }
-    Outdent();
-    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
-
-    mPrinter->Print({{"classname", mClassName}},
-                    assignmentOperatorTemplate);
-    Indent();
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        auto field = mMessage->field(i);
-        if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() && !field->is_repeated()) {
-            printField(mMessage, field, Templates::CopyComplexFieldTemplate);
-        } else {
-            printField(mMessage, field, Templates::CopyFieldTemplate);
-        }
-    }
-    mPrinter->Print(Templates::AssignmentOperatorReturnTemplate);
-    Outdent();
-    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
-}
-
-void ProtobufSourceGenerator::printMoveSemantic()
-{
-    assert(mMessage != nullptr);
-
-    const char *constructorTemplate = Templates::MoveConstructorDefinitionTemplate;
-    const char *assignmentOperatorTemplate = Templates::MoveAssignmentOperatorDefinitionTemplate;
-    if (mMessage->field_count() <= 0) {
-        constructorTemplate = Templates::EmptyMoveConstructorDefinitionTemplate;
-        assignmentOperatorTemplate = Templates::EmptyMoveAssignmentOperatorDefinitionTemplate;
-    }
-
-    mPrinter->Print({{"classname", mClassName}},
-                    constructorTemplate);
-    for (int j = 0; j < mMessage->field_count(); j++) {
-        const FieldDescriptor *field = mMessage->field(j);
-        std::string fieldName = utils::lowerCaseName(field->camelcase_name());
-        auto fieldTypeName = getTypeName(field, mMessage);
-        fieldName = qualifiedName(fieldName);
-
-        if (field->type() == FieldDescriptor::TYPE_MESSAGE
-                && !field->is_map() && !field->is_repeated()) {
-            mPrinter->Print({{"property_name", fieldName}, {"type", fieldTypeName}}, Templates::MessagePropertyEmptyInitializerTemplate);
-        }
-    }
-    mPrinter->Print("\n{\n");
-
-    Indent();
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        const FieldDescriptor *field = mMessage->field(i);
-        if (isComplexType(field) || field->is_repeated()) {
-            if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() && !field->is_repeated()) {
-                printField(mMessage, field, Templates::MoveMessageFieldTemplate);
-            } else {
-                printField(mMessage, field, Templates::MoveComplexFieldConstructorTemplate);
-            }
-        } else {
-            if (field->type() != FieldDescriptor::TYPE_ENUM) {
-                printField(mMessage, field, Templates::MoveFieldTemplate);
-            }
-            else {
-                printField(mMessage, field, Templates::EnumMoveFieldTemplate);
-            }
-        }
-    }
-    Outdent();
-    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
-
-    mPrinter->Print({{"classname", mClassName}},
-                    assignmentOperatorTemplate);
-    Indent();
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        const FieldDescriptor *field = mMessage->field(i);
-        if (isComplexType(field) || field->is_repeated()) {
-            if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() && !field->is_repeated()) {
-                printField(mMessage, field, Templates::MoveMessageFieldTemplate);
-            } else {
-                printField(mMessage, field, Templates::MoveComplexFieldTemplate);
-            }
-        } else {
-            if (field->type() != FieldDescriptor::TYPE_ENUM) {
-                printField(mMessage, field, Templates::MoveFieldTemplate);
-            }
-            else {
-                printField(mMessage, field, Templates::EnumMoveFieldTemplate);
-            }
-        }
-    }
-    mPrinter->Print(Templates::AssignmentOperatorReturnTemplate);
-    Outdent();
-    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
-}
-
-void ProtobufSourceGenerator::printComparisonOperators()
-{
-    assert(mMessage != nullptr);
-    if (mMessage->field_count() <= 0) {
-        mPrinter->Print({{"classname", mClassName}}, Templates::EmptyEqualOperatorDefinitionTemplate);
-        mPrinter->Print({{"classname", mClassName}}, Templates::NotEqualOperatorDefinitionTemplate);
-        return;
-    }
-
-    PropertyMap properties;
-    mPrinter->Print({{"classname", mClassName}}, Templates::EqualOperatorDefinitionTemplate);
-
-    bool isFirst = true;
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        const FieldDescriptor *field = mMessage->field(i);
-        if (producePropertyMap(mMessage, field, properties)) {
-            if (!isFirst) {
-                mPrinter->Print("\n&& ");
-            } else {
-                Indent();
-                Indent();
-                isFirst = false;
-            }
-            if (field->type() == FieldDescriptor::TYPE_MESSAGE
-                    && !field->is_map() && !field->is_repeated()) {
-                mPrinter->Print(properties, Templates::EqualOperatorMessagePropertyTemplate);
-            } else {
-                mPrinter->Print(properties, Templates::EqualOperatorPropertyTemplate);
-            }
-        }
-    }
-
-    //Only if at least one field "copied"
-    if (!isFirst) {
-        Outdent();
-        Outdent();
-    }
-
-    mPrinter->Print(";\n");
-    mPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
-
-    mPrinter->Print({{"classname", mClassName}}, Templates::NotEqualOperatorDefinitionTemplate);
-}
-
-void ProtobufSourceGenerator::printGetters()
-{
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        const FieldDescriptor *field = mMessage->field(i);
-        auto propertyMap = common::producePropertyMap(field, mMessage);
-        if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() && !field->is_repeated()) {
-            printField(mMessage, field, Templates::GetterPrivateMessageDefinitionTemplate);
-            printField(mMessage, field, Templates::GetterMessageDefinitionTemplate);
-        }
-        if (field->is_repeated()) {
-            if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map()
-                    && GeneratorOptions::instance().hasQml()) {
-                mPrinter->Print(propertyMap, Templates::GetterQmlListDefinitionTemplate);
-            }
-        }
-    }
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        auto field = mMessage->field(i);
-        switch (field->type()) {
-        case FieldDescriptor::TYPE_MESSAGE:
-            if (!field->is_map() && !field->is_repeated()) {
-                printField(mMessage, field, Templates::SetterPrivateTemplateDefinitionMessageType);
-                printField(mMessage, field, Templates::SetterTemplateDefinitionMessageType);
-            } else {
-                printField(mMessage, field, Templates::SetterTemplateDefinitionComplexType);
-            }
-            break;
-        case FieldDescriptor::FieldDescriptor::TYPE_STRING:
-        case FieldDescriptor::FieldDescriptor::TYPE_BYTES:
-            printField(mMessage, field, Templates::SetterTemplateDefinitionComplexType);
-            break;
-        default:
-            break;
-        }
-    }
-}
-
-void ProtobufSourceGenerator::printDestructor()
-{
-    mPrinter->Print({{"classname", mClassName}}, Templates::RegistrarTemplate);
-    mPrinter->Print({{"classname", mClassName}}, "$classname$::~$classname$()\n"
-                                                 "{}\n\n");
-}
-
-void ProtobufSourceGenerator::printIncludes()
-{
-    std::set<std::string> existingIncludes;
-    for (int i = 0; i < mMessage->field_count(); i++) {
-        printInclude(mMessage, mMessage->field(i), existingIncludes);
-    }
-}

+ 5 - 14
src/generator/servergenerator.cpp → src/generator/serverdeclarationprinter.cpp

@@ -23,26 +23,17 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "servergenerator.h"
+#include "serverdeclarationprinter.h"
 
-#include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/printer.h>
-#include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/descriptor.h>
 
-#include <unordered_set>
-
-#include "utils.h"
-#include "templates.h"
-
 using namespace ::QtProtobuf::generator;
 using namespace ::google::protobuf;
-using namespace ::google::protobuf::compiler;
 
-ServerGenerator::ServerGenerator(const ServiceDescriptor *service, const std::shared_ptr<io::ZeroCopyOutputStream> &out) :
-    ServiceGeneratorBase(service, out)
-  , mService(nullptr)
+ServerDeclarationPrinter::ServerDeclarationPrinter(const ::google::protobuf::ServiceDescriptor *service,
+                                 const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
+    ServiceDeclarationPrinterBase(service, printer)
 {
-    mClassName += "Server";
+    mName += "Server";
 }

+ 5 - 8
src/generator/servergenerator.h → src/generator/serverdeclarationprinter.h

@@ -25,9 +25,8 @@
 
 #pragma once
 
-#include "servicegeneratorbase.h"
+#include "servicedeclarationprinterbase.h"
 #include <string>
-#include <memory>
 #include <google/protobuf/io/printer.h>
 
 namespace google { namespace protobuf {
@@ -41,18 +40,16 @@ namespace generator {
 /*!
  * \ingroup generator
  * \private
- * \brief The ServerGenerator class
+ * \brief The ServerDeclarationPrinter class
  */
-class ServerGenerator : public ServiceGeneratorBase
+class ServerDeclarationPrinter : public ServiceDeclarationPrinterBase
 {
     const google::protobuf::ServiceDescriptor *mService;
 public:
-    ServerGenerator(const google::protobuf::ServiceDescriptor *service, const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out);
-    virtual ~ServerGenerator() = default;
+    ServerDeclarationPrinter(const google::protobuf::ServiceDescriptor *service, const std::shared_ptr<google::protobuf::io::Printer> &printer);
+    virtual ~ServerDeclarationPrinter() = default;
 
     void run() {
-        printDisclaimer();
-        printPreamble();
         printIncludes();
         printNamespaces();
         printClassName();

+ 12 - 21
src/generator/servicegeneratorbase.cpp → src/generator/servicedeclarationprinterbase.cpp

@@ -23,7 +23,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "servicegeneratorbase.h"
+#include "servicedeclarationprinterbase.h"
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
@@ -41,25 +41,17 @@ using namespace ::google::protobuf;
 using namespace ::google::protobuf::compiler;
 using namespace QtProtobuf::generator;
 
-ServiceGeneratorBase::ServiceGeneratorBase(const ::google::protobuf::ServiceDescriptor *service,
-                                           const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out) :
-    ClassGeneratorBase(service->full_name(), out)
-  , mService(service)
-{
-}
-
-ServiceGeneratorBase::ServiceGeneratorBase(const ::google::protobuf::ServiceDescriptor *service,
+ServiceDeclarationPrinterBase::ServiceDeclarationPrinterBase(const ::google::protobuf::ServiceDescriptor *service,
                 const std::shared_ptr<::google::protobuf::io::Printer> &printer) :
-    ClassGeneratorBase(service->full_name(), printer)
-  , mService(service)
+    DescriptorPrinterBase<::google::protobuf::ServiceDescriptor>(service, printer)
 {}
 
-void ServiceGeneratorBase::printIncludes()
+void ServiceDeclarationPrinterBase::printIncludes()
 {
     std::unordered_set<std::string> includeSet;
 
-    for (int i = 0; i < mService->method_count(); i++) {
-        const MethodDescriptor *method = mService->method(i);
+    for (int i = 0; i < mDescriptor->method_count(); i++) {
+        const MethodDescriptor *method = mDescriptor->method(i);
         std::string inputTypeName = method->input_type()->name();
         std::string outputTypeName = method->output_type()->name();
         utils::tolower(inputTypeName);
@@ -73,18 +65,17 @@ void ServiceGeneratorBase::printIncludes()
     }
 }
 
-void ServiceGeneratorBase::printClassName()
+void ServiceDeclarationPrinterBase::printClassName()
 {
-    mPrinter->Print({{"classname", mClassName}}, Templates::NonProtoClassDefinitionTemplate);
+    mPrinter->Print({{"classname", mName}}, Templates::ClassDeclarationTemplate);
 }
 
-void ServiceGeneratorBase::printMethodsDeclaration(const char *methodTemplate, const char *methodAsyncTemplate, const char *methodAsync2Template)
+void ServiceDeclarationPrinterBase::printMethodsDeclaration(const char *methodTemplate, const char *methodAsyncTemplate, const char *methodAsync2Template)
 {
     Indent();
-    for (int i = 0; i < mService->method_count(); i++) {
-        const MethodDescriptor *method = mService->method(i);
-        std::map<std::string, std::string> parameters;
-        getMethodParameters(method, parameters);
+    for (int i = 0; i < mDescriptor->method_count(); i++) {
+        const MethodDescriptor *method = mDescriptor->method(i);
+        std::map<std::string, std::string> parameters = common::produceMethodMap(method, mName);
         mPrinter->Print(parameters, methodTemplate);
         mPrinter->Print(parameters, methodAsyncTemplate);
         mPrinter->Print(parameters, methodAsync2Template);

+ 5 - 12
src/generator/servicegeneratorbase.h → src/generator/servicedeclarationprinterbase.h

@@ -25,7 +25,7 @@
 
 #pragma once
 
-#include "classgeneratorbase.h"
+#include "descriptorprinterbase.h"
 #include <string>
 #include <memory>
 #include <google/protobuf/io/printer.h>
@@ -41,21 +41,14 @@ namespace generator {
 /*!
  * \ingroup generator
  * \private
- * \brief The ServiceGeneratorBase class
+ * \brief The ServiceDeclarationPrinterBase class
  */
-class ServiceGeneratorBase : public ClassGeneratorBase
+class ServiceDeclarationPrinterBase : public DescriptorPrinterBase<::google::protobuf::ServiceDescriptor>
 {
-protected:
-    const ::google::protobuf::ServiceDescriptor *mService;
-
 public:
-    ServiceGeneratorBase(const ::google::protobuf::ServiceDescriptor *service,
-                         const std::shared_ptr<google::protobuf::io::ZeroCopyOutputStream> &out);
-    ServiceGeneratorBase(const ::google::protobuf::ServiceDescriptor *service,
+    ServiceDeclarationPrinterBase(const ::google::protobuf::ServiceDescriptor *service,
                     const std::shared_ptr<::google::protobuf::io::Printer> &printer);
-    void run() = 0;
-
-    void printIncludes();
+    void printIncludes();//TODO: refactoring
     void printClassName();
     void printMethodsDeclaration(const char *methodTemplate, const char *methodAsyncTemplate = "", const char *methodAsync2Template = "");
 };

+ 68 - 101
src/generator/singlefilegenerator.cpp

@@ -24,15 +24,15 @@
  */
 
 #include "singlefilegenerator.h"
+#include "messagedeclarationprinter.h"
+#include "messagedefinitionprinter.h"
+#include "enumdeclarationprinter.h"
+#include "enumdefinitionprinter.h"
+#include "serverdeclarationprinter.h"
+#include "clientdeclarationprinter.h"
+#include "clientdefinitionprinter.h"
+
 #include "templates.h"
-#include "classgeneratorbase.h"
-#include "protobufclassgenerator.h"
-#include "protobufsourcegenerator.h"
-#include "enumsgenerator.h"
-#include "enumssourcegenerator.h"
-#include "servergenerator.h"
-#include "clientgenerator.h"
-#include "clientsourcegenerator.h"
 #include "utils.h"
 #include "generatoroptions.h"
 
@@ -73,24 +73,26 @@ bool SingleFileGenerator::GenerateMessages(const ::google::protobuf::FileDescrip
         return true;
     }
 
-    std::string outFileBasename = generateBaseName(file, utils::extractFileBasename(file->name()));
     std::set<std::string> internalIncludes;
     std::set<std::string> externalIncludes;
-    std::shared_ptr<io::ZeroCopyOutputStream> outHeader(generatorContext->Open(outFileBasename + Templates::ProtoFileSuffix + ".h"));
-    std::shared_ptr<io::ZeroCopyOutputStream> outSource(generatorContext->Open(outFileBasename + Templates::ProtoFileSuffix + ".cpp"));
-    std::shared_ptr<::google::protobuf::io::Printer> outHeaderPrinter(new ::google::protobuf::io::Printer(outHeader.get(), '$'));
-    std::shared_ptr<::google::protobuf::io::Printer> outSourcePrinter(new ::google::protobuf::io::Printer(outSource.get(), '$'));
 
+    std::string basename = generateBaseName(file, utils::extractFileBasename(file->name()));
+    std::unique_ptr<io::ZeroCopyOutputStream> headerStream(generatorContext->Open(basename + Templates::ProtoFileSuffix + ".h"));
+    std::unique_ptr<io::ZeroCopyOutputStream> sourceStream(generatorContext->Open(basename + Templates::ProtoFileSuffix + ".cpp"));
+
+    std::shared_ptr<::google::protobuf::io::Printer> headerPrinter(new ::google::protobuf::io::Printer(headerStream.get(), '$'));
+    std::shared_ptr<::google::protobuf::io::Printer> sourcePrinter(new ::google::protobuf::io::Printer(sourceStream.get(), '$'));
+
+    printDisclaimer(headerPrinter);
+    printPreamble(headerPrinter);
 
-    outHeaderPrinter->Print(Templates::DisclaimerTemplate);
-    outHeaderPrinter->Print(Templates::PreambleTemplate);
-    outHeaderPrinter->Print(Templates::DefaultProtobufIncludesTemplate);
+    headerPrinter->Print(Templates::DefaultProtobufIncludesTemplate);
     if (GeneratorOptions::instance().hasQml()) {
-        outHeaderPrinter->Print(Templates::QmlProtobufIncludesTemplate);
+        headerPrinter->Print(Templates::QmlProtobufIncludesTemplate);
     }
 
-    outSourcePrinter->Print(Templates::DisclaimerTemplate);
-    outSourcePrinter->Print({{"include", outFileBasename + Templates::ProtoFileSuffix}}, Templates::InternalIncludeTemplate);
+    printDisclaimer(sourcePrinter);
+    sourcePrinter->Print({{"include", basename + Templates::ProtoFileSuffix}}, Templates::InternalIncludeTemplate);
 
     externalIncludes.insert("QByteArray");
     externalIncludes.insert("QString");
@@ -99,34 +101,28 @@ bool SingleFileGenerator::GenerateMessages(const ::google::protobuf::FileDescrip
         internalIncludes.insert(utils::removeFileSuffix(file->dependency(i)->name()) + Templates::ProtoFileSuffix);
     }
 
-    for(auto include : externalIncludes) {
-        outHeaderPrinter->Print({{"include", include}}, Templates::ExternalIncludeTemplate);
+    for (auto include : externalIncludes) {
+        headerPrinter->Print({{"include", include}}, Templates::ExternalIncludeTemplate);
     }
 
-    for(auto include : internalIncludes) {
-        outHeaderPrinter->Print({{"include", include}}, Templates::InternalIncludeTemplate);
+    for (auto include : internalIncludes) {
+        headerPrinter->Print({{"include", include}}, Templates::InternalIncludeTemplate);
     }
 
     if (GeneratorOptions::instance().hasQml()) {
-        outSourcePrinter->Print({{"include", "QQmlEngine"}}, Templates::ExternalIncludeTemplate);
+        sourcePrinter->Print({{"include", "QQmlEngine"}}, Templates::ExternalIncludeTemplate);
     }
-    outSourcePrinter->Print({{"namespace", "QtProtobuf"}}, Templates::UsingNamespaceTemplate);
 
+    printQtProtobufUsingNamespace(sourcePrinter);
 
     PackagesList packageList;
     packageList[file->package()].push_back(file);
 
-    for(int i = 0; i < file->enum_type_count(); i++) {
-        EnumsGenerator enumGen2(file->enum_type(i),
-                                outHeaderPrinter);
-        enumGen2.run();
-    }
-
-    for(int i = 0; i < file->enum_type_count(); i++) {
-        auto enumType = file->enum_type(i);
-        EnumsSourceGenerator enumSourceGen2(enumType,
-                                outSourcePrinter);
-        enumSourceGen2.run();
+    for (int i = 0; i < file->enum_type_count(); i++) {
+        EnumDeclarationPrinter enumDecl(file->enum_type(i), headerPrinter);
+        enumDecl.run();
+        EnumDefinitionPrinter enumSourceDef(file->enum_type(i), sourcePrinter);
+        enumSourceDef.run();
     }
 
     std::vector<std::string> namespaces = utils::split(file->package(), '.');
@@ -138,44 +134,26 @@ bool SingleFileGenerator::GenerateMessages(const ::google::protobuf::FileDescrip
             namespacesColonDelimited = namespacesColonDelimited.append("::");
         }
         namespacesColonDelimited = namespacesColonDelimited.append(namespaces[i]);
-        outHeaderPrinter->Print({{"namespace", namespaces[i]}}, Templates::NamespaceTemplate);
+        headerPrinter->Print({{"namespace", namespaces[i]}}, Templates::NamespaceTemplate);
     }
 
-    iterateNonNestedFileds(file, [&outHeaderPrinter](const ::google::protobuf::Descriptor *message){
+    iterateNonNestedFileds(file, [&headerPrinter](const ::google::protobuf::Descriptor *message){
         std::string qualifiedClassName = utils::upperCaseName(message->name());
-        outHeaderPrinter->Print({{"classname", qualifiedClassName}}, Templates::ProtoClassDeclarationTemplate);
-        outHeaderPrinter->Print({{"classname", qualifiedClassName}}, Templates::ComplexListTypeUsingTemplate);
+        headerPrinter->Print({{"classname", qualifiedClassName}}, Templates::ProtoClassDeclarationTemplate);
+        headerPrinter->Print({{"classname", qualifiedClassName}}, Templates::ComplexListTypeUsingTemplate);
     });
 
     for (size_t i = 0; i < namespaces.size(); i++) {
-        outHeaderPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
+        headerPrinter->Print(Templates::SimpleBlockEnclosureTemplate);
     }
 
-    iterateNonNestedFileds(file, [&outHeaderPrinter, &outSourcePrinter](const ::google::protobuf::Descriptor *message){
-        ProtobufClassGenerator classGen(message,
-                                        outHeaderPrinter);
-
-        classGen.printNamespaces();
-        classGen.printComments(message);
-        classGen.printClassDeclaration();
-        classGen.printClassBody();
-        classGen.encloseClass();
-        classGen.encloseNamespaces();
-        classGen.printMetaTypesDeclaration();
-
-        ProtobufSourceGenerator srcGen(message,
-                                       outSourcePrinter);
-        srcGen.printNamespaces();
-        srcGen.printFieldsOrdering();
-        srcGen.printRegisterBody();
-        srcGen.printDestructor();
-        srcGen.printConstructor();
-        srcGen.printCopyFunctionality();
-        srcGen.printMoveSemantic();
-        srcGen.printComparisonOperators();
-        srcGen.printGetters();
-        srcGen.encloseNamespaces();
+    iterateNonNestedFileds(file, [&headerPrinter, &sourcePrinter](const ::google::protobuf::Descriptor *message){
+        MessageDeclarationPrinter messageDecl(message, headerPrinter);
 
+        messageDecl.run();
+
+        MessageDefinitionPrinter messageDef(message, sourcePrinter);
+        messageDef.run();
     });
 
     return true;
@@ -191,23 +169,24 @@ bool SingleFileGenerator::GenerateServices(const ::google::protobuf::FileDescrip
         return true;
     }
 
-    std::string outFileBasename = generateBaseName(file, utils::extractFileBasename(file->name()));
     std::set<std::string> internalIncludes;
     std::set<std::string> externalIncludes;
-    std::shared_ptr<io::ZeroCopyOutputStream> outHeader(generatorContext->Open(outFileBasename + Templates::GrpcFileSuffix + Templates::ProtoFileSuffix + ".h"));
-    std::shared_ptr<io::ZeroCopyOutputStream> outSource(generatorContext->Open(outFileBasename + Templates::GrpcFileSuffix + Templates::ProtoFileSuffix + ".cpp"));
-    std::shared_ptr<::google::protobuf::io::Printer> outHeaderPrinter(new ::google::protobuf::io::Printer(outHeader.get(), '$'));
-    std::shared_ptr<::google::protobuf::io::Printer> outSourcePrinter(new ::google::protobuf::io::Printer(outSource.get(), '$'));
-
-    outHeaderPrinter->Print(Templates::DisclaimerTemplate);
-    outHeaderPrinter->Print(Templates::PreambleTemplate);
-    outHeaderPrinter->Print(Templates::DefaultProtobufIncludesTemplate);
+
+    std::string basename = generateBaseName(file, utils::extractFileBasename(file->name()));
+    std::unique_ptr<io::ZeroCopyOutputStream> headerStream(generatorContext->Open(basename + Templates::GrpcFileSuffix + Templates::ProtoFileSuffix + ".h"));
+    std::unique_ptr<io::ZeroCopyOutputStream> sourceStream(generatorContext->Open(basename + Templates::GrpcFileSuffix + Templates::ProtoFileSuffix + ".cpp"));
+    std::shared_ptr<::google::protobuf::io::Printer> headerPrinter(new ::google::protobuf::io::Printer(headerStream.get(), '$'));
+    std::shared_ptr<::google::protobuf::io::Printer> sourcePrinter(new ::google::protobuf::io::Printer(sourceStream.get(), '$'));
+
+    printDisclaimer(headerPrinter);
+    printPreamble(headerPrinter);
+    headerPrinter->Print(Templates::DefaultProtobufIncludesTemplate);
     if (GeneratorOptions::instance().hasQml()) {
-        outHeaderPrinter->Print(Templates::QmlProtobufIncludesTemplate);
+        headerPrinter->Print(Templates::QmlProtobufIncludesTemplate);
     }
 
-    outSourcePrinter->Print(Templates::DisclaimerTemplate);
-    outSourcePrinter->Print({{"include", outFileBasename + Templates::GrpcFileSuffix + Templates::ProtoFileSuffix}}, Templates::InternalIncludeTemplate);
+    printDisclaimer(sourcePrinter);
+    sourcePrinter->Print({{"include", basename + Templates::GrpcFileSuffix + Templates::ProtoFileSuffix}}, Templates::InternalIncludeTemplate);
 
     for (int i = 0; i < file->service_count(); i++) {
         const ServiceDescriptor *service = file->service(i);
@@ -228,18 +207,17 @@ bool SingleFileGenerator::GenerateServices(const ::google::protobuf::FileDescrip
     externalIncludes.insert("QGrpcSubscription");
 
     if (file->message_type_count() > 0) {
-        internalIncludes.insert(outFileBasename + Templates::ProtoFileSuffix);
+        internalIncludes.insert(basename + Templates::ProtoFileSuffix);
     }
-    for(auto include : externalIncludes) {
-        outHeaderPrinter->Print({{"include", include}}, Templates::ExternalIncludeTemplate);
+    for (auto include : externalIncludes) {
+        headerPrinter->Print({{"include", include}}, Templates::ExternalIncludeTemplate);
     }
 
-    for(auto include : internalIncludes) {
-        outHeaderPrinter->Print({{"include", include}}, Templates::InternalIncludeTemplate);
+    for (auto include : internalIncludes) {
+        headerPrinter->Print({{"include", include}}, Templates::InternalIncludeTemplate);
     }
 
-
-    outSourcePrinter->Print({{"namespace", "QtProtobuf"}}, Templates::UsingNamespaceTemplate);
+    printQtProtobufUsingNamespace(sourcePrinter);
 
     for (int i = 0; i < file->service_count(); i++) {
         const ServiceDescriptor *service = file->service(i);
@@ -248,26 +226,15 @@ bool SingleFileGenerator::GenerateServices(const ::google::protobuf::FileDescrip
         //        utils::tolower(baseFilename);
 
         //        std::string fullFilename = baseFilename + "server.h";
-        //        ServerGenerator serverGen(service,
+        //        ServerDeclarationprinter serverGen(service,
         //                                  std::shared_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(fullFilename)));
         //        serverGen.run();
 
-        ClientGenerator clientGen(service,
-                                  outHeaderPrinter);
-        clientGen.printNamespaces();
-        clientGen.printClientClass();
-        clientGen.printPublicBlock();
-        clientGen.printConstructor();
-        clientGen.printClientMethodsDeclaration();
-        clientGen.encloseClass();
-        clientGen.encloseNamespaces();
-
-        ClientSourceGenerator clientSrcGen(service,
-                                           outSourcePrinter);
-        clientSrcGen.printNamespaces();
-        clientSrcGen.printConstructor();
-        clientSrcGen.printMethods();
-        clientSrcGen.encloseNamespaces();
+        ClientDeclarationPrinter clientDecl(service, headerPrinter);
+        clientDecl.run();
+
+        ClientDefinitionPrinter clientDef(service, sourcePrinter);
+        clientDef.run();
     }
 
     return true;

+ 32 - 22
src/generator/templates.cpp

@@ -60,18 +60,18 @@ const char *Templates::ManualRegistrationComplexTypeDefinition = "void $type$::r
                                                                  "    qRegisterMetaType<$type$>(\"$full_type$\");\n"
                                                                  "    qRegisterMetaType<$list_type$>(\"$full_list_type$\");\n"
                                                                  "";
-const char *Templates::ManualRegistrationGlobalEnumDefinition = "void $classname$::registerTypes()\n{\n"
+const char *Templates::ManualRegistrationGlobalEnumDefinition = "void $enum_gadget$::registerTypes()\n{\n"
                                                                  "";
-const char *Templates::ComplexGlobalEnumFieldRegistrationTemplate = "qRegisterMetaType<$classname$::$enum$>(\"$namespaces$::$classname$::$enum$\");\n";
+const char *Templates::ComplexGlobalEnumFieldRegistrationTemplate = "qRegisterMetaType<$type$>(\"$full_type$\");\n";
 const char *Templates::ComplexListTypeUsingTemplate = "using $classname$Repeated = QList<QSharedPointer<$classname$>>;\n";
 const char *Templates::MapTypeUsingTemplate = "using $type$ = QMap<$key_type$, $value_type$>;\n";
 const char *Templates::MessageMapTypeUsingTemplate = "using $type$ = QMap<$key_type$, QSharedPointer<$value_type$>>;\n";
 
-const char *Templates::EnumTypeRepeatedTemplate = "using $enum$Repeated = QList<$enum$>;\n";
+const char *Templates::EnumTypeRepeatedTemplate = "using $list_type$ = QList<$type$>;\n";
 
-const char *Templates::NamespaceTemplate = "\nnamespace $namespace$ {\n";
+const char *Templates::NamespaceTemplate = "namespace $namespace$ {\n";
 const char *Templates::UsingNamespaceTemplate = "using namespace $namespace$;\n";
-const char *Templates::NonProtoClassDefinitionTemplate = "\nclass $classname$ : public QObject\n"
+const char *Templates::ClassDeclarationTemplate = "\nclass $classname$ : public QObject\n"
                                                          "{\n"
                                                          "    Q_OBJECT\n";
 const char *Templates::ProtoClassDeclarationTemplate = "class $classname$;\n";
@@ -99,11 +99,13 @@ const char *Templates::ListMemberTemplate = "$scope_list_type$ m_$property_name$
 const char *Templates::ComplexMemberTemplate = "std::unique_ptr<$scope_type$> m_$property_name$;\n";
 const char *Templates::PublicBlockTemplate = "\npublic:\n";
 const char *Templates::PrivateBlockTemplate = "\nprivate:\n";
-const char *Templates::EnumDefinitionTemplate = "enum $enum$ {\n";
+const char *Templates::EnumDefinitionTemplate = "enum $type$ {\n";
 const char *Templates::EnumFieldTemplate = "$enumvalue$ = $value$,\n";
 
 
-const char *Templates::ProtoConstructorDefinitionTemplate = "$classname$::$classname$($parameter_list$QObject *parent) : QObject(parent)";
+const char *Templates::ProtoConstructorDefinitionBeginTemplate = "$type$::$type$(";
+const char *Templates::ProtoConstructorDefinitionEndTemplate = "QObject *parent) : QObject(parent)";
+
 const char *Templates::ConstructorTemplate = "$classname$();\n";
 const char *Templates::QObjectConstructorTemplate = "explicit $classname$(QObject *parent = nullptr);\n";
 const char *Templates::ConstructorHeaderTemplate = "$classname$() {}\n";
@@ -158,12 +160,12 @@ const char *Templates::NotEqualOperatorDefinitionTemplate = "bool $classname$::o
                                                   "}\n\n";
 
 const char *Templates::GetterPrivateMessageDeclarationTemplate = "$getter_type$ *$property_name$_p() const;\n";
-const char *Templates::GetterPrivateMessageDefinitionTemplate = "$type$ *$classname$::$property_name$_p() const\n{\n"
+const char *Templates::GetterPrivateMessageDefinitionTemplate = "$getter_type$ *$classname$::$property_name$_p() const\n{\n"
                                         "    return m_$property_name$.get();\n"
                                         "}\n\n";
 
 const char *Templates::GetterMessageDeclarationTemplate = "const $getter_type$ &$property_name$() const;\n";
-const char *Templates::GetterMessageDefinitionTemplate = "const $type$ &$classname$::$property_name$() const\n{\n"
+const char *Templates::GetterMessageDefinitionTemplate = "const $getter_type$ &$classname$::$property_name$() const\n{\n"
                                         "    return *m_$property_name$;\n"
                                         "}\n\n";
 
@@ -185,7 +187,7 @@ const char *Templates::GetterQmlListDefinitionTemplate = "QQmlListProperty<$full
                                                "}\n\n";
 
 const char *Templates::SetterPrivateTemplateDeclarationMessageType = "void set$property_name_cap$_p($setter_type$ *$property_name$);\n";
-const char *Templates::SetterPrivateTemplateDefinitionMessageType = "void $classname$::set$property_name_cap$_p($type$ *$property_name$)\n{\n"
+const char *Templates::SetterPrivateTemplateDefinitionMessageType = "void $classname$::set$property_name_cap$_p($setter_type$ *$property_name$)\n{\n"
                                                    "    if ($property_name$ == nullptr) {\n"
                                                    "        *m_$property_name$ = {};\n"
                                                    "        return;\n"
@@ -199,7 +201,7 @@ const char *Templates::SetterPrivateTemplateDefinitionMessageType = "void $class
                                                    "}\n\n";
 
 const char *Templates::SetterTemplateDeclarationMessageType = "void set$property_name_cap$(const $setter_type$ &$property_name$);\n";
-const char *Templates::SetterTemplateDefinitionMessageType = "void $classname$::set$property_name_cap$(const $type$ &$property_name$)\n{\n"
+const char *Templates::SetterTemplateDefinitionMessageType = "void $classname$::set$property_name_cap$(const $setter_type$ &$property_name$)\n{\n"
                                                    "    if (*m_$property_name$ != $property_name$) {\n"
                                                    "        *m_$property_name$ = $property_name$;\n"
                                                    "        $property_name$Changed();\n"
@@ -207,7 +209,7 @@ const char *Templates::SetterTemplateDefinitionMessageType = "void $classname$::
                                                    "}\n\n";
 
 const char *Templates::SetterTemplateDeclarationComplexType = "void set$property_name_cap$(const $setter_type$ &$property_name$);\n";
-const char *Templates::SetterTemplateDefinitionComplexType = "void $classname$::set$property_name_cap$(const $type$ &$property_name$)\n{\n"
+const char *Templates::SetterTemplateDefinitionComplexType = "void $classname$::set$property_name_cap$(const $setter_type$ &$property_name$)\n{\n"
                                                    "    if (m_$property_name$ != $property_name$) {\n"
                                                    "        m_$property_name$ = $property_name$;\n"
                                                    "        $property_name$Changed();\n"
@@ -236,13 +238,13 @@ const char *Templates::FieldOrderTemplate = "{$field_number$, $property_number$}
 
 const char *Templates::EnumTemplate = "$type$";
 
-const char *Templates::SimpleBlockEnclosureTemplate = "}\n\n";
+const char *Templates::SimpleBlockEnclosureTemplate = "}\n";
 const char *Templates::SemicolonBlockEnclosureTemplate = "};\n";
 const char *Templates::EmptyBlockTemplate = "{}\n\n";
 const char *Templates::PropertyInitializerTemplate = "\n    , m_$property_name$($property_name$)";
-const char *Templates::PropertyEmptyInitializerTemplate = "\n    , m_$property_name$($initializer$)";
-const char *Templates::MessagePropertyInitializerTemplate = "\n    , m_$property_name$(new $type$($property_name$))";
-const char *Templates::MessagePropertyEmptyInitializerTemplate = "\n    , m_$property_name$(new $type$)";
+const char *Templates::PropertyDefaultInitializerTemplate = "\n    , m_$property_name$($initializer$)";
+const char *Templates::MessagePropertyInitializerTemplate = "\n    , m_$property_name$(new $scope_type$($property_name$))";
+const char *Templates::MessagePropertyDefaultInitializerTemplate = "\n    , m_$property_name$(new $scope_type$)";
 const char *Templates::ConstructorContentTemplate = "\n{\n}\n";
 
 const char *Templates::DeclareMetaTypeTemplate = "Q_DECLARE_METATYPE($full_type$)\n";
@@ -258,16 +260,23 @@ const char *Templates::DeclareMetaTypeMapTemplate = "#ifndef Q_PROTOBUF_MAP_$key
                                                     "Q_DECLARE_METATYPE($full_type$)\n"
                                                     "#endif\n";
 
-const char *Templates::RegisterMetaTypeDefaultTemplate = "qRegisterMetaType<$namespaces$::$type$>();\n";
+
+const char *Templates::RegisterLocalEnumTemplate = "qRegisterProtobufEnumType<$scope_type$>();\n"
+                                                   "qRegisterMetaType<$scope_type$>(\"$type$\");\n"
+                                                   "qRegisterMetaType<$scope_list_type$>(\"$full_type$\");\n"
+                                                   "qRegisterMetaType<$scope_list_type$>(\"$full_list_type$\");\n";
+const char *Templates::RegisterMapTemplate = "qRegisterMetaType<$scope_type$>(\"$full_type$\");\n"
+                                             "qRegisterMetaType<$scope_type$>(\"$full_list_type$\");\n"
+                                             "qRegisterProtobufMapType<$key_type$, $value_type$>();\n";
+
 const char *Templates::RegisterMetaTypeTemplateNoNamespace = "qRegisterMetaType<$namespaces$::$type$>(\"$type$\");\n";
 const char *Templates::RegisterMetaTypeTemplate = "qRegisterMetaType<$namespaces$::$type$>(\"$namespaces$::$type$\");\n";
+const char *Templates::RegisterGlobalEnumMetaTypeTemplate = "qRegisterMetaType<$full_type$>(\"$full_type$\");\n";
 const char *Templates::RegisterQmlListPropertyMetaTypeTemplate = "qRegisterMetaType<QQmlListProperty<$full_type$>>(\"QQmlListProperty<$full_type$>\");\n";
 
 
 const char *Templates::QEnumTemplate = "Q_ENUM($type$)\n";
 
-const char *Templates::MapSerializationRegisterTemplate = "qRegisterProtobufMapType<$key_type$, $value_type$>();\n";
-
 const char *Templates::ClassDefinitionTemplate = "\nclass $classname$ : public $parent_class$\n"
                                                  "{\n";
 const char *Templates::QObjectMacro = "Q_OBJECT";
@@ -297,11 +306,12 @@ const char *Templates::ClientMethodDefinitionAsync2Template = "\nvoid $classname
                                                               "}\n";
 
 const char *Templates::RegisterSerializersTemplate = "qRegisterProtobufType<$classname$>();\n";
-const char *Templates::RegisterEnumSerializersTemplate = "qRegisterProtobufEnumType<$type$>();\n";
+const char *Templates::RegisterEnumSerializersTemplate = "qRegisterProtobufEnumType<$full_type$>();\n";
 const char *Templates::RegistrarTemplate = "static QtProtobuf::ProtoTypeRegistrar<$classname$> ProtoTypeRegistrar$classname$(qRegisterProtobufType<$classname$>);\n";
-const char *Templates::EnumRegistrarTemplate = "static QtProtobuf::ProtoTypeRegistrar<$classname$> ProtoTypeRegistrar$classname$($classname$::registerTypes);\n";
+const char *Templates::EnumRegistrarTemplate = "static QtProtobuf::ProtoTypeRegistrar<$enum_gadget$> ProtoTypeRegistrar$enum_gadget$($enum_gadget$::registerTypes);\n";
 const char *Templates::QmlRegisterTypeTemplate = "qmlRegisterType<$full_type$>(\"$qml_package$\", 1, 0, \"$type$\");\n";
-const char *Templates::QmlRegisterTypeUncreatableTemplate = "qmlRegisterUncreatableType<$namespaces$::$classname$>(\"$package$\", 1, 0, \"$classname$\", \"$namespaces$::$classname$ Could not be created from qml context\");\n";
+const char *Templates::QmlRegisterTypeUncreatableTemplate = "qmlRegisterUncreatableType<$full_name$>(\"$qml_package$\", 1, 0, \"$type$\", \"$full_type$ Could not be created from qml context\");\n";
+const char *Templates::QmlRegisterEnumTypeTemplate = "qmlRegisterUncreatableType<$enum_gadget$>(\"$qml_package$\", 1, 0, \"$type$\", \"$full_type$ Could not be created from qml context\");\n";
 
 
 const char *Templates::ClientMethodSignalDeclarationTemplate = "Q_SIGNAL void $method_name$Updated(const $return_type$ &);\n";

+ 10 - 6
src/generator/templates.h

@@ -60,7 +60,7 @@ public:
     static const char *EnumTypeRepeatedTemplate;
     static const char *NamespaceTemplate;
     static const char *UsingNamespaceTemplate;
-    static const char *NonProtoClassDefinitionTemplate;
+    static const char *ClassDeclarationTemplate;
     static const char *ProtoClassDeclarationTemplate;
     static const char *ProtoClassDefinitionTemplate;
     static const char *ConstructorHeaderTemplate;
@@ -83,7 +83,9 @@ public:
     static const char *ConstructorParameterDefinitionTemplate;
     static const char *ConstructorMessageParameterDefinitionTemplate;
     static const char *ConstructorRepeatedParameterDefinitionTemplate;
-    static const char *ProtoConstructorDefinitionTemplate;
+
+    static const char *ProtoConstructorDefinitionBeginTemplate;
+    static const char *ProtoConstructorDefinitionEndTemplate;
 
     static const char *MemberTemplate;
     static const char *ListMemberTemplate;
@@ -150,9 +152,9 @@ public:
     static const char *SemicolonBlockEnclosureTemplate;
     static const char *EmptyBlockTemplate;
     static const char *PropertyInitializerTemplate;
-    static const char *PropertyEmptyInitializerTemplate;
+    static const char *PropertyDefaultInitializerTemplate;
     static const char *MessagePropertyInitializerTemplate;
-    static const char *MessagePropertyEmptyInitializerTemplate;
+    static const char *MessagePropertyDefaultInitializerTemplate;
     static const char *ConstructorContentTemplate;
     static const char *DeclareMetaTypeTemplate;
     static const char *DeclareMetaTypeListTemplate;
@@ -160,18 +162,20 @@ public:
     static const char *DeclareComplexListTypeTemplate;
     static const char *DeclareComplexQmlListTypeTemplate;
     static const char *DeclareMetaTypeMapTemplate;
-    static const char *RegisterMetaTypeDefaultTemplate;
+    static const char *RegisterLocalEnumTemplate;
+    static const char *RegisterMapTemplate;
     static const char *RegisterMetaTypeTemplate;
+    static const char *RegisterGlobalEnumMetaTypeTemplate;
     static const char *RegisterMetaTypeTemplateNoNamespace;
     static const char *RegisterQmlListPropertyMetaTypeTemplate;
     static const char *QEnumTemplate;
-    static const char *MapSerializationRegisterTemplate;
     static const char *RegisterSerializersTemplate;
     static const char *RegisterEnumSerializersTemplate;
     static const char *RegistrarTemplate;
     static const char *EnumRegistrarTemplate;
     static const char *QmlRegisterTypeTemplate;
     static const char *QmlRegisterTypeUncreatableTemplate;
+    static const char *QmlRegisterEnumTypeTemplate;
     //Service templates
     static const char *ClientConstructorDefinitionTemplate;
 

+ 1 - 1
src/protobuf/qprotobufserializer_p.h

@@ -375,7 +375,7 @@ public:
         qProtoDebug() << __func__ << "currentByte:" << QString::number((*it), 16);
 
         unsigned int length = deserializeVarintCommon<uint32>(it);
-        QByteArray result((QByteArray::const_iterator&)it, length); //TODO: it's possible to void buffeer copying by setupimg new "end of QByteArray";
+        QByteArray result((QByteArray::const_iterator&)it, length); //TODO: it's possible to avoid buffer copying by setuping new "end of QByteArray";
         it += length;
         return result;
     }

+ 1 - 1
src/protobuf/qt_lib_protobuf.pri.in

@@ -16,7 +16,7 @@ defineTest(qtprotobuf_generate) {
     QML_ENABLED = $$1
     $$QML_ENABLED:GENERATOR_OPTIONS="$$GENERATOR_OPTIONS:QML"
 
-    for(PROTO_FILE_REL, PROTO_FILES) {
+    for (PROTO_FILE_REL, PROTO_FILES) {
         PROTO_FILE_ABS = $$absolute_path($$PROTO_FILE_REL)
         PROTO_FILES_PRIV *= $$PROTO_FILE_ABS
         PROTO_INCLUDES_PRIV = "$$PROTO_INCLUDES_PRIV -I$$dirname(PROTO_FILE_ABS)"