mirror of https://github.com/JakubMelka/PDF4QT.git
Generating code
This commit is contained in:
parent
96d2e33692
commit
bc6ca3fc46
|
@ -17,6 +17,12 @@
|
||||||
|
|
||||||
#include "codegenerator.h"
|
#include "codegenerator.h"
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QTextLayout>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QFontMetrics>
|
||||||
|
|
||||||
namespace codegen
|
namespace codegen
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -57,6 +63,18 @@ void GeneratedCodeStorage::removeFunction(GeneratedFunction* function)
|
||||||
m_functions.removeOne(function);
|
m_functions.removeOne(function);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GeneratedCodeStorage::generateCode(QTextStream& stream, CodeGeneratorParameters& parameters) const
|
||||||
|
{
|
||||||
|
stream << Qt::endl << Qt::endl;
|
||||||
|
|
||||||
|
for (const QObject* object : m_functions)
|
||||||
|
{
|
||||||
|
const GeneratedFunction* generatedFunction = qobject_cast<const GeneratedFunction*>(object);
|
||||||
|
generatedFunction->generateCode(stream, parameters);
|
||||||
|
stream << Qt::endl << Qt::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QObject* Serializer::load(const QDomElement& element, QObject* parent)
|
QObject* Serializer::load(const QDomElement& element, QObject* parent)
|
||||||
{
|
{
|
||||||
QString className = element.attribute("class");
|
QString className = element.attribute("class");
|
||||||
|
@ -223,6 +241,95 @@ void CodeGenerator::store(QDomDocument& document)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CodeGenerator::generateCode(QString headerName, QString sourceName) const
|
||||||
|
{
|
||||||
|
QString startMark = "/* START GENERATED CODE */";
|
||||||
|
QString endMark = "/* END GENERATED CODE */";
|
||||||
|
QString className = "PDFDocumentBuilder";
|
||||||
|
const int indent = 4;
|
||||||
|
|
||||||
|
QFile headerFile(headerName);
|
||||||
|
if (headerFile.exists())
|
||||||
|
{
|
||||||
|
if (headerFile.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
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(indent);
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
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(className, indent);
|
||||||
|
QString allCode = frontPart + sourceGeneratedCode + backPart;
|
||||||
|
|
||||||
|
sourceFile.open(QFile::WriteOnly | QFile::Truncate);
|
||||||
|
sourceFile.write(allCode.toUtf8());
|
||||||
|
sourceFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CodeGenerator::generateHeader(int indent) const
|
||||||
|
{
|
||||||
|
QByteArray ba;
|
||||||
|
{
|
||||||
|
QTextStream stream(&ba, QIODevice::WriteOnly);
|
||||||
|
stream.setCodec("UTF-8");
|
||||||
|
stream.setRealNumberPrecision(3);
|
||||||
|
stream.setRealNumberNotation(QTextStream::FixedNotation);
|
||||||
|
|
||||||
|
CodeGeneratorParameters parameters;
|
||||||
|
parameters.header = true;
|
||||||
|
parameters.indent = indent;
|
||||||
|
m_storage->generateCode(stream, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString::fromUtf8(ba);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CodeGenerator::generateSource(QString className, int indent) const
|
||||||
|
{
|
||||||
|
QByteArray ba;
|
||||||
|
{
|
||||||
|
QTextStream stream(&ba, QIODevice::WriteOnly);
|
||||||
|
stream.setCodec("UTF-8");
|
||||||
|
stream.setRealNumberPrecision(3);
|
||||||
|
stream.setRealNumberNotation(QTextStream::FixedNotation);
|
||||||
|
|
||||||
|
CodeGeneratorParameters parameters;
|
||||||
|
parameters.header = false;
|
||||||
|
parameters.indent = indent;
|
||||||
|
parameters.className = className;
|
||||||
|
m_storage->generateCode(stream, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString::fromUtf8(ba);
|
||||||
|
}
|
||||||
|
|
||||||
GeneratedFunction::GeneratedFunction(QObject* parent) :
|
GeneratedFunction::GeneratedFunction(QObject* parent) :
|
||||||
BaseClass(parent)
|
BaseClass(parent)
|
||||||
{
|
{
|
||||||
|
@ -274,6 +381,91 @@ GeneratedFunction* GeneratedFunction::clone(QObject* parent)
|
||||||
return qobject_cast<GeneratedFunction*>(Serializer::clone(this, parent));
|
return qobject_cast<GeneratedFunction*>(Serializer::clone(this, parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GeneratedFunction::generateCode(QTextStream& stream, CodeGeneratorParameters& parameters) const
|
||||||
|
{
|
||||||
|
QStringList parameterCaptions;
|
||||||
|
QStringList parameterTexts;
|
||||||
|
std::function<void (const GeneratedBase*, Pass)> gatherParameters = [&](const GeneratedBase* object, Pass pass)
|
||||||
|
{
|
||||||
|
if (pass != Pass::Enter)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const GeneratedParameter* generatedParameter = qobject_cast<const GeneratedParameter*>(object))
|
||||||
|
{
|
||||||
|
parameterCaptions << QString("%1 %2").arg(generatedParameter->getParameterName(), generatedParameter->getParameterDescription());
|
||||||
|
parameterTexts << QString("%1 %2").arg(getCppType(generatedParameter->getParameterDataType()), generatedParameter->getParameterName());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
applyFunctor(gatherParameters);
|
||||||
|
|
||||||
|
if (parameters.header)
|
||||||
|
{
|
||||||
|
// Generate header source code
|
||||||
|
|
||||||
|
// Function comments
|
||||||
|
for (const QString& string : getFormattedTextWithLayout("/// ", "/// ", getFunctionDescription(), parameters.indent))
|
||||||
|
{
|
||||||
|
stream << string << Qt::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function parameter comments
|
||||||
|
for (const QString& parameterCaption : parameterCaptions)
|
||||||
|
{
|
||||||
|
for (const QString& string : getFormattedTextWithLayout("/// \\param ", "/// ", parameterCaption, parameters.indent))
|
||||||
|
{
|
||||||
|
stream << string << Qt::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function declaration
|
||||||
|
QString functionHeader = QString("%1 %2(").arg(getCppType(getReturnType()), getFunctionName());
|
||||||
|
QString functionHeaderNext(functionHeader.length(), QChar(QChar::Space));
|
||||||
|
QString functionFooter = QString(");");
|
||||||
|
|
||||||
|
for (QString& str : parameterTexts)
|
||||||
|
{
|
||||||
|
str += ",";
|
||||||
|
}
|
||||||
|
parameterTexts.back().replace(",", functionFooter);
|
||||||
|
|
||||||
|
QStringList functionDeclaration = getFormattedTextBlock(functionHeader, functionHeaderNext, parameterTexts, parameters.indent);
|
||||||
|
for (const QString& functionDeclarationItem : functionDeclaration)
|
||||||
|
{
|
||||||
|
stream << functionDeclarationItem << Qt::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Generate c++ source code
|
||||||
|
QString functionHeader = QString("%1 %2::%3(").arg(getCppType(getReturnType()), parameters.className, getFunctionName());
|
||||||
|
QString functionHeaderNext(functionHeader.length(), QChar(QChar::Space));
|
||||||
|
QString functionFooter = QString(")");
|
||||||
|
|
||||||
|
for (QString& str : parameterTexts)
|
||||||
|
{
|
||||||
|
str += ",";
|
||||||
|
}
|
||||||
|
parameterTexts.back().replace(",", functionFooter);
|
||||||
|
|
||||||
|
QStringList functionDeclaration = getFormattedTextBlock(functionHeader, functionHeaderNext, parameterTexts, 0);
|
||||||
|
for (const QString& functionDeclarationItem : functionDeclaration)
|
||||||
|
{
|
||||||
|
stream << functionDeclarationItem << Qt::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString indent(parameters.indent, QChar(QChar::Space));
|
||||||
|
|
||||||
|
stream << "{" << Qt::endl;
|
||||||
|
stream << indent << "PDFObjectFactory objectBuilder;" << Qt::endl << Qt::endl;
|
||||||
|
|
||||||
|
generateSourceCode(stream, parameters);
|
||||||
|
|
||||||
|
stream << "}" << Qt::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool GeneratedFunction::hasField(GeneratedBase::FieldType fieldType) const
|
bool GeneratedFunction::hasField(GeneratedBase::FieldType fieldType) const
|
||||||
{
|
{
|
||||||
switch (fieldType)
|
switch (fieldType)
|
||||||
|
@ -552,6 +744,86 @@ void GeneratedAction::setCode(const QString& code)
|
||||||
m_code = code;
|
m_code = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GeneratedAction::generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, GeneratedBase::Pass pass) const
|
||||||
|
{
|
||||||
|
if (pass == Pass::Enter && getActionType() == Code)
|
||||||
|
{
|
||||||
|
QString indent(parameters.indent, QChar(QChar::Space));
|
||||||
|
QStringList lines = getCode().split(QChar('\n'), Qt::KeepEmptyParts, Qt::CaseInsensitive);
|
||||||
|
|
||||||
|
for (QString string : lines)
|
||||||
|
{
|
||||||
|
string = string.trimmed();
|
||||||
|
if (!string.isEmpty())
|
||||||
|
{
|
||||||
|
stream << indent << string << Qt::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stream << Qt::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pass == Pass::Leave && getActionType() == CreateObject)
|
||||||
|
{
|
||||||
|
QString indent(parameters.indent, QChar(QChar::Space));
|
||||||
|
|
||||||
|
switch (getVariableType())
|
||||||
|
{
|
||||||
|
case _PDFObject:
|
||||||
|
{
|
||||||
|
stream << indent << getCppType(getVariableType()) << " " << getVariableName() << " = objectBuilder.takeObject();";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case _PDFObjectReference:
|
||||||
|
{
|
||||||
|
stream << indent << getCppType(getVariableType()) << " " << getVariableName() << " = addObject(objectBuilder.takeObject());";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pass == Pass::Leave && getActionType() != Parameters && !parameters.isLastItem)
|
||||||
|
{
|
||||||
|
stream << Qt::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeneratedBase::generateSourceCode(QTextStream& stream, CodeGeneratorParameters& parameters) const
|
||||||
|
{
|
||||||
|
generateSourceCodeImpl(stream, parameters, Pass::Enter);
|
||||||
|
|
||||||
|
for (const QObject* object : m_items)
|
||||||
|
{
|
||||||
|
const GeneratedBase* generatedBase = qobject_cast<const GeneratedBase*>(object);
|
||||||
|
CodeGeneratorParameters parametersTemporary = parameters;
|
||||||
|
parametersTemporary.isFirstItem = object == m_items.front();
|
||||||
|
parametersTemporary.isLastItem = object == m_items.back();
|
||||||
|
generatedBase->generateSourceCode(stream, parametersTemporary);
|
||||||
|
}
|
||||||
|
|
||||||
|
generateSourceCodeImpl(stream, parameters, Pass::Leave);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeneratedBase::applyFunctor(std::function<void (const GeneratedBase*, Pass)>& functor) const
|
||||||
|
{
|
||||||
|
functor(this, Pass::Enter);
|
||||||
|
|
||||||
|
for (const QObject* object : m_items)
|
||||||
|
{
|
||||||
|
const GeneratedBase* generatedBase = qobject_cast<const GeneratedBase*>(object);
|
||||||
|
generatedBase->applyFunctor(functor);
|
||||||
|
}
|
||||||
|
|
||||||
|
functor(this, Pass::Leave);
|
||||||
|
}
|
||||||
|
|
||||||
bool GeneratedBase::canPerformOperation(Operation operation) const
|
bool GeneratedBase::canPerformOperation(Operation operation) const
|
||||||
{
|
{
|
||||||
const bool isFunction = qobject_cast<const GeneratedFunction*>(this) != nullptr;
|
const bool isFunction = qobject_cast<const GeneratedFunction*>(this) != nullptr;
|
||||||
|
@ -679,6 +951,73 @@ void GeneratedBase::clearItems()
|
||||||
m_items.clear();
|
m_items.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GeneratedBase::generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, GeneratedBase::Pass pass) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(stream);
|
||||||
|
Q_UNUSED(parameters);
|
||||||
|
Q_UNUSED(pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString GeneratedBase::getCppType(DataType type) const
|
||||||
|
{
|
||||||
|
return Serializer::convertEnumToString(type).mid(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList GeneratedBase::getFormattedTextWithLayout(QString firstPrefix, QString prefix, QString text, int indent) const
|
||||||
|
{
|
||||||
|
QFont font = QApplication::font();
|
||||||
|
QFontMetrics fontMetrics(font);
|
||||||
|
|
||||||
|
int usedLength = indent + qMax(firstPrefix.length(), prefix.length());
|
||||||
|
int length = 80 - usedLength;
|
||||||
|
QString testText(length, QChar('A'));
|
||||||
|
int width = fontMetrics.width(testText);
|
||||||
|
|
||||||
|
QTextLayout layout(text, font);
|
||||||
|
layout.setCacheEnabled(false);
|
||||||
|
QTextOption textOption = layout.textOption();
|
||||||
|
textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
|
||||||
|
layout.setTextOption(textOption);
|
||||||
|
|
||||||
|
layout.beginLayout();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
QTextLine textLine = layout.createLine();
|
||||||
|
if (!textLine.isValid())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
textLine.setLineWidth(width);
|
||||||
|
}
|
||||||
|
layout.endLayout();
|
||||||
|
|
||||||
|
QStringList texts;
|
||||||
|
const int lineCount = layout.lineCount();
|
||||||
|
for (int i = 0; i < lineCount; ++i)
|
||||||
|
{
|
||||||
|
QTextLine line = layout.lineAt(i);
|
||||||
|
texts << text.mid(line.textStart(), line.textLength());
|
||||||
|
}
|
||||||
|
return getFormattedTextBlock(firstPrefix, prefix, texts, indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList GeneratedBase::getFormattedTextBlock(QString firstPrefix, QString prefix, QStringList texts, int indent) const
|
||||||
|
{
|
||||||
|
QString indentText(indent, QChar(QChar::Space));
|
||||||
|
firstPrefix.prepend(indentText);
|
||||||
|
prefix.prepend(indentText);
|
||||||
|
|
||||||
|
QStringList result;
|
||||||
|
QString currentPrefix = firstPrefix;
|
||||||
|
for (const QString& text : texts)
|
||||||
|
{
|
||||||
|
result << QString("%1%2").arg(currentPrefix, text);
|
||||||
|
currentPrefix = prefix;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
GeneratedPDFObject::GeneratedPDFObject(QObject* parent) :
|
GeneratedPDFObject::GeneratedPDFObject(QObject* parent) :
|
||||||
BaseClass(parent)
|
BaseClass(parent)
|
||||||
{
|
{
|
||||||
|
@ -844,6 +1183,89 @@ void GeneratedPDFObject::setDictionaryItemName(const QString& dictionaryItemName
|
||||||
m_dictionaryItemName = dictionaryItemName;
|
m_dictionaryItemName = dictionaryItemName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GeneratedPDFObject::generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, GeneratedBase::Pass pass) const
|
||||||
|
{
|
||||||
|
QString indent(parameters.indent, QChar(QChar::Space));
|
||||||
|
QString writeTo("objectBuilder << ");
|
||||||
|
|
||||||
|
switch (getObjectType())
|
||||||
|
{
|
||||||
|
case codegen::GeneratedPDFObject::Object:
|
||||||
|
{
|
||||||
|
if (pass == Pass::Enter)
|
||||||
|
{
|
||||||
|
stream << indent << writeTo << getValue().trimmed() << ";" << Qt::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case codegen::GeneratedPDFObject::ArraySimple:
|
||||||
|
{
|
||||||
|
if (pass == Pass::Enter)
|
||||||
|
{
|
||||||
|
stream << indent << "objectBuilder.beginArray();" << Qt::endl;
|
||||||
|
stream << indent << writeTo << getValue().trimmed() << ";" << Qt::endl;
|
||||||
|
stream << indent << "objectBuilder.endArray();" << Qt::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case codegen::GeneratedPDFObject::ArrayComplex:
|
||||||
|
{
|
||||||
|
if (pass == Pass::Enter)
|
||||||
|
{
|
||||||
|
stream << indent << "objectBuilder.beginArray();" << Qt::endl;
|
||||||
|
}
|
||||||
|
if (pass == Pass::Leave)
|
||||||
|
{
|
||||||
|
stream << indent << "objectBuilder.endArray();" << Qt::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case codegen::GeneratedPDFObject::Dictionary:
|
||||||
|
{
|
||||||
|
if (pass == Pass::Enter)
|
||||||
|
{
|
||||||
|
stream << indent << "objectBuilder.beginDictionary();" << Qt::endl;
|
||||||
|
}
|
||||||
|
if (pass == Pass::Leave)
|
||||||
|
{
|
||||||
|
stream << indent << "objectBuilder.endDictionary();" << Qt::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case codegen::GeneratedPDFObject::DictionaryItemSimple:
|
||||||
|
{
|
||||||
|
if (pass == Pass::Enter)
|
||||||
|
{
|
||||||
|
stream << indent << QString("objectBuilder.beginDictionaryItem(\"%1\");").arg(getDictionaryItemName()) << Qt::endl;
|
||||||
|
stream << indent << writeTo << getValue().trimmed() << ";" << Qt::endl;
|
||||||
|
stream << indent << "objectBuilder.endDictionaryItem();" << Qt::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case codegen::GeneratedPDFObject::DictionaryItemComplex:
|
||||||
|
{
|
||||||
|
if (pass == Pass::Enter)
|
||||||
|
{
|
||||||
|
stream << indent << QString("objectBuilder.beginDictionaryItem(\"%1\");").arg(getDictionaryItemName()) << Qt::endl;
|
||||||
|
}
|
||||||
|
if (pass == Pass::Leave)
|
||||||
|
{
|
||||||
|
stream << indent << "objectBuilder.endDictionaryItem();" << Qt::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GeneratedParameter::GeneratedParameter(QObject* parent) :
|
GeneratedParameter::GeneratedParameter(QObject* parent) :
|
||||||
BaseClass(parent)
|
BaseClass(parent)
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,6 +29,15 @@
|
||||||
namespace codegen
|
namespace codegen
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct CodeGeneratorParameters
|
||||||
|
{
|
||||||
|
bool header = false;
|
||||||
|
int indent = 0;
|
||||||
|
QString className;
|
||||||
|
bool isFirstItem = false;
|
||||||
|
bool isLastItem = false;
|
||||||
|
};
|
||||||
|
|
||||||
class Serializer
|
class Serializer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -97,6 +106,8 @@ public:
|
||||||
GeneratedFunction* addFunction(GeneratedFunction* function);
|
GeneratedFunction* addFunction(GeneratedFunction* function);
|
||||||
void removeFunction(GeneratedFunction* function);
|
void removeFunction(GeneratedFunction* function);
|
||||||
|
|
||||||
|
void generateCode(QTextStream& stream, CodeGeneratorParameters& parameters) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QObjectList m_functions;
|
QObjectList m_functions;
|
||||||
};
|
};
|
||||||
|
@ -147,6 +158,15 @@ public:
|
||||||
virtual QStringList getCaptions() const = 0;
|
virtual QStringList getCaptions() const = 0;
|
||||||
virtual GeneratedBase* appendItem() = 0;
|
virtual GeneratedBase* appendItem() = 0;
|
||||||
|
|
||||||
|
enum class Pass
|
||||||
|
{
|
||||||
|
Enter,
|
||||||
|
Leave
|
||||||
|
};
|
||||||
|
|
||||||
|
void generateSourceCode(QTextStream& stream, CodeGeneratorParameters& parameters) const;
|
||||||
|
void applyFunctor(std::function<void(const GeneratedBase*, Pass)>& functor) const;
|
||||||
|
|
||||||
enum class Operation
|
enum class Operation
|
||||||
{
|
{
|
||||||
Delete,
|
Delete,
|
||||||
|
@ -167,6 +187,13 @@ public:
|
||||||
void removeItem(QObject* object);
|
void removeItem(QObject* object);
|
||||||
void clearItems();
|
void clearItems();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, Pass pass) const;
|
||||||
|
|
||||||
|
QString getCppType(DataType type) const;
|
||||||
|
QStringList getFormattedTextWithLayout(QString firstPrefix, QString prefix, QString text, int indent) const;
|
||||||
|
QStringList getFormattedTextBlock(QString firstPrefix, QString prefix, QStringList texts, int indent) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QObjectList m_items;
|
QObjectList m_items;
|
||||||
};
|
};
|
||||||
|
@ -249,6 +276,9 @@ public:
|
||||||
QString getDictionaryItemName() const;
|
QString getDictionaryItemName() const;
|
||||||
void setDictionaryItemName(const QString& dictionaryItemName);
|
void setDictionaryItemName(const QString& dictionaryItemName);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, Pass pass) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_dictionaryItemName;
|
QString m_dictionaryItemName;
|
||||||
ObjectType m_objectType = Object;
|
ObjectType m_objectType = Object;
|
||||||
|
@ -298,6 +328,9 @@ public:
|
||||||
QString getCode() const;
|
QString getCode() const;
|
||||||
void setCode(const QString& code);
|
void setCode(const QString& code);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void generateSourceCodeImpl(QTextStream& stream, CodeGeneratorParameters& parameters, Pass pass) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ActionType m_actionType;
|
ActionType m_actionType;
|
||||||
QString m_variableName;
|
QString m_variableName;
|
||||||
|
@ -355,6 +388,8 @@ public:
|
||||||
/// Create a clone of this function
|
/// Create a clone of this function
|
||||||
GeneratedFunction* clone(QObject* parent);
|
GeneratedFunction* clone(QObject* parent);
|
||||||
|
|
||||||
|
void generateCode(QTextStream& stream, CodeGeneratorParameters& parameters) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FunctionType m_functionType = FunctionType::Annotations;
|
FunctionType m_functionType = FunctionType::Annotations;
|
||||||
QString m_functionName;
|
QString m_functionName;
|
||||||
|
@ -382,7 +417,12 @@ public:
|
||||||
void load(const QDomDocument& document);
|
void load(const QDomDocument& document);
|
||||||
void store(QDomDocument& document);
|
void store(QDomDocument& document);
|
||||||
|
|
||||||
|
void generateCode(QString headerName, QString sourceName) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QString generateHeader(int indent) const;
|
||||||
|
QString generateSource(QString className, int indent) const;
|
||||||
|
|
||||||
GeneratedCodeStorage* m_storage = nullptr;
|
GeneratedCodeStorage* m_storage = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,8 @@ void GeneratorMainWindow::saveSettings()
|
||||||
{
|
{
|
||||||
QSettings settings("MelkaJ");
|
QSettings settings("MelkaJ");
|
||||||
settings.setValue("fileName", m_defaultFileName);
|
settings.setValue("fileName", m_defaultFileName);
|
||||||
|
settings.setValue("headerFile", m_headerFileName);
|
||||||
|
settings.setValue("sourceFile", m_sourceFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneratorMainWindow::loadGeneratedSettings()
|
void GeneratorMainWindow::loadGeneratedSettings()
|
||||||
|
@ -349,6 +351,8 @@ void GeneratorMainWindow::loadSettings()
|
||||||
{
|
{
|
||||||
QSettings settings("MelkaJ");
|
QSettings settings("MelkaJ");
|
||||||
m_defaultFileName = settings.value("fileName").toString();
|
m_defaultFileName = settings.value("fileName").toString();
|
||||||
|
m_headerFileName = settings.value("headerFile", QVariant()).toString();
|
||||||
|
m_sourceFileName = settings.value("sourceFile", QVariant()).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneratorMainWindow::save(const QString& fileName)
|
void GeneratorMainWindow::save(const QString& fileName)
|
||||||
|
@ -486,3 +490,31 @@ void GeneratorMainWindow::on_itemNewSiblingButton_clicked()
|
||||||
loadGeneratedSettings();
|
loadGeneratedSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GeneratorMainWindow::on_actionSet_code_header_h_triggered()
|
||||||
|
{
|
||||||
|
QString fileName = QFileDialog::getOpenFileName(this, tr("Select cpp header"), QString(), "cpp header (*.h)");
|
||||||
|
if (!fileName.isEmpty())
|
||||||
|
{
|
||||||
|
m_headerFileName = fileName;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeneratorMainWindow::on_actionSet_code_source_cpp_triggered()
|
||||||
|
{
|
||||||
|
QString fileName = QFileDialog::getOpenFileName(this, tr("Select cpp source"), QString(), "cpp source (*.cpp)");
|
||||||
|
if (!fileName.isEmpty())
|
||||||
|
{
|
||||||
|
m_sourceFileName = fileName;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeneratorMainWindow::on_actionGenerate_code_triggered()
|
||||||
|
{
|
||||||
|
if (m_generator)
|
||||||
|
{
|
||||||
|
m_generator->generateCode(m_headerFileName, m_sourceFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -77,6 +77,9 @@ private slots:
|
||||||
void on_itemDownButton_clicked();
|
void on_itemDownButton_clicked();
|
||||||
void on_itemNewChildButton_clicked();
|
void on_itemNewChildButton_clicked();
|
||||||
void on_itemNewSiblingButton_clicked();
|
void on_itemNewSiblingButton_clicked();
|
||||||
|
void on_actionSet_code_header_h_triggered();
|
||||||
|
void on_actionSet_code_source_cpp_triggered();
|
||||||
|
void on_actionGenerate_code_triggered();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadSettings();
|
void loadSettings();
|
||||||
|
@ -97,6 +100,8 @@ private:
|
||||||
codegen::GeneratedFunction* m_currentFunction;
|
codegen::GeneratedFunction* m_currentFunction;
|
||||||
codegen::GeneratedBase* m_currentSettings;
|
codegen::GeneratedBase* m_currentSettings;
|
||||||
QString m_defaultFileName;
|
QString m_defaultFileName;
|
||||||
|
QString m_headerFileName;
|
||||||
|
QString m_sourceFileName;
|
||||||
std::map<codegen::GeneratedFunction*, QTreeWidgetItem*> m_mapFunctionToWidgetItem;
|
std::map<codegen::GeneratedFunction*, QTreeWidgetItem*> m_mapFunctionToWidgetItem;
|
||||||
bool m_isLoadingData;
|
bool m_isLoadingData;
|
||||||
};
|
};
|
||||||
|
|
|
@ -233,7 +233,16 @@
|
||||||
<addaction name="actionSave"/>
|
<addaction name="actionSave"/>
|
||||||
<addaction name="actionSaveAs"/>
|
<addaction name="actionSaveAs"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuCode">
|
||||||
|
<property name="title">
|
||||||
|
<string>Code</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionSet_code_header_h"/>
|
||||||
|
<addaction name="actionSet_code_source_cpp"/>
|
||||||
|
<addaction name="actionGenerate_code"/>
|
||||||
|
</widget>
|
||||||
<addaction name="menuFile"/>
|
<addaction name="menuFile"/>
|
||||||
|
<addaction name="menuCode"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusbar"/>
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
<action name="actionLoad">
|
<action name="actionLoad">
|
||||||
|
@ -257,6 +266,24 @@
|
||||||
<string>Save As...</string>
|
<string>Save As...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionSet_code_header_h">
|
||||||
|
<property name="text">
|
||||||
|
<string>Set code header (*.h)</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSet_code_source_cpp">
|
||||||
|
<property name="text">
|
||||||
|
<string>Set code source (*.cpp)</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionGenerate_code">
|
||||||
|
<property name="text">
|
||||||
|
<string>Generate code</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+G</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|
|
@ -232,6 +232,11 @@ PDFObjectReference PDFObjectStorage::addObject(PDFObject object)
|
||||||
return reference;
|
return reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFObjectStorage::setObject(PDFObjectReference reference, PDFObject object)
|
||||||
|
{
|
||||||
|
m_objects[reference.objectNumber] = Entry(reference.generation, qMove(object));
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray PDFDocumentDataLoaderDecorator::readName(const PDFObject& object)
|
QByteArray PDFDocumentDataLoaderDecorator::readName(const PDFObject& object)
|
||||||
{
|
{
|
||||||
const PDFObject& dereferencedObject = m_document->getObject(object);
|
const PDFObject& dereferencedObject = m_document->getObject(object);
|
||||||
|
|
|
@ -84,6 +84,11 @@ public:
|
||||||
/// \returns Reference to new object
|
/// \returns Reference to new object
|
||||||
PDFObjectReference addObject(PDFObject object);
|
PDFObjectReference addObject(PDFObject object);
|
||||||
|
|
||||||
|
/// Sets object to object storage. Reference must exist.
|
||||||
|
/// \param reference Reference to object
|
||||||
|
/// \param object New value of object
|
||||||
|
void setObject(PDFObjectReference reference, PDFObject object);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PDFObjects m_objects;
|
PDFObjects m_objects;
|
||||||
PDFObject m_trailerDictionary;
|
PDFObject m_trailerDictionary;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "pdfdocumentbuilder.h"
|
#include "pdfdocumentbuilder.h"
|
||||||
|
#include "pdfencoding.h"
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
|
@ -62,6 +63,82 @@ void PDFObjectFactory::endDictionaryItem()
|
||||||
std::get<PDFDictionary>(dictionaryItem.object).addEntry(qMove(topItem.itemName), qMove(std::get<PDFObject>(topItem.object)));
|
std::get<PDFDictionary>(dictionaryItem.object).addEntry(qMove(topItem.itemName), qMove(std::get<PDFObject>(topItem.object)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFObjectFactory& PDFObjectFactory::operator<<(QString textString)
|
||||||
|
{
|
||||||
|
if (!PDFEncoding::canConvertToEncoding(textString, PDFEncoding::Encoding::PDFDoc))
|
||||||
|
{
|
||||||
|
// Use unicode encoding
|
||||||
|
QByteArray ba;
|
||||||
|
|
||||||
|
{
|
||||||
|
QTextStream textStream(&ba, QIODevice::WriteOnly);
|
||||||
|
textStream.setCodec("UTF-16BE");
|
||||||
|
textStream.setGenerateByteOrderMark(true);
|
||||||
|
textStream << textString;
|
||||||
|
}
|
||||||
|
|
||||||
|
addObject(PDFObject::createString(std::make_shared<PDFString>(qMove(ba))));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use PDF document encoding
|
||||||
|
addObject(PDFObject::createString(std::make_shared<PDFString>(PDFEncoding::convertToEncoding(textString, PDFEncoding::Encoding::PDFDoc))));
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFObjectFactory& PDFObjectFactory::operator<<(WrapAnnotationColor color)
|
||||||
|
{
|
||||||
|
if (color.color.isValid())
|
||||||
|
{
|
||||||
|
// Jakub Melka: we will decide, if we have gray/rgb/cmyk color
|
||||||
|
QColor value = color.color;
|
||||||
|
if (value.spec() == QColor::Cmyk)
|
||||||
|
{
|
||||||
|
*this << std::initializer_list<PDFReal>{ value.cyanF(), value.magentaF(), value.yellowF(), value.blackF() };
|
||||||
|
}
|
||||||
|
else if (qIsGray(value.rgb()))
|
||||||
|
{
|
||||||
|
*this << std::initializer_list<PDFReal>{ value.redF() };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*this << std::initializer_list<PDFReal>{ value.redF(), value.greenF(), value.blueF() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addObject(PDFObject::createNull());
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFObjectFactory& PDFObjectFactory::operator<<(WrapCurrentDateTime)
|
||||||
|
{
|
||||||
|
addObject(PDFObject::createString(std::make_shared<PDFString>(PDFEncoding::converDateTimeToString(QDateTime::currentDateTime()))));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFObjectFactory& PDFObjectFactory::operator<<(const QRectF& value)
|
||||||
|
{
|
||||||
|
*this << std::initializer_list<PDFReal>{ value.left(), value.top(), value.right(), value.bottom() };
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFObjectFactory& PDFObjectFactory::operator<<(int value)
|
||||||
|
{
|
||||||
|
*this << PDFInteger(value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFObjectFactory& PDFObjectFactory::operator<<(WrapName wrapName)
|
||||||
|
{
|
||||||
|
addObject(PDFObject::createName(std::make_shared<PDFString>(qMove(wrapName.name))));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
PDFObject PDFObjectFactory::takeObject()
|
PDFObject PDFObjectFactory::takeObject()
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_items.size() == 1);
|
Q_ASSERT(m_items.size() == 1);
|
||||||
|
@ -154,8 +231,111 @@ PDFDocument PDFDocumentBuilder::build() const
|
||||||
return PDFDocument(PDFObjectStorage(m_storage), m_version);
|
return PDFDocument(PDFObjectStorage(m_storage), m_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFObjectReference PDFDocumentBuilder::addObject(PDFObject object)
|
||||||
|
{
|
||||||
|
return m_storage.addObject(PDFObjectManipulator::removeNullObjects(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFDocumentBuilder::mergeTo(PDFObjectReference reference, PDFObject object)
|
||||||
|
{
|
||||||
|
m_storage.setObject(reference, PDFObjectManipulator::merge(m_storage.getObject(reference), qMove(object), PDFObjectManipulator::RemoveNullObjects));
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF PDFDocumentBuilder::getPopupWindowRect(const QRectF& rectangle) const
|
||||||
|
{
|
||||||
|
return rectangle.translated(rectangle.width() * 1.25, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* START GENERATED CODE */
|
/* START GENERATED CODE */
|
||||||
|
|
||||||
|
PDFObjectReference PDFDocumentBuilder::createAnnotationSquare(PDFObjectReference page,
|
||||||
|
QRectF rectangle,
|
||||||
|
PDFReal borderWidth,
|
||||||
|
QColor fillColor,
|
||||||
|
QColor strokeColor,
|
||||||
|
QString title,
|
||||||
|
QString subject,
|
||||||
|
QString contents)
|
||||||
|
{
|
||||||
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Subtype");
|
||||||
|
objectBuilder << WrapName("Square");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Rect");
|
||||||
|
objectBuilder << rectangle;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("F");
|
||||||
|
objectBuilder << 4;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("P");
|
||||||
|
objectBuilder << page;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("M");
|
||||||
|
objectBuilder << WrapCurrentDateTime();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("CreationDate");
|
||||||
|
objectBuilder << WrapCurrentDateTime();
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Border");
|
||||||
|
objectBuilder << std::initializer_list<PDFReal>{ 0.0, 0.0, borderWidth };
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("C");
|
||||||
|
objectBuilder << WrapAnnotationColor(strokeColor);
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("IC");
|
||||||
|
objectBuilder << WrapAnnotationColor(fillColor);
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("T");
|
||||||
|
objectBuilder << title;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Contents");
|
||||||
|
objectBuilder << contents;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Subj");
|
||||||
|
objectBuilder << subject;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObjectReference annotationObject = addObject(objectBuilder.takeObject());
|
||||||
|
PDFObjectReference popupAnnotation = createAnnotationPopup(page, annotationObject, getPopupWindowRect(rectangle), false);
|
||||||
|
|
||||||
|
objectBuilder.beginDictionaryItem("Popup");
|
||||||
|
objectBuilder << popupAnnotation;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
PDFObject updateAnnotationPopup = objectBuilder.takeObject();
|
||||||
|
mergeTo(annotationObject, updateAnnotationPopup);
|
||||||
|
return PDFObjectReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFObjectReference PDFDocumentBuilder::createAnnotationPopup(PDFObjectReference page,
|
||||||
|
PDFObjectReference parentAnnotation,
|
||||||
|
QRectF rectangle,
|
||||||
|
bool opened)
|
||||||
|
{
|
||||||
|
PDFObjectFactory objectBuilder;
|
||||||
|
|
||||||
|
objectBuilder.beginDictionary();
|
||||||
|
objectBuilder.beginDictionaryItem("Subtype");
|
||||||
|
objectBuilder << WrapName("Popup");
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Rect");
|
||||||
|
objectBuilder << rectangle;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("P");
|
||||||
|
objectBuilder << page;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Parent");
|
||||||
|
objectBuilder << parentAnnotation;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.beginDictionaryItem("Open");
|
||||||
|
objectBuilder << opened;
|
||||||
|
objectBuilder.endDictionaryItem();
|
||||||
|
objectBuilder.endDictionary();
|
||||||
|
PDFObjectReference popupAnnotation = addObject(objectBuilder.takeObject());
|
||||||
|
return popupAnnotation;
|
||||||
|
}
|
||||||
|
|
||||||
/* END GENERATED CODE */
|
/* END GENERATED CODE */
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
|
@ -24,6 +24,30 @@
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct WrapName
|
||||||
|
{
|
||||||
|
WrapName(const char* name) :
|
||||||
|
name(name)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WrapAnnotationColor
|
||||||
|
{
|
||||||
|
WrapAnnotationColor(QColor color) :
|
||||||
|
color(color)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WrapCurrentDateTime { };
|
||||||
|
|
||||||
/// Factory for creating various PDF objects, such as simple objects,
|
/// Factory for creating various PDF objects, such as simple objects,
|
||||||
/// dictionaries, arrays etc.
|
/// dictionaries, arrays etc.
|
||||||
class PDFObjectFactory
|
class PDFObjectFactory
|
||||||
|
@ -45,6 +69,12 @@ public:
|
||||||
PDFObjectFactory& operator<<(PDFReal value);
|
PDFObjectFactory& operator<<(PDFReal value);
|
||||||
PDFObjectFactory& operator<<(PDFInteger value);
|
PDFObjectFactory& operator<<(PDFInteger value);
|
||||||
PDFObjectFactory& operator<<(PDFObjectReference value);
|
PDFObjectFactory& operator<<(PDFObjectReference value);
|
||||||
|
PDFObjectFactory& operator<<(WrapName wrapName);
|
||||||
|
PDFObjectFactory& operator<<(int value);
|
||||||
|
PDFObjectFactory& operator<<(const QRectF& value);
|
||||||
|
PDFObjectFactory& operator<<(WrapCurrentDateTime);
|
||||||
|
PDFObjectFactory& operator<<(WrapAnnotationColor color);
|
||||||
|
PDFObjectFactory& operator<<(QString textString);
|
||||||
|
|
||||||
/// Treat containers - write them as array
|
/// Treat containers - write them as array
|
||||||
template<typename Container, typename ValueType = decltype(*std::begin(std::declval<Container>()))>
|
template<typename Container, typename ValueType = decltype(*std::begin(std::declval<Container>()))>
|
||||||
|
@ -119,11 +149,52 @@ public:
|
||||||
|
|
||||||
PDFDocument build() const;
|
PDFDocument build() const;
|
||||||
|
|
||||||
/* START GENERATED CODE */
|
/* START GENERATED CODE */
|
||||||
|
|
||||||
/* END GENERATED CODE */
|
/// Square annotation displays rectangle (or square). When opened, they display pop-up window
|
||||||
|
/// containing the text of associated note (and window title). Square border/fill color can be defined,
|
||||||
|
/// along with border width.
|
||||||
|
/// \param page Page to which is annotation added
|
||||||
|
/// \param rectangle Area in which is rectangle displayed
|
||||||
|
/// \param borderWidth Width of the border line of rectangle
|
||||||
|
/// \param fillColor Fill color of rectangle (interior color). If you do not want to have area color filled,
|
||||||
|
/// then use invalid QColor.
|
||||||
|
/// \param strokeColor Stroke color (color of the rectangle border). If you do not want to have a
|
||||||
|
/// border, then use invalid QColor.
|
||||||
|
/// \param title Title (it is displayed as title of popup window)
|
||||||
|
/// \param subject Subject (short description of the subject being adressed by the annotation)
|
||||||
|
/// \param contents Contents (text displayed, for example, in the marked annotation dialog)
|
||||||
|
PDFObjectReference createAnnotationSquare(PDFObjectReference page,
|
||||||
|
QRectF rectangle,
|
||||||
|
PDFReal borderWidth,
|
||||||
|
QColor fillColor,
|
||||||
|
QColor strokeColor,
|
||||||
|
QString title,
|
||||||
|
QString subject,
|
||||||
|
QString contents);
|
||||||
|
|
||||||
|
|
||||||
|
/// Creates a new popup annotation on the page. Popup annotation is represented usually by floating
|
||||||
|
/// window, which can be opened, or closed. Popup annotation is associated with parent annotation,
|
||||||
|
/// which can be usually markup annotation. Popup annotation displays parent annotation's texts, for
|
||||||
|
/// example, title, comment, date etc.
|
||||||
|
/// \param page Page to which is annotation added
|
||||||
|
/// \param parentAnnotation Parent annotation (for which is popup window displayed)
|
||||||
|
/// \param rectangle Area on the page, where popup window appears
|
||||||
|
/// \param opened Is the window opened?
|
||||||
|
PDFObjectReference createAnnotationPopup(PDFObjectReference page,
|
||||||
|
PDFObjectReference parentAnnotation,
|
||||||
|
QRectF rectangle,
|
||||||
|
bool opened);
|
||||||
|
|
||||||
|
|
||||||
|
/* END GENERATED CODE */
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
PDFObjectReference addObject(PDFObject object);
|
||||||
|
void mergeTo(PDFObjectReference reference, PDFObject object);
|
||||||
|
QRectF getPopupWindowRect(const QRectF& rectangle) const;
|
||||||
|
|
||||||
PDFObjectStorage m_storage;
|
PDFObjectStorage m_storage;
|
||||||
PDFVersion m_version;
|
PDFVersion m_version;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2149,6 +2149,7 @@ QByteArray PDFEncoding::convertToEncoding(const QString& string, PDFEncoding::En
|
||||||
if (unicode == (*table)[static_cast<unsigned char>(i)])
|
if (unicode == (*table)[static_cast<unsigned char>(i)])
|
||||||
{
|
{
|
||||||
converted = i;
|
converted = i;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2158,6 +2159,34 @@ QByteArray PDFEncoding::convertToEncoding(const QString& string, PDFEncoding::En
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PDFEncoding::canConvertToEncoding(const QString& string, PDFEncoding::Encoding encoding)
|
||||||
|
{
|
||||||
|
const encoding::EncodingTable* table = getTableForEncoding(encoding);
|
||||||
|
Q_ASSERT(table);
|
||||||
|
|
||||||
|
for (QChar character : string)
|
||||||
|
{
|
||||||
|
ushort unicode = character.unicode();
|
||||||
|
bool converted = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < table->size(); ++i)
|
||||||
|
{
|
||||||
|
if (unicode == (*table)[static_cast<unsigned char>(i)])
|
||||||
|
{
|
||||||
|
converted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!converted)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
QString PDFEncoding::convertTextString(const QByteArray& stream)
|
QString PDFEncoding::convertTextString(const QByteArray& stream)
|
||||||
{
|
{
|
||||||
if (hasUnicodeLeadMarkings(stream))
|
if (hasUnicodeLeadMarkings(stream))
|
||||||
|
@ -2259,6 +2288,13 @@ QDateTime PDFEncoding::convertToDateTime(const QByteArray& stream)
|
||||||
return QDateTime();
|
return QDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray PDFEncoding::converDateTimeToString(QDateTime dateTime)
|
||||||
|
{
|
||||||
|
QDateTime utcDateTime = dateTime.toUTC();
|
||||||
|
QString convertedDateTime = QString("D:%1").arg(utcDateTime.toString("yyyyMMddhhmmss"));
|
||||||
|
return convertedDateTime.toLatin1();
|
||||||
|
}
|
||||||
|
|
||||||
const encoding::EncodingTable* PDFEncoding::getTableForEncoding(Encoding encoding)
|
const encoding::EncodingTable* PDFEncoding::getTableForEncoding(Encoding encoding)
|
||||||
{
|
{
|
||||||
switch (encoding)
|
switch (encoding)
|
||||||
|
|
|
@ -70,6 +70,13 @@ public:
|
||||||
/// \sa convert
|
/// \sa convert
|
||||||
static QByteArray convertToEncoding(const QString& string, Encoding encoding);
|
static QByteArray convertToEncoding(const QString& string, Encoding encoding);
|
||||||
|
|
||||||
|
/// Verifies, if string with given unicode characters can be converted using
|
||||||
|
/// the specified encoding (so, all unicode characters present in the string
|
||||||
|
/// are also present in given encoding).
|
||||||
|
/// \param string String to be tested
|
||||||
|
/// \param encoding Encoding used in verification of conversion
|
||||||
|
static bool canConvertToEncoding(const QString& string, Encoding encoding);
|
||||||
|
|
||||||
/// Convert text string to the unicode string, using either PDFDocEncoding,
|
/// Convert text string to the unicode string, using either PDFDocEncoding,
|
||||||
/// or UTF-16BE encoding. Please see PDF Reference 1.7, Chapter 3.8.1. If
|
/// or UTF-16BE encoding. Please see PDF Reference 1.7, Chapter 3.8.1. If
|
||||||
/// UTF-16BE encoding is used, then leading bytes should be 0xFE and 0xFF
|
/// UTF-16BE encoding is used, then leading bytes should be 0xFE and 0xFF
|
||||||
|
@ -88,6 +95,11 @@ public:
|
||||||
/// \param stream Stream, from which date/time is read
|
/// \param stream Stream, from which date/time is read
|
||||||
static QDateTime convertToDateTime(const QByteArray& stream);
|
static QDateTime convertToDateTime(const QByteArray& stream);
|
||||||
|
|
||||||
|
/// Convert date/time to string according to PDF Reference 1.7, Chapter 3.8.1.
|
||||||
|
/// If date is invalid, empty byte array is returned.
|
||||||
|
/// \param dateTime Date and time to be converted
|
||||||
|
static QByteArray converDateTimeToString(QDateTime dateTime);
|
||||||
|
|
||||||
/// Returns conversion table for particular encoding
|
/// Returns conversion table for particular encoding
|
||||||
/// \param encoding Encoding
|
/// \param encoding Encoding
|
||||||
static const encoding::EncodingTable* getTableForEncoding(Encoding encoding);
|
static const encoding::EncodingTable* getTableForEncoding(Encoding encoding);
|
||||||
|
|
|
@ -204,6 +204,25 @@ const PDFObject& PDFDictionary::get(const char* key) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFDictionary::setEntry(const QByteArray& key, PDFObject&& value)
|
||||||
|
{
|
||||||
|
auto it = find(key);
|
||||||
|
if (it != m_dictionary.end())
|
||||||
|
{
|
||||||
|
it->second = qMove(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addEntry(QByteArray(key), qMove(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFDictionary::removeNullObjects()
|
||||||
|
{
|
||||||
|
m_dictionary.erase(std::remove_if(m_dictionary.begin(), m_dictionary.end(), [](const DictionaryEntry& entry) { return entry.second.isNull(); }), m_dictionary.end());
|
||||||
|
m_dictionary.shrink_to_fit();
|
||||||
|
}
|
||||||
|
|
||||||
void PDFDictionary::optimize()
|
void PDFDictionary::optimize()
|
||||||
{
|
{
|
||||||
m_dictionary.shrink_to_fit();
|
m_dictionary.shrink_to_fit();
|
||||||
|
@ -219,6 +238,11 @@ std::vector<PDFDictionary::DictionaryEntry>::const_iterator PDFDictionary::find(
|
||||||
return std::find_if(m_dictionary.cbegin(), m_dictionary.cend(), [&key](const DictionaryEntry& entry) { return entry.first == key; });
|
return std::find_if(m_dictionary.cbegin(), m_dictionary.cend(), [&key](const DictionaryEntry& entry) { return entry.first == key; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<PDFDictionary::DictionaryEntry>::iterator PDFDictionary::find(const QByteArray& key)
|
||||||
|
{
|
||||||
|
return std::find_if(m_dictionary.begin(), m_dictionary.end(), [&key](const DictionaryEntry& entry) { return entry.first == key; });
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<PDFDictionary::DictionaryEntry>::const_iterator PDFDictionary::find(const char* key) const
|
std::vector<PDFDictionary::DictionaryEntry>::const_iterator PDFDictionary::find(const char* key) const
|
||||||
{
|
{
|
||||||
return std::find_if(m_dictionary.cbegin(), m_dictionary.cend(), [&key](const DictionaryEntry& entry) { return entry.first == key; });
|
return std::find_if(m_dictionary.cbegin(), m_dictionary.cend(), [&key](const DictionaryEntry& entry) { return entry.first == key; });
|
||||||
|
@ -231,4 +255,59 @@ bool PDFStream::equals(const PDFObjectContent* other) const
|
||||||
return m_dictionary.equals(&otherStream->m_dictionary) && m_content == otherStream->m_content;
|
return m_dictionary.equals(&otherStream->m_dictionary) && m_content == otherStream->m_content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFObject PDFObjectManipulator::merge(PDFObject left, PDFObject right, MergeFlags flags)
|
||||||
|
{
|
||||||
|
if (left.getType() != right.getType())
|
||||||
|
{
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left.isDictionary())
|
||||||
|
{
|
||||||
|
Q_ASSERT(right.isDictionary());
|
||||||
|
|
||||||
|
PDFDictionary targetDictionary = *left.getDictionary();
|
||||||
|
const PDFDictionary& sourceDictionary = *right.getDictionary();
|
||||||
|
|
||||||
|
for (size_t i = 0, count = sourceDictionary.getCount(); i < count; ++i)
|
||||||
|
{
|
||||||
|
const QByteArray& key = sourceDictionary.getKey(i);
|
||||||
|
PDFObject value = merge(targetDictionary.get(key), sourceDictionary.getValue(i), flags);
|
||||||
|
targetDictionary.setEntry(key, qMove(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.testFlag(RemoveNullObjects))
|
||||||
|
{
|
||||||
|
targetDictionary.removeNullObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
return PDFObject::createDictionary(std::make_shared<PDFDictionary>(qMove(targetDictionary)));
|
||||||
|
}
|
||||||
|
else if (left.isArray() && flags.testFlag(ConcatenateArrays))
|
||||||
|
{
|
||||||
|
// Concatenate arrays
|
||||||
|
const PDFArray* leftArray = left.getArray();
|
||||||
|
const PDFArray* rightArray = right.getArray();
|
||||||
|
|
||||||
|
std::vector<PDFObject> objects;
|
||||||
|
objects.reserve(leftArray->getCount() + rightArray->getCount());
|
||||||
|
for (size_t i = 0, count = leftArray->getCount(); i < count; ++i)
|
||||||
|
{
|
||||||
|
objects.emplace_back(leftArray->getItem(i));
|
||||||
|
}
|
||||||
|
for (size_t i = 0, count = rightArray->getCount(); i < count; ++i)
|
||||||
|
{
|
||||||
|
objects.emplace_back(rightArray->getItem(i));
|
||||||
|
}
|
||||||
|
return PDFObject::createArray(std::make_shared<PDFArray>(qMove(objects)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFObject PDFObjectManipulator::removeNullObjects(PDFObject object)
|
||||||
|
{
|
||||||
|
return merge(object, object, RemoveNullObjects);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
|
@ -95,6 +95,8 @@ public:
|
||||||
constexpr inline PDFObject& operator=(const PDFObject&) = default;
|
constexpr inline PDFObject& operator=(const PDFObject&) = default;
|
||||||
constexpr inline PDFObject& operator=(PDFObject&&) = default;
|
constexpr inline PDFObject& operator=(PDFObject&&) = default;
|
||||||
|
|
||||||
|
inline Type getType() const { return m_type; }
|
||||||
|
|
||||||
// Test operators
|
// Test operators
|
||||||
inline bool isNull() const { return m_type == Type::Null; }
|
inline bool isNull() const { return m_type == Type::Null; }
|
||||||
inline bool isBool() const { return m_type == Type::Bool; }
|
inline bool isBool() const { return m_type == Type::Bool; }
|
||||||
|
@ -260,6 +262,12 @@ public:
|
||||||
/// \param value Value
|
/// \param value Value
|
||||||
void addEntry(QByteArray&& key, PDFObject&& value) { m_dictionary.emplace_back(std::move(key), std::move(value)); }
|
void addEntry(QByteArray&& key, PDFObject&& value) { m_dictionary.emplace_back(std::move(key), std::move(value)); }
|
||||||
|
|
||||||
|
/// Sets entry value. If entry with given key doesn't exist,
|
||||||
|
/// then it is created.
|
||||||
|
/// \param key Key
|
||||||
|
/// \param value Value
|
||||||
|
void setEntry(const QByteArray& key, PDFObject&& value);
|
||||||
|
|
||||||
/// Returns count of items in the dictionary
|
/// Returns count of items in the dictionary
|
||||||
size_t getCount() const { return m_dictionary.size(); }
|
size_t getCount() const { return m_dictionary.size(); }
|
||||||
|
|
||||||
|
@ -274,6 +282,9 @@ public:
|
||||||
/// \param index Zero-based index of value in the dictionary
|
/// \param index Zero-based index of value in the dictionary
|
||||||
const PDFObject& getValue(size_t index) const { return m_dictionary[index].second; }
|
const PDFObject& getValue(size_t index) const { return m_dictionary[index].second; }
|
||||||
|
|
||||||
|
/// Removes null objects from dictionary
|
||||||
|
void removeNullObjects();
|
||||||
|
|
||||||
/// Optimizes the dictionary for memory consumption
|
/// Optimizes the dictionary for memory consumption
|
||||||
virtual void optimize() override;
|
virtual void optimize() override;
|
||||||
|
|
||||||
|
@ -283,6 +294,11 @@ private:
|
||||||
/// \param key Key to be found
|
/// \param key Key to be found
|
||||||
std::vector<DictionaryEntry>::const_iterator find(const QByteArray& key) const;
|
std::vector<DictionaryEntry>::const_iterator find(const QByteArray& key) const;
|
||||||
|
|
||||||
|
/// Finds an item in the dictionary array, if the item is not in the dictionary,
|
||||||
|
/// then end iterator is returned.
|
||||||
|
/// \param key Key to be found
|
||||||
|
std::vector<DictionaryEntry>::iterator find(const QByteArray& key);
|
||||||
|
|
||||||
/// Finds an item in the dictionary array, if the item is not in the dictionary,
|
/// Finds an item in the dictionary array, if the item is not in the dictionary,
|
||||||
/// then end iterator is returned.
|
/// then end iterator is returned.
|
||||||
/// \param key Key to be found
|
/// \param key Key to be found
|
||||||
|
@ -322,6 +338,34 @@ private:
|
||||||
QByteArray m_content;
|
QByteArray m_content;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PDFObjectManipulator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFObjectManipulator() = delete;
|
||||||
|
|
||||||
|
enum MergeFlag
|
||||||
|
{
|
||||||
|
RemoveNullObjects = 0x0001, ///< Remove null object from dictionaries
|
||||||
|
ConcatenateArrays = 0x0002, ///< Concatenate arrays instead of replace
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(MergeFlags, MergeFlag)
|
||||||
|
|
||||||
|
/// Merges two objects. If object type is different, then object from right is used.
|
||||||
|
/// If both objects are dictionaries, then their content is merged, object \p right
|
||||||
|
/// has precedence over object \p left. If both objects are arrays, and concatenating
|
||||||
|
/// flag is turned on, then they are concatenated instead of replacing left array
|
||||||
|
/// by right array. If remove null objects flag is turend on, then null objects
|
||||||
|
/// are removed from dictionaries.
|
||||||
|
/// \param left Left, 'slave' object
|
||||||
|
/// \param right Right 'master' object, has priority over left
|
||||||
|
/// \param flags Merge flags
|
||||||
|
static PDFObject merge(PDFObject left, PDFObject right, MergeFlags flags);
|
||||||
|
|
||||||
|
/// Remove null objects from all dictionaries
|
||||||
|
/// \param object Object
|
||||||
|
static PDFObject removeNullObjects(PDFObject object);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
#endif // PDFOBJECT_H
|
#endif // PDFOBJECT_H
|
||||||
|
|
|
@ -68,7 +68,6 @@ private:
|
||||||
PDFObjectReference m_reference;
|
PDFObjectReference m_reference;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void PDFDecryptObjectVisitor::visitNull()
|
void PDFDecryptObjectVisitor::visitNull()
|
||||||
{
|
{
|
||||||
m_objectStack.push_back(PDFObject::createNull());
|
m_objectStack.push_back(PDFObject::createNull());
|
||||||
|
|
|
@ -48,21 +48,21 @@
|
||||||
<property name="items"/>
|
<property name="items"/>
|
||||||
<property name="parameterName">title</property>
|
<property name="parameterName">title</property>
|
||||||
<property name="parameterType">_QString</property>
|
<property name="parameterType">_QString</property>
|
||||||
<property name="parameterDescription">Title of the annotation</property>
|
<property name="parameterDescription">Title (it is displayed as title of popup window)</property>
|
||||||
</QObject>
|
</QObject>
|
||||||
<QObject class="codegen::GeneratedParameter">
|
<QObject class="codegen::GeneratedParameter">
|
||||||
<property name="objectName"></property>
|
<property name="objectName"></property>
|
||||||
<property name="items"/>
|
<property name="items"/>
|
||||||
<property name="parameterName">subject</property>
|
<property name="parameterName">subject</property>
|
||||||
<property name="parameterType">_QString</property>
|
<property name="parameterType">_QString</property>
|
||||||
<property name="parameterDescription">Subject of the annotation (short description of the subject being adressed by the annotation)</property>
|
<property name="parameterDescription">Subject (short description of the subject being adressed by the annotation)</property>
|
||||||
</QObject>
|
</QObject>
|
||||||
<QObject class="codegen::GeneratedParameter">
|
<QObject class="codegen::GeneratedParameter">
|
||||||
<property name="objectName"></property>
|
<property name="objectName"></property>
|
||||||
<property name="items"/>
|
<property name="items"/>
|
||||||
<property name="parameterName">contents</property>
|
<property name="parameterName">contents</property>
|
||||||
<property name="parameterType">_QString</property>
|
<property name="parameterType">_QString</property>
|
||||||
<property name="parameterDescription">Contents of the annotation (text displayed, for example, in the marked annotation dialog)</property>
|
<property name="parameterDescription">Contents (text displayed, for example, in the marked annotation dialog)</property>
|
||||||
</QObject>
|
</QObject>
|
||||||
</property>
|
</property>
|
||||||
<property name="actionType">Parameters</property>
|
<property name="actionType">Parameters</property>
|
||||||
|
@ -123,7 +123,7 @@
|
||||||
<property name="items"/>
|
<property name="items"/>
|
||||||
<property name="dictionaryItemName">Border</property>
|
<property name="dictionaryItemName">Border</property>
|
||||||
<property name="objectType">DictionaryItemSimple</property>
|
<property name="objectType">DictionaryItemSimple</property>
|
||||||
<property name="value">{ 0.0, 0.0, borderWidth }</property>
|
<property name="value">std::initializer_list<PDFReal>{ 0.0, 0.0, borderWidth }</property>
|
||||||
</QObject>
|
</QObject>
|
||||||
<QObject class="codegen::GeneratedPDFObject">
|
<QObject class="codegen::GeneratedPDFObject">
|
||||||
<property name="objectName"></property>
|
<property name="objectName"></property>
|
||||||
|
@ -151,7 +151,7 @@
|
||||||
<property name="items"/>
|
<property name="items"/>
|
||||||
<property name="dictionaryItemName">Contents</property>
|
<property name="dictionaryItemName">Contents</property>
|
||||||
<property name="objectType">DictionaryItemSimple</property>
|
<property name="objectType">DictionaryItemSimple</property>
|
||||||
<property name="value">comment</property>
|
<property name="value">contents</property>
|
||||||
</QObject>
|
</QObject>
|
||||||
<QObject class="codegen::GeneratedPDFObject">
|
<QObject class="codegen::GeneratedPDFObject">
|
||||||
<property name="objectName"></property>
|
<property name="objectName"></property>
|
||||||
|
@ -201,7 +201,7 @@
|
||||||
<property name="actionType">Code</property>
|
<property name="actionType">Code</property>
|
||||||
<property name="variableName"></property>
|
<property name="variableName"></property>
|
||||||
<property name="variableType">_void</property>
|
<property name="variableType">_void</property>
|
||||||
<property name="code">mergeTo(annotationObject, popupAnnotation);
|
<property name="code">mergeTo(annotationObject, updateAnnotationPopup);
|
||||||
return annotationObject;</property>
|
return annotationObject;</property>
|
||||||
</QObject>
|
</QObject>
|
||||||
</property>
|
</property>
|
||||||
|
|
Loading…
Reference in New Issue