Browse Source

Add common support library for generated files

- Add UniversalListModel to support repeating fields
- Update install rules
Alexey Edelev 6 years ago
parent
commit
256e1ad84f

+ 2 - 0
CMakeLists.txt

@@ -4,6 +4,8 @@ project(qtprotobuf)
 
 find_package(Protobuf)
 
+add_subdirectory("src/lib")
+
 add_executable(${PROJECT_NAME} "src/generator/main.cpp" "src/generator/generator.cpp"
     "src/generator/classgeneratorbase.cpp")
 target_link_libraries(${PROJECT_NAME} ${Protobuf_LIBRARIES} "-lprotoc")

+ 46 - 46
src/generator/classgeneratorbase.cpp

@@ -182,14 +182,14 @@ std::string ClassGeneratorBase::getTypeName(const FieldDescriptor* field)
             typeName = field->enum_type()->name();
         }
     } else {
-            auto it = TypeReflection.find(field->type());
-            if (it != std::end(TypeReflection)) {
-                if (field->is_repeated()) {
-                    typeName = std::string("QVariantList");
-                } else {
-                    typeName = it->second;
-                }
+        auto it = TypeReflection.find(field->type());
+        if (it != std::end(TypeReflection)) {
+            if (field->is_repeated()) {
+                typeName = std::string("QVariantList");
+            } else {
+                typeName = it->second;
             }
+        }
     }
 
 
@@ -203,45 +203,45 @@ void ClassGeneratorBase::printConstructor()
 
     //FIXME: Explicit default values are not allowed in proto3 seems
     //this function is useless
-//    for (int i = 0; i < mMessage->field_count(); i++) {
-//        const FieldDescriptor* field = mMessage->field(i);
-//        std::string defaultValue;
-//        if (field->has_default_value()) {
-//            switch (field->type()) {
-//            case FieldDescriptor::TYPE_DOUBLE:
-//                defaultValue = std::to_string(field->default_value_double());
-//                break;
-//            case FieldDescriptor::TYPE_FLOAT:
-//                defaultValue = std::to_string(field->default_value_float());
-//                break;
-//            case FieldDescriptor::TYPE_INT32:
-//            case FieldDescriptor::TYPE_UINT32:
-//            case FieldDescriptor::TYPE_SFIXED32:
-//            case FieldDescriptor::TYPE_SINT32:
-//                defaultValue = std::to_string(field->default_value_int32());
-//                break;
-//            case FieldDescriptor::TYPE_BOOL:
-//                defaultValue = field->default_value_bool() ? "true" : "false";
-//                break;
-//            case FieldDescriptor::TYPE_STRING:
-//                defaultValue = field->default_value_string();
-//                break;
-//            case FieldDescriptor::TYPE_ENUM:
-//                defaultValue = field->default_value_enum()->name();
-//                break;
-//            default:
-//                std::cerr << "Default value substitution"
-//                             " is not supported for type"
-//                          << field->type_name() << std::endl;
-//                break;
-//            }
-//            if (defaultValue.size() > 0) {
-//                mPrinter.Print({{"property_name", field->camelcase_name()},
-//                                {"default_value", defaultValue}},
-//                               "    , $m_property_name$($default_value$)\n");
-//            }
-//        }
-//    }
+    //    for (int i = 0; i < mMessage->field_count(); i++) {
+    //        const FieldDescriptor* field = mMessage->field(i);
+    //        std::string defaultValue;
+    //        if (field->has_default_value()) {
+    //            switch (field->type()) {
+    //            case FieldDescriptor::TYPE_DOUBLE:
+    //                defaultValue = std::to_string(field->default_value_double());
+    //                break;
+    //            case FieldDescriptor::TYPE_FLOAT:
+    //                defaultValue = std::to_string(field->default_value_float());
+    //                break;
+    //            case FieldDescriptor::TYPE_INT32:
+    //            case FieldDescriptor::TYPE_UINT32:
+    //            case FieldDescriptor::TYPE_SFIXED32:
+    //            case FieldDescriptor::TYPE_SINT32:
+    //                defaultValue = std::to_string(field->default_value_int32());
+    //                break;
+    //            case FieldDescriptor::TYPE_BOOL:
+    //                defaultValue = field->default_value_bool() ? "true" : "false";
+    //                break;
+    //            case FieldDescriptor::TYPE_STRING:
+    //                defaultValue = field->default_value_string();
+    //                break;
+    //            case FieldDescriptor::TYPE_ENUM:
+    //                defaultValue = field->default_value_enum()->name();
+    //                break;
+    //            default:
+    //                std::cerr << "Default value substitution"
+    //                             " is not supported for type"
+    //                          << field->type_name() << std::endl;
+    //                break;
+    //            }
+    //            if (defaultValue.size() > 0) {
+    //                mPrinter.Print({{"property_name", field->camelcase_name()},
+    //                                {"default_value", defaultValue}},
+    //                               "    , $m_property_name$($default_value$)\n");
+    //            }
+    //        }
+    //    }
     mPrinter.Print("    {}\n\n");
 }
 

