diff --git a/CodeGenerator/CodeGenerator.pro b/CodeGenerator/CodeGenerator.pro
new file mode 100644
index 0000000..dc2193d
--- /dev/null
+++ b/CodeGenerator/CodeGenerator.pro
@@ -0,0 +1,40 @@
+QT += core gui xml
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+CONFIG += c++11
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+QMAKE_CXXFLAGS += /std:c++latest /utf-8
+
+DESTDIR = $$OUT_PWD/..
+
+LIBS += -L$$OUT_PWD/..
+
+
+SOURCES += \
+ codegenerator.cpp \
+ main.cpp \
+ generatormainwindow.cpp
+
+HEADERS += \
+ codegenerator.h \
+ generatormainwindow.h
+
+FORMS += \
+ generatormainwindow.ui
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
diff --git a/CodeGenerator/codegenerator.cpp b/CodeGenerator/codegenerator.cpp
new file mode 100644
index 0000000..f6e8976
--- /dev/null
+++ b/CodeGenerator/codegenerator.cpp
@@ -0,0 +1,234 @@
+// Copyright (C) 2020 Jakub Melka
+//
+// This file is part of PdfForQt.
+//
+// PdfForQt is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// PdfForQt is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with PDFForQt. If not, see .
+
+#include "codegenerator.h"
+
+namespace codegen
+{
+
+GeneratedCodeStorage::GeneratedCodeStorage(QObject* parent) :
+ BaseClass(parent)
+{
+
+}
+
+QObjectList GeneratedCodeStorage::getFunctions() const
+{
+ return m_functions;
+}
+
+void GeneratedCodeStorage::setFunctions(const QObjectList& functions)
+{
+ m_functions = functions;
+}
+
+GeneratedFunction* GeneratedCodeStorage::addFunction(const QString& name)
+{
+ GeneratedFunction* function = new GeneratedFunction(this);
+ function->setFunctionName(name);
+ m_functions.append(function);
+ return function;
+}
+
+QObject* Serializer::load(const QDomElement& element, QObject* parent)
+{
+ QString className = element.attribute("class");
+ const int metaTypeId = QMetaType::type(className.toLatin1());
+ const QMetaObject* metaObject = QMetaType::metaObjectForType(metaTypeId);
+
+ if (metaObject)
+ {
+ QObject* deserializedObject = metaObject->newInstance(Q_ARG(QObject*, parent));
+
+ const int propertyCount = metaObject->propertyCount();
+ for (int i = 0; i < propertyCount; ++i)
+ {
+ QMetaProperty property = metaObject->property(i);
+ if (property.isWritable())
+ {
+ // Find, if property was serialized
+ QDomElement propertyElement;
+ QDomNodeList children = element.childNodes();
+ for (int i = 0; i < children.count(); ++i)
+ {
+ QDomNode child = children.item(i);
+ if (child.isElement())
+ {
+ QDomElement childElement = child.toElement();
+ QString attributeName = childElement.attribute("name");
+ if (attributeName == property.name())
+ {
+ propertyElement = child.toElement();
+ break;
+ }
+ }
+ }
+
+ if (!propertyElement.isNull())
+ {
+ // Deserialize the element
+ if (property.userType() == qMetaTypeId())
+ {
+ QObjectList objectList;
+ QDomNodeList children = propertyElement.childNodes();
+ for (int i = 0; i < children.count(); ++i)
+ {
+ QDomNode node = children.item(i);
+ if (node.isElement())
+ {
+ QDomElement element = node.toElement();
+ if (QObject* object = Serializer::load(element, deserializedObject))
+ {
+ objectList.append(object);
+ }
+ }
+ }
+
+ property.write(deserializedObject, QVariant::fromValue(qMove(objectList)));
+ }
+ else
+ {
+ QVariant value = propertyElement.text();
+ property.write(deserializedObject, value);
+ }
+ }
+ }
+ }
+
+ return deserializedObject;
+ }
+
+ return nullptr;
+}
+
+void Serializer::store(QObject* object, QDomElement& element)
+{
+ Q_ASSERT(object);
+
+ const QMetaObject* metaObject = object->metaObject();
+ element.setAttribute("class", QString(metaObject->className()));
+
+ const int propertyCount = metaObject->propertyCount();
+ if (propertyCount > 0)
+ {
+ for (int i = 0; i < propertyCount; ++i)
+ {
+ QMetaProperty property = metaObject->property(i);
+ if (property.isReadable())
+ {
+ QDomElement propertyElement = element.ownerDocument().createElement("property");
+ element.appendChild(propertyElement);
+ propertyElement.setAttribute("name", property.name());
+
+ QVariant value = property.read(object);
+ if (value.canConvert())
+ {
+ QObjectList objectList = value.value();
+ for (QObject* currentObject : objectList)
+ {
+ QDomElement objectElement = element.ownerDocument().createElement("QObject");
+ propertyElement.appendChild(objectElement);
+ Serializer::store(currentObject, objectElement);
+ }
+ }
+ else
+ {
+ propertyElement.appendChild(propertyElement.ownerDocument().createTextNode(value.toString()));
+ }
+ }
+ }
+ }
+}
+
+CodeGenerator::CodeGenerator(QObject* parent) :
+ BaseClass(parent)
+{
+ qRegisterMetaType("codegen::GeneratedCodeStorage");
+ qRegisterMetaType("codegen::GeneratedFunction");
+ qRegisterMetaType("QObjectList");
+}
+
+void CodeGenerator::initialize()
+{
+ m_storage = new GeneratedCodeStorage(this);
+}
+
+void CodeGenerator::load(const QDomDocument& document)
+{
+ delete m_storage;
+ m_storage = nullptr;
+
+ m_storage = qobject_cast(Serializer::load(document.firstChildElement("root"), this));
+}
+
+void CodeGenerator::store(QDomDocument& document)
+{
+ if (m_storage)
+ {
+ QDomElement rootElement = document.createElement("root");
+ document.appendChild(rootElement);
+ Serializer::store(m_storage, rootElement);
+ }
+}
+
+GeneratedFunction::GeneratedFunction(QObject* parent) :
+ BaseClass(parent)
+{
+
+}
+
+QString GeneratedFunction::getFunctionTypeString() const
+{
+ return Serializer::convertEnumToString(m_functionType);
+}
+
+void GeneratedFunction::setFunctionTypeString(const QString& string)
+{
+ Serializer::convertStringToEnum(string, m_functionType);
+}
+
+GeneratedFunction::FunctionType GeneratedFunction::getFunctionType() const
+{
+ return m_functionType;
+}
+
+void GeneratedFunction::setFunctionType(const FunctionType& functionType)
+{
+ m_functionType = functionType;
+}
+
+QString GeneratedFunction::getFunctionName() const
+{
+ return m_functionName;
+}
+
+void GeneratedFunction::setFunctionName(const QString& functionName)
+{
+ m_functionName = functionName;
+}
+
+QString GeneratedFunction::getFunctionDescription() const
+{
+ return m_functionDescription;
+}
+
+void GeneratedFunction::setFunctionDescription(const QString& functionDescription)
+{
+ m_functionDescription = functionDescription;
+}
+
+}
diff --git a/CodeGenerator/codegenerator.h b/CodeGenerator/codegenerator.h
new file mode 100644
index 0000000..26dd907
--- /dev/null
+++ b/CodeGenerator/codegenerator.h
@@ -0,0 +1,150 @@
+// Copyright (C) 2020 Jakub Melka
+//
+// This file is part of PdfForQt.
+//
+// PdfForQt is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// PdfForQt is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with PDFForQt. If not, see .
+
+#ifndef CODEGENERATOR_H
+#define CODEGENERATOR_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace codegen
+{
+
+class Serializer
+{
+public:
+ static QObject* load(const QDomElement& element, QObject* parent);
+ static void store(QObject* object, QDomElement& element);
+
+ template
+ static inline QString convertEnumToString(T enumValue)
+ {
+ QMetaEnum metaEnum = QMetaEnum::fromType();
+ Q_ASSERT(metaEnum.isValid());
+ return metaEnum.valueToKey(enumValue);
+ }
+
+ template
+ static inline void convertStringToEnum(const QString enumString, T& value)
+ {
+ QMetaEnum metaEnum = QMetaEnum::fromType();
+ Q_ASSERT(metaEnum.isValid());
+ bool ok = false;
+ value = static_cast(metaEnum.keyToValue(enumString.toLatin1().data(), &ok));
+ if (!ok)
+ {
+ // Set default value, if something fails.
+ value = T();
+ }
+ }
+};
+
+class GeneratedFunction;
+
+class GeneratedCodeStorage : public QObject
+{
+ Q_OBJECT
+
+private:
+ using BaseClass = QObject;
+
+public:
+ Q_INVOKABLE GeneratedCodeStorage(QObject* parent);
+
+ Q_PROPERTY(QObjectList functions READ getFunctions WRITE setFunctions)
+
+ QObjectList getFunctions() const;
+ void setFunctions(const QObjectList& functions);
+
+ GeneratedFunction* addFunction(const QString& name);
+
+private:
+ QObjectList m_functions;
+};
+
+class GeneratedFunction : public QObject
+{
+ Q_OBJECT
+
+private:
+ using BaseClass = QObject;
+
+public:
+
+ enum FunctionType
+ {
+ Annotations,
+ ColorSpace
+ };
+ Q_ENUM(FunctionType)
+
+
+ Q_INVOKABLE GeneratedFunction(QObject* parent);
+
+ Q_PROPERTY(QString functionType READ getFunctionTypeString WRITE setFunctionTypeString)
+ Q_PROPERTY(QString functionName READ getFunctionName WRITE setFunctionName)
+ Q_PROPERTY(QString functionDescription READ getFunctionDescription WRITE setFunctionDescription)
+
+ QString getFunctionTypeString() const;
+ void setFunctionTypeString(const QString& string);
+
+ FunctionType getFunctionType() const;
+ void setFunctionType(const FunctionType& functionType);
+
+ QString getFunctionName() const;
+ void setFunctionName(const QString& functionName);
+
+ QString getFunctionDescription() const;
+ void setFunctionDescription(const QString& functionDescription);
+
+private:
+ FunctionType m_functionType = FunctionType::Annotations;
+ QString m_functionName;
+ QString m_functionDescription;
+};
+
+class CodeGenerator : public QObject
+{
+ Q_OBJECT
+
+private:
+ using BaseClass = QObject;
+
+public:
+ CodeGenerator(QObject* parent = nullptr);
+
+ void initialize();
+
+ GeneratedFunction* addFunction(const QString& name) { return m_storage->addFunction(name); }
+
+ void load(const QDomDocument& document);
+ void store(QDomDocument& document);
+
+private:
+ GeneratedCodeStorage* m_storage = nullptr;
+};
+
+} // namespace codegen
+
+Q_DECLARE_METATYPE(codegen::GeneratedCodeStorage*)
+Q_DECLARE_METATYPE(codegen::GeneratedFunction*)
+
+#endif // CODEGENERATOR_H
diff --git a/CodeGenerator/generatormainwindow.cpp b/CodeGenerator/generatormainwindow.cpp
new file mode 100644
index 0000000..f3c6672
--- /dev/null
+++ b/CodeGenerator/generatormainwindow.cpp
@@ -0,0 +1,134 @@
+// Copyright (C) 2020 Jakub Melka
+//
+// This file is part of PdfForQt.
+//
+// PdfForQt is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// PdfForQt is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with PDFForQt. If not, see .
+
+#include "generatormainwindow.h"
+#include "ui_generatormainwindow.h"
+
+#include "codegenerator.h"
+
+#include
+#include
+#include
+#include
+#include
+
+GeneratorMainWindow::GeneratorMainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::GeneratorMainWindow),
+ m_generator(new codegen::CodeGenerator(this))
+{
+ ui->setupUi(this);
+
+ m_generator->initialize();
+
+ loadSettings();
+
+ if (!m_defaultFileName.isEmpty())
+ {
+ load(m_defaultFileName);
+ }
+
+ // Temporary - to delete:
+ m_generator->addFunction("createAnnotationWatermark");
+ m_generator->addFunction("createAnnotationFreeText");
+}
+
+GeneratorMainWindow::~GeneratorMainWindow()
+{
+ delete ui;
+}
+
+void GeneratorMainWindow::load(const QString& fileName)
+{
+ QFile file(fileName);
+ if (file.open(QFile::ReadOnly | QFile::Truncate))
+ {
+ QTextStream stream(&file);
+ stream.setCodec("UTF-8");
+
+ QDomDocument document;
+ document.setContent(stream.readAll());
+ m_generator->load(document);
+ file.close();
+ }
+}
+
+void GeneratorMainWindow::saveSettings()
+{
+ QSettings settings("MelkaJ");
+ settings.setValue("fileName", m_defaultFileName);
+}
+
+void GeneratorMainWindow::loadSettings()
+{
+ QSettings settings("MelkaJ");
+ m_defaultFileName = settings.value("fileName").toString();
+}
+
+void GeneratorMainWindow::save(const QString& fileName)
+{
+ QFile file(fileName);
+ if (file.open(QFile::WriteOnly | QFile::Truncate))
+ {
+ QTextStream stream(&file);
+ stream.setCodec("UTF-8");
+
+ QDomDocument document;
+ m_generator->store(document);
+ document.save(stream, 2, QDomDocument::EncodingFromTextStream);
+ file.close();
+
+ // Update default file name
+ m_defaultFileName = fileName;
+ saveSettings();
+ }
+}
+
+void GeneratorMainWindow::on_actionLoad_triggered()
+{
+ QFileInfo info(m_defaultFileName);
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Select XML definition file"), info.dir().absolutePath(), "XML files (*.xml)");
+ if (!fileName.isEmpty())
+ {
+ m_defaultFileName = fileName;
+ saveSettings();
+
+ load(m_defaultFileName);
+ }
+}
+
+void GeneratorMainWindow::on_actionSaveAs_triggered()
+{
+ QFileInfo info(m_defaultFileName);
+ QString fileName = QFileDialog::getSaveFileName(this, tr("Select XML definition file"), info.dir().absolutePath(), "XML files (*.xml)");
+ if (!fileName.isEmpty())
+ {
+ save(fileName);
+ }
+}
+
+void GeneratorMainWindow::on_actionSave_triggered()
+{
+ if (!m_defaultFileName.isEmpty())
+ {
+ save(m_defaultFileName);
+ }
+ else
+ {
+ on_actionSaveAs_triggered();
+ }
+}
diff --git a/CodeGenerator/generatormainwindow.h b/CodeGenerator/generatormainwindow.h
new file mode 100644
index 0000000..6ac705d
--- /dev/null
+++ b/CodeGenerator/generatormainwindow.h
@@ -0,0 +1,59 @@
+// Copyright (C) 2020 Jakub Melka
+//
+// This file is part of PdfForQt.
+//
+// PdfForQt is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// PdfForQt is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with PDFForQt. If not, see .
+
+#ifndef GENERATORMAINWINDOW_H
+#define GENERATORMAINWINDOW_H
+
+#include
+
+namespace codegen
+{
+class CodeGenerator;
+}
+
+namespace Ui
+{
+class GeneratorMainWindow;
+}
+
+class GeneratorMainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ GeneratorMainWindow(QWidget* parent = nullptr);
+ virtual ~GeneratorMainWindow() override;
+
+ void load(const QString& fileName);
+ void save(const QString& fileName);
+
+private slots:
+ void on_actionLoad_triggered();
+ void on_actionSaveAs_triggered();
+
+ void on_actionSave_triggered();
+
+private:
+ void loadSettings();
+ void saveSettings();
+
+ Ui::GeneratorMainWindow* ui;
+ codegen::CodeGenerator* m_generator;
+ QString m_defaultFileName;
+};
+
+#endif // GENERATORMAINWINDOW_H
diff --git a/CodeGenerator/generatormainwindow.ui b/CodeGenerator/generatormainwindow.ui
new file mode 100644
index 0000000..d902060
--- /dev/null
+++ b/CodeGenerator/generatormainwindow.ui
@@ -0,0 +1,205 @@
+
+
+ GeneratorMainWindow
+
+
+
+ 0
+ 0
+ 1121
+ 662
+
+
+
+ Code Generator
+
+
+
+ -
+
+
-
+
+
+
+ 1
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Up
+
+
+
+ -
+
+
+ Down
+
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Remove
+
+
+
+ -
+
+
+ Clone
+
+
+
+ -
+
+
+ New
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Parameters
+
+
+
+ -
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ PushButton
+
+
+
+ -
+
+
+ PushButton
+
+
+
+ -
+
+
+ PushButton
+
+
+
+ -
+
+
+ PushButton
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Load
+
+
+ Ctrl+O
+
+
+
+
+ Save
+
+
+ Ctrl+S
+
+
+
+
+ Save As...
+
+
+
+
+
+
diff --git a/CodeGenerator/main.cpp b/CodeGenerator/main.cpp
new file mode 100644
index 0000000..cae4c84
--- /dev/null
+++ b/CodeGenerator/main.cpp
@@ -0,0 +1,28 @@
+// Copyright (C) 2020 Jakub Melka
+//
+// This file is part of PdfForQt.
+//
+// PdfForQt is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// PdfForQt is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with PDFForQt. If not, see .
+
+#include "generatormainwindow.h"
+
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ GeneratorMainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/PdfForQt.pro b/PdfForQt.pro
index 8c88194..05207e4 100644
--- a/PdfForQt.pro
+++ b/PdfForQt.pro
@@ -18,6 +18,7 @@
TEMPLATE = subdirs
SUBDIRS += \
+ CodeGenerator \
JBIG2_Viewer \
PdfForQtLib \
UnitTests \