mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
3D PDF: Code generator for PRC (initial commit)
This commit is contained in:
@@ -1913,4 +1913,252 @@ QString XFACodeGenerator::generateHeader() const
|
||||
return QString::fromUtf8(ba);
|
||||
}
|
||||
|
||||
void PRCCodeGenerator::generateCode(const QDomDocument& document, QString headerName, QString sourceName)
|
||||
{
|
||||
QString startMark = "/* START GENERATED CODE */";
|
||||
QString endMark = "/* END GENERATED CODE */";
|
||||
|
||||
loadClasses(document);
|
||||
|
||||
QFile headerFile(headerName);
|
||||
if (headerFile.exists())
|
||||
{
|
||||
if (headerFile.open(QFile::ReadOnly | QFile::Text))
|
||||
{
|
||||
QString utfCode = QString::fromUtf8(headerFile.readAll());
|
||||
headerFile.close();
|
||||
|
||||
int startIndex = utfCode.indexOf(startMark, Qt::CaseSensitive) + startMark.length();
|
||||
int endIndex = utfCode.indexOf(endMark, Qt::CaseSensitive);
|
||||
|
||||
QString frontPart = utfCode.left(startIndex);
|
||||
QString backPart = utfCode.mid(endIndex);
|
||||
QString headerGeneratedCode = generateHeader();
|
||||
QString allCode = frontPart + headerGeneratedCode + backPart;
|
||||
|
||||
headerFile.open(QFile::WriteOnly | QFile::Truncate);
|
||||
headerFile.write(allCode.toUtf8());
|
||||
headerFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
QFile sourceFile(sourceName);
|
||||
if (sourceFile.exists())
|
||||
{
|
||||
if (sourceFile.open(QFile::ReadOnly | QFile::Text))
|
||||
{
|
||||
QString utfCode = QString::fromUtf8(sourceFile.readAll());
|
||||
sourceFile.close();
|
||||
|
||||
int startIndex = utfCode.indexOf(startMark, Qt::CaseSensitive) + startMark.length();
|
||||
int endIndex = utfCode.indexOf(endMark, Qt::CaseSensitive);
|
||||
|
||||
QString frontPart = utfCode.left(startIndex);
|
||||
QString backPart = utfCode.mid(endIndex);
|
||||
QString sourceGeneratedCode = generateSource();
|
||||
QString allCode = frontPart + sourceGeneratedCode + backPart;
|
||||
|
||||
sourceFile.open(QFile::WriteOnly | QFile::Truncate);
|
||||
sourceFile.write(allCode.toUtf8());
|
||||
sourceFile.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PRCCodeGenerator::loadClasses(const QDomDocument& document)
|
||||
{
|
||||
QDomElement prcElement = document.firstChildElement("prc");
|
||||
|
||||
if (prcElement.isNull())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QDomElement element = prcElement.firstChildElement("objects");
|
||||
|
||||
if (element.isNull())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QDomNodeList childNodes = element.elementsByTagName("object");
|
||||
|
||||
for (int i = 0; i < childNodes.length(); ++i)
|
||||
{
|
||||
QDomNode node = childNodes.item(i);
|
||||
QDomElement classElement = node.toElement();
|
||||
QString className = classElement.attribute("name");
|
||||
|
||||
Class myClass;
|
||||
myClass.classType = className;
|
||||
myClass.isFlat = classElement.attribute("flat") == "true";
|
||||
myClass.valueType = myClass.isFlat ? className : QString("std::shared_ptr<%1>").arg(myClass.classType);
|
||||
|
||||
QDomNodeList loadItems = classElement.childNodes();
|
||||
for (int j = 0; j < loadItems.length(); ++j)
|
||||
{
|
||||
QDomElement loadElement = loadItems.item(j).toElement();
|
||||
|
||||
LoadItem loadItem;
|
||||
loadItem.name = loadElement.attribute("name");
|
||||
loadItem.type = loadElement.attribute("type");
|
||||
loadItem.constant = loadElement.attribute("constant");
|
||||
loadItem.bits = loadElement.attribute("bits");
|
||||
|
||||
if (loadElement.tagName() == "field")
|
||||
{
|
||||
loadItem.loadItemType = Field;
|
||||
}
|
||||
if (loadElement.tagName() == "array")
|
||||
{
|
||||
loadItem.loadItemType = Array;
|
||||
}
|
||||
|
||||
if (loadElement.attribute("value") == "true")
|
||||
{
|
||||
myClass.isValue = true;
|
||||
myClass.valueType = loadElement.attribute("type");
|
||||
}
|
||||
|
||||
myClass.items.emplace_back(std::move(loadItem));
|
||||
}
|
||||
|
||||
m_classes[className] = (std::move(myClass));
|
||||
}
|
||||
}
|
||||
|
||||
QString PRCCodeGenerator::generateHeader() const
|
||||
{
|
||||
QByteArray ba;
|
||||
{
|
||||
QTextStream stream(&ba, QIODevice::WriteOnly);
|
||||
stream.setEncoding(QStringConverter::Utf8);
|
||||
stream.setRealNumberPrecision(3);
|
||||
stream.setRealNumberNotation(QTextStream::FixedNotation);
|
||||
|
||||
stream << Qt::endl << Qt::endl;
|
||||
|
||||
for (const auto& item : m_classes)
|
||||
{
|
||||
const Class& myClass = item.second;
|
||||
|
||||
if (myClass.isValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
stream << "class " << myClass.classType << Qt::endl;
|
||||
stream << "{" << Qt::endl;
|
||||
stream << "public:" << Qt::endl;
|
||||
stream << QString(" explicit %1() = default;").arg(myClass.classType) << Qt::endl;
|
||||
stream << QString(" ~%1() = default;").arg(myClass.classType) << Qt::endl << Qt::endl;
|
||||
|
||||
// Generate getters/setters
|
||||
for (const LoadItem& loadItem : myClass.items)
|
||||
{
|
||||
if (!loadItem.isFieldOrArray())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
stream << QString(" const %1& %2() const { return %3; }").arg(getValueTypeForLoadItem(loadItem), getGetterFunctionNameForLoadItem(loadItem), getClassFieldNameForValueItem(loadItem)) << Qt::endl;
|
||||
stream << QString(" void %2(%1 value) { return %3 = std::move(value); }").arg(getValueTypeForLoadItem(loadItem), getSetterFunctionNameForLoadItem(loadItem), getClassFieldNameForValueItem(loadItem)) << Qt::endl;
|
||||
|
||||
stream << Qt::endl;
|
||||
}
|
||||
|
||||
stream << Qt::endl;
|
||||
stream << "private:" << Qt::endl;
|
||||
|
||||
// Generate fields
|
||||
for (const LoadItem& loadItem : myClass.items)
|
||||
{
|
||||
if (!loadItem.isFieldOrArray())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
stream << QString(" %1 %2 = %1();").arg(getValueTypeForLoadItem(loadItem), getClassFieldNameForValueItem(loadItem)) << Qt::endl;
|
||||
}
|
||||
|
||||
stream << "};" << Qt::endl << Qt::endl;
|
||||
}
|
||||
|
||||
stream << Qt::endl << Qt::endl;
|
||||
}
|
||||
|
||||
return QString::fromUtf8(ba);
|
||||
}
|
||||
|
||||
QString PRCCodeGenerator::generateSource() const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString PRCCodeGenerator::getCamelCase(QString string) const
|
||||
{
|
||||
QString str;
|
||||
|
||||
bool upperCase = false;
|
||||
for (QChar ch : string)
|
||||
{
|
||||
if (ch == '_')
|
||||
{
|
||||
upperCase = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (upperCase)
|
||||
{
|
||||
upperCase = false;
|
||||
ch = ch.toUpper();
|
||||
}
|
||||
|
||||
str += ch;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
QString PRCCodeGenerator::getValueTypeForLoadItem(const LoadItem& item) const
|
||||
{
|
||||
auto it = m_classes.find(item.type);
|
||||
if (it != m_classes.cend())
|
||||
{
|
||||
const Class& myClass = (*it).second;
|
||||
QString valueType = myClass.valueType;
|
||||
|
||||
if (item.isField())
|
||||
{
|
||||
return valueType;
|
||||
}
|
||||
|
||||
if (item.isArray())
|
||||
{
|
||||
return QString("std::vector<%1>").arg(valueType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "Class " << item.type << " not found!";
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString PRCCodeGenerator::getClassFieldNameForValueItem(const LoadItem& item) const
|
||||
{
|
||||
return QString("m_") + getCamelCase(item.name);
|
||||
}
|
||||
|
||||
QString PRCCodeGenerator::getGetterFunctionNameForLoadItem(const LoadItem& item) const
|
||||
{
|
||||
return getCamelCase(QString("is_") + item.name);
|
||||
}
|
||||
|
||||
QString PRCCodeGenerator::getSetterFunctionNameForLoadItem(const LoadItem& item) const
|
||||
{
|
||||
return getCamelCase(QString("set_") + item.name);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -498,6 +498,62 @@ private:
|
||||
std::set<QString> m_usedTypes;
|
||||
};
|
||||
|
||||
class PRCCodeGenerator
|
||||
{
|
||||
public:
|
||||
PRCCodeGenerator() = default;
|
||||
|
||||
void generateCode(const QDomDocument& document, QString headerName, QString sourceName);
|
||||
|
||||
private:
|
||||
|
||||
enum LoadItemType
|
||||
{
|
||||
Field,
|
||||
Array
|
||||
};
|
||||
|
||||
struct LoadItem
|
||||
{
|
||||
bool isField() const { return loadItemType == Field; }
|
||||
bool isArray() const { return loadItemType == Array; }
|
||||
bool isFieldOrArray() const { return isField() || loadItemType == Array; }
|
||||
|
||||
LoadItemType loadItemType = Field;
|
||||
QString name;
|
||||
QString type;
|
||||
QString constant;
|
||||
QString bits;
|
||||
};
|
||||
|
||||
struct Class
|
||||
{
|
||||
QString classType;
|
||||
QString valueType;
|
||||
|
||||
/// Use class by value, not by shared pointer?
|
||||
bool isFlat = false;
|
||||
|
||||
/// Use value type instead of the class?
|
||||
bool isValue = false;
|
||||
|
||||
std::vector<LoadItem> items;
|
||||
};
|
||||
|
||||
void loadClasses(const QDomDocument& document);
|
||||
|
||||
QString generateHeader() const;
|
||||
QString generateSource() const;
|
||||
|
||||
QString getCamelCase(QString string) const;
|
||||
QString getValueTypeForLoadItem(const LoadItem& item) const;
|
||||
QString getClassFieldNameForValueItem(const LoadItem& item) const;
|
||||
QString getGetterFunctionNameForLoadItem(const LoadItem& item) const;
|
||||
QString getSetterFunctionNameForLoadItem(const LoadItem& item) const;
|
||||
|
||||
std::map<QString, Class> m_classes;
|
||||
};
|
||||
|
||||
} // namespace codegen
|
||||
|
||||
Q_DECLARE_METATYPE(codegen::GeneratedCodeStorage*)
|
||||
|
@@ -91,6 +91,9 @@ void GeneratorMainWindow::saveSettings()
|
||||
settings.setValue("XFAdefinitionFileName", m_XFAdefinitionFileName);
|
||||
settings.setValue("XFAheaderFileName", m_XFAheaderFileName);
|
||||
settings.setValue("XFAsourceFileName", m_XFAsourceFileName);
|
||||
settings.setValue("PRCdefinitionFileName", m_PRCdefinitionFileName);
|
||||
settings.setValue("PRCheaderFileName", m_PRCheaderFileName);
|
||||
settings.setValue("PRCsourceFileName", m_PRCsourceFileName);
|
||||
}
|
||||
|
||||
void GeneratorMainWindow::loadGeneratedSettings()
|
||||
@@ -362,6 +365,9 @@ void GeneratorMainWindow::loadSettings()
|
||||
m_XFAdefinitionFileName = settings.value("XFAdefinitionFileName", QVariant()).toString();
|
||||
m_XFAheaderFileName = settings.value("XFAheaderFileName", QVariant()).toString();
|
||||
m_XFAsourceFileName = settings.value("XFAsourceFileName", QVariant()).toString();
|
||||
m_PRCdefinitionFileName = settings.value("PRCdefinitionFileName", QVariant()).toString();
|
||||
m_PRCheaderFileName = settings.value("PRCheaderFileName", QVariant()).toString();
|
||||
m_PRCsourceFileName = settings.value("PRCsourceFileName", QVariant()).toString();
|
||||
}
|
||||
|
||||
void GeneratorMainWindow::save(const QString& fileName)
|
||||
@@ -572,3 +578,48 @@ void GeneratorMainWindow::on_actionGenerate_XFA_code_triggered()
|
||||
generator.generateCode(document, m_XFAheaderFileName, m_XFAsourceFileName);
|
||||
}
|
||||
}
|
||||
|
||||
void GeneratorMainWindow::on_actionSet_code_header_PRC_triggered()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Select cpp header"), QString(), "cpp header (*.h)");
|
||||
if (!fileName.isEmpty())
|
||||
{
|
||||
m_PRCheaderFileName = fileName;
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void GeneratorMainWindow::on_actionSet_code_source_PRC_triggered()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Select cpp source"), QString(), "cpp source (*.cpp)");
|
||||
if (!fileName.isEmpty())
|
||||
{
|
||||
m_PRCsourceFileName = fileName;
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void GeneratorMainWindow::on_actionSet_PRC_description_triggered()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Select xml definition"), QString(), "XML file (*.xml)");
|
||||
if (!fileName.isEmpty())
|
||||
{
|
||||
m_PRCdefinitionFileName = fileName;
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void GeneratorMainWindow::on_actionGenerate_PRC_code_triggered()
|
||||
{
|
||||
codegen::PRCCodeGenerator generator;
|
||||
|
||||
QFile file(m_PRCdefinitionFileName);
|
||||
if (file.open(QFile::ReadOnly))
|
||||
{
|
||||
QDomDocument document;
|
||||
document.setContent(&file);
|
||||
file.close();
|
||||
|
||||
generator.generateCode(document, m_PRCheaderFileName, m_PRCsourceFileName);
|
||||
}
|
||||
}
|
||||
|
@@ -84,6 +84,10 @@ private slots:
|
||||
void on_actionSet_code_source_XFA_triggered();
|
||||
void on_actionGenerate_XFA_code_triggered();
|
||||
void on_actionSet_XFA_description_triggered();
|
||||
void on_actionSet_code_header_PRC_triggered();
|
||||
void on_actionSet_code_source_PRC_triggered();
|
||||
void on_actionGenerate_PRC_code_triggered();
|
||||
void on_actionSet_PRC_description_triggered();
|
||||
|
||||
private:
|
||||
void loadSettings();
|
||||
@@ -112,6 +116,10 @@ private:
|
||||
QString m_XFAdefinitionFileName;
|
||||
QString m_XFAheaderFileName;
|
||||
QString m_XFAsourceFileName;
|
||||
|
||||
QString m_PRCdefinitionFileName;
|
||||
QString m_PRCheaderFileName;
|
||||
QString m_PRCsourceFileName;
|
||||
};
|
||||
|
||||
#endif // GENERATORMAINWINDOW_H
|
||||
|
@@ -250,9 +250,19 @@
|
||||
<addaction name="actionSet_code_source_XFA"/>
|
||||
<addaction name="actionGenerate_XFA_code"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuPRC">
|
||||
<property name="title">
|
||||
<string>PRC</string>
|
||||
</property>
|
||||
<addaction name="actionSet_PRC_description"/>
|
||||
<addaction name="actionSet_code_header_PRC"/>
|
||||
<addaction name="actionSet_code_source_PRC"/>
|
||||
<addaction name="actionGenerate_PRC_code"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuCode"/>
|
||||
<addaction name="menuXFA"/>
|
||||
<addaction name="menuPRC"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<action name="actionLoad">
|
||||
@@ -314,6 +324,26 @@
|
||||
<string>Set XFA description</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSet_code_header_PRC">
|
||||
<property name="text">
|
||||
<string>Set code header PRC</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSet_code_source_PRC">
|
||||
<property name="text">
|
||||
<string>Set code source PRC</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionGenerate_PRC_code">
|
||||
<property name="text">
|
||||
<string>Generate PRC code</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSet_PRC_description">
|
||||
<property name="text">
|
||||
<string>Set PRC description</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
@@ -101,6 +101,8 @@ add_library(Pdf4QtLib SHARED
|
||||
sources/pdfobjecteditorwidget_impl.h
|
||||
sources/pdfdocumentsanitizer.h
|
||||
sources/pdfdocumentsanitizer.cpp
|
||||
sources/pdf3d_prc.h
|
||||
sources/pdf3d_prc.cpp
|
||||
cmaps.qrc
|
||||
)
|
||||
|
||||
|
30
Pdf4QtLib/sources/pdf3d_prc.cpp
Normal file
30
Pdf4QtLib/sources/pdf3d_prc.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2023 Jakub Melka
|
||||
//
|
||||
// This file is part of PDF4QT.
|
||||
//
|
||||
// PDF4QT 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
|
||||
// with the written consent of the copyright owner, any later version.
|
||||
//
|
||||
// PDF4QT 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 PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "pdf3d_prc.h"
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
namespace prc
|
||||
{
|
||||
|
||||
/* START GENERATED CODE *//* END GENERATED CODE */
|
||||
|
||||
} // namespace prc
|
||||
|
||||
} // namespace pdf
|
39
Pdf4QtLib/sources/pdf3d_prc.h
Normal file
39
Pdf4QtLib/sources/pdf3d_prc.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2023 Jakub Melka
|
||||
//
|
||||
// This file is part of PDF4QT.
|
||||
//
|
||||
// PDF4QT 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
|
||||
// with the written consent of the copyright owner, any later version.
|
||||
//
|
||||
// PDF4QT 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 PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef PDF3D_PRC_H
|
||||
#define PDF3D_PRC_H
|
||||
|
||||
#include "pdfglobal.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
namespace prc
|
||||
{
|
||||
|
||||
/* START GENERATED CODE */
|
||||
|
||||
/* END GENERATED CODE */
|
||||
|
||||
} // namespace prc
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDF3D_PRC_H
|
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2022 Jakub Melka
|
||||
// Copyright (C) 2022-2023 Jakub Melka
|
||||
//
|
||||
// This file is part of PDF4QT.
|
||||
//
|
||||
|
@@ -1,3 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||
|
||||
<!--
|
||||
// Copyright (C) 2022-2023 Jakub Melka
|
||||
//
|
||||
@@ -18,7 +20,6 @@
|
||||
|
||||
-->
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||
<prc>
|
||||
|
||||
<!--
|
||||
@@ -480,12 +481,12 @@
|
||||
<field name="v_param_coeff_b" type="Double" />
|
||||
</object>
|
||||
|
||||
<object name="Vector2d" flat="true">
|
||||
<object name="Vector2D" flat="true">
|
||||
<field name="x_value" type="Double" />
|
||||
<field name="y_value" type="Double" />
|
||||
</object>
|
||||
|
||||
<object name="Vector3d" flat="true">
|
||||
<object name="Vector3D" flat="true">
|
||||
<field name="x_value" type="Double" />
|
||||
<field name="y_value" type="Double" />
|
||||
<field name="z_value" type="Double" />
|
||||
@@ -875,7 +876,7 @@
|
||||
<array name="homogenous" dim="4" type="Double" condition="behavior & PRC_TRANSFORMATION_Homogenous == TRUE" />
|
||||
</object>
|
||||
|
||||
<object name="2DTransformation">
|
||||
<object name="_2DTransformation">
|
||||
<field name="behavior" type="Character" />
|
||||
<field name="translation" type="Vector3D" condition="behavior & PRC_TRANSFORMATION_Translate == TRUE" />
|
||||
<array name="non_ortho_matrix" dim="3" type="Vector3D" condition="behavior & PRC_TRANSFORMATION_NonOrtho == TRUE" />
|
||||
|
Reference in New Issue
Block a user