+ 20 - 0
src/lib/CMakeLists.txt

@@ -0,0 +1,20 @@
+find_package(Qt5 COMPONENTS Core REQUIRED)
+
+include_directories(${Qt5Core_INCLUDE_DIRS})
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+if (Qt5_POSITION_INDEPENDENT_CODE)
+  SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
+endif()
+
+add_library(qtprotobufsupport "universallistmodelbase.cpp" "universallistmodel.cpp")
+
+set_target_properties(qtprotobufsupport PROPERTIES PUBLIC_HEADER "universallistmodelbase.h;universallistmodel.h")
+
+install(TARGETS qtprotobufsupport
+    ARCHIVE DESTINATION lib
+    PUBLIC_HEADER DESTINATION include)

+ 23 - 0
src/lib/universallistmodel.cpp

@@ -0,0 +1,23 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2017 Alexey Edelev <semlanik@gmail.com>
+ *
+ * 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 "universallistmodel.h"

+ 224 - 0
src/lib/universallistmodel.h

@@ -0,0 +1,224 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2017 Alexey Edelev <semlanik@gmail.com>
+ *
+ * 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 <universallistmodelbase.h>
+
+#include <QObject>
+#include <QList>
+#include <QHash>
+#include <QPointer>
+#include <QMetaProperty>
+#include <QMetaObject>
+
+#include <QDebug>
+
+
+/*!
+ * \brief Universal list model is QObject-base list model abstraction.
+ * It exposes all objects properties as data-roles.
+ */
+template <typename T>
+class UniversalListModel : public UniversalListModelBase
+{
+public:
+    UniversalListModel(QObject* parent = 0) : UniversalListModelBase(parent) {}
+    ~UniversalListModel() {
+        clear();
+    }
+
+    int rowCount(const QModelIndex &parent) const override {
+        Q_UNUSED(parent)
+        return count();
+    }
+
+    int count() const override {
+        return m_container.count();
+    }
+
+    QHash<int, QByteArray> roleNames() const override {
+        if(s_roleNames.isEmpty()) {
+            int propertyCount = T::staticMetaObject.propertyCount();
+            for(int i = 1; i < propertyCount; i++) {
+                s_roleNames.insert(Qt::UserRole + i, T::staticMetaObject.property(i).name());
+            }
+            s_roleNames[propertyCount] = "modelData";
+        }
+        return s_roleNames;
+    }
+
+    QVariant data(const QModelIndex &index, int role) const override
+    {
+        int row = index.row();
+
+        if(row < 0 || row >= m_container.count() || m_container.at(row).isNull()) {
+            return QVariant();
+        }
+
+        T* dataPtr = m_container.at(row).data();
+
+        if(s_roleNames.value(role) == "modelData") {
+            return QVariant::fromValue(dataPtr);
+        }
+        return dataPtr->property(s_roleNames.value(role));
+    }
+
+    /*!
+     * \brief append
+     * \param value
+     * \return
+     */
+    int append(T* value) {
+        Q_ASSERT_X(value != nullptr, fullTemplateName(), "Trying to add member of NULL");
+
+        if(m_container.indexOf(value) >= 0) {
+#ifdef DEBUG
+            qDebug() << fullTemplateName() << "Member already exists";
+#endif
+            return -1;
+        }
+        beginInsertRows(QModelIndex(), m_container.count(), m_container.count());
+        m_container.append(QPointer<T>(value));
+        emit countChanged();
+        endInsertRows();
+        return m_container.count() - 1;
+    }
+
+    /*!
+     * \brief prepend
+     * \param value
+     * \return
+     */
+    int prepend(T* value) {
+        Q_ASSERT_X(value != nullptr, fullTemplateName(), "Trying to add member of NULL");
+
+        if(m_container.indexOf(value) >= 0) {
+#ifdef DEBUG
+            qDebug() << fullTemplateName() << "Member already exists";
+#endif
+            return -1;
+        }
+        beginInsertRows(QModelIndex(), 0, 0);
+        m_container.prepend(QPointer<T>(value));
+        emit countChanged();
+        endInsertRows();
+        return 0;
+    }
+
+    /*!
+     * \brief remove
+     * \param value
+     */
+    void remove(T* value) {
+        Q_ASSERT_X(value != nullptr, fullTemplateName(), ": Trying to remove member of NULL");
+
+        int valueIndex = m_container.indexOf(value);
+
+        remove(valueIndex);
+    }
+
+    void remove(int valueIndex) override {
+        if(valueIndex >= 0) {
+            beginRemoveRows(QModelIndex(), valueIndex, valueIndex);
+            m_container.removeAt(valueIndex);
+            emit countChanged();
+            endRemoveRows();
+        }
+    }
+
+    /*!
+     * \brief Resets container with new container passed as parameter
+     * \param container a data for model. Should contain QPointer's to objects.
+     * Passing empty container makes model empty. This method should be used to cleanup model.
+     */
+    void reset(const QList<QPointer<T> >& container) {
+        beginResetModel();
+        clear();
+        m_container = container;
+        emit countChanged();
+        endResetModel();
+    }
+
+    /*!
+     * \brief Returns the item at index position i in the list. i must be a valid index position in the list (i.e., 0 <= i < rowCount()).
+     * This function is very fast (constant time).
+     * \param i index of looking object
+     * \return Object at provided index
+     */
+    T* at(int i) const {
+        return m_container.at(i);
+    }
+
+    /*!
+     * \brief Looking for index of objec
+     * \param value
+     * \return
+     */
+    int indexOf(T* value) const {
+        return m_container.indexOf(value);
+    }
+
+    /*!
+     * \brief findByProperty method finds item in internal container property of that is provided value
+     * \param propertyName Latin1 name of looking property
+     * \param value property of corresponded type inside QVariant container
+     * \return
+     */
+    QPointer<T> findByProperty(const char* propertyName, const QVariant& value) const {
+        auto iter = std::find_if(m_container.begin(), m_container.end(), [=](const QPointer<T> &item) -> bool {
+            return item->property(propertyName) == value;
+        });
+
+        if(iter != m_container.end()) {
+            return *iter;
+        }
+        return QPointer<T>();
+    }
+
+    /*!
+     * \brief container returns internal container
+     * \return
+     */
+    QList<QPointer<T> > container() const {
+        return m_container;
+    }
+
+protected:
+    void clear() {
+        m_container.clear();
+        emit countChanged();
+    }
+
+    QList<QPointer<T> > m_container;
+    static QHash<int, QByteArray> s_roleNames;
+
+
+private:
+    static QByteArray fullTemplateName() { //Debug helper
+        return QString("UniversalListModel<%1>").arg(T::staticMetaObject.className()).toLatin1();
+    }
+};
+
+template<typename T>
+QHash<int, QByteArray> UniversalListModel<T>::s_roleNames;

+ 29 - 0
src/lib/universallistmodelbase.cpp

@@ -0,0 +1,29 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2017 Alexey Edelev <semlanik@gmail.com>
+ *
+ * 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 "universallistmodelbase.h"
+
+UniversalListModelBase::UniversalListModelBase(QObject *parent) : QAbstractListModel(parent)
+{
+
+}

+ 47 - 0
src/lib/universallistmodelbase.h

@@ -0,0 +1,47 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2017 Alexey Edelev <semlanik@gmail.com>
+ *
+ * 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 <QAbstractListModel>
+/*!
+ * \brief The UniversalListModelBase class to make prossible properties definition for UniversalListModel
+ * This class should not be used as is, but leaves this possibility.
+ */
+class UniversalListModelBase : public QAbstractListModel
+{
+    Q_OBJECT
+    Q_PROPERTY(int count READ count NOTIFY countChanged)
+public:
+    explicit UniversalListModelBase(QObject *parent = nullptr);
+
+    /*!
+     * \brief count property that declares row count of UniversalListModel
+     * \return
+     */
+    virtual int count() const = 0;
+    Q_INVOKABLE virtual void remove(int valueIndex) = 0;
+
+signals:
+    void countChanged();
+};