mirror of
				https://github.com/JakubMelka/PDF4QT.git
				synced 2025-06-05 21:59:17 +02:00 
			
		
		
		
	Output formatter
This commit is contained in:
		| @@ -42,6 +42,7 @@ LIBS += -lPDFForQtLib | |||||||
|  |  | ||||||
| SOURCES += \ | SOURCES += \ | ||||||
|         main.cpp \ |         main.cpp \ | ||||||
|  |         pdfoutputformatter.cpp \ | ||||||
|         pdftoolabstractapplication.cpp |         pdftoolabstractapplication.cpp | ||||||
|  |  | ||||||
| # Default rules for deployment. | # Default rules for deployment. | ||||||
| @@ -54,4 +55,5 @@ application.path = $$DESTDIR/install | |||||||
| INSTALLS += application | INSTALLS += application | ||||||
|  |  | ||||||
| HEADERS += \ | HEADERS += \ | ||||||
|  |     pdfoutputformatter.h \ | ||||||
|     pdftoolabstractapplication.h |     pdftoolabstractapplication.h | ||||||
|   | |||||||
							
								
								
									
										571
									
								
								PdfTool/pdfoutputformatter.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										571
									
								
								PdfTool/pdfoutputformatter.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,571 @@ | |||||||
|  | //    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 <https://www.gnu.org/licenses/>. | ||||||
|  |  | ||||||
|  | #include "pdfoutputformatter.h" | ||||||
|  |  | ||||||
|  | #include <QTextStream> | ||||||
|  | #include <QXmlStreamWriter> | ||||||
|  | #include <QCoreApplication> | ||||||
|  |  | ||||||
|  | #include <stack> | ||||||
|  |  | ||||||
|  | namespace pdftool | ||||||
|  | { | ||||||
|  |  | ||||||
|  | class PDFOutputFormatterImpl | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     explicit PDFOutputFormatterImpl() = default; | ||||||
|  |     virtual ~PDFOutputFormatterImpl() = default; | ||||||
|  |  | ||||||
|  |     /// Starts a new element in structure tree. Each call of this function must be | ||||||
|  |     /// accompanied with matching call to \p endElement function. Element can have | ||||||
|  |     /// internal name (in xml file), text description for user (as string), and reference | ||||||
|  |     /// number. Also alignment can also be specified. Element type and name must | ||||||
|  |     /// always be specified. | ||||||
|  |     /// \param type Element type | ||||||
|  |     /// \param name Internal element name (for example, xml tag if style is XML) | ||||||
|  |     /// \param description Text description for user | ||||||
|  |     /// \param alignment Cell alignment in table | ||||||
|  |     /// \param reference Reference number | ||||||
|  |     virtual void beginElement(PDFOutputFormatter::Element type, QString name, QString description = QString(), Qt::Alignment alignment = Qt::AlignLeft, int reference = 0) = 0; | ||||||
|  |  | ||||||
|  |     /// Ends current element. Must match with a call of \p beginElement | ||||||
|  |     virtual void endElement() = 0; | ||||||
|  |  | ||||||
|  |     /// Get result string in unicode. | ||||||
|  |     virtual QString getString() const = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class PDFTextOutputFormatterImpl : public PDFOutputFormatterImpl | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     PDFTextOutputFormatterImpl(); | ||||||
|  |  | ||||||
|  |     virtual void beginElement(PDFOutputFormatter::Element type, QString name, QString description, Qt::Alignment alignment, int reference) override; | ||||||
|  |     virtual void endElement() override; | ||||||
|  |     virtual QString getString() const override; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     static constexpr const int INDENT_STEP = 2; | ||||||
|  |  | ||||||
|  |     void writeIndent(); | ||||||
|  |  | ||||||
|  |     struct TableCell | ||||||
|  |     { | ||||||
|  |         QString text; | ||||||
|  |         Qt::Alignment alignment; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     const TableCell& getTableCell(size_t row, size_t column) const; | ||||||
|  |  | ||||||
|  |     QString m_string; | ||||||
|  |     QTextStream m_streamWriter; | ||||||
|  |     int m_depth; | ||||||
|  |     int m_indent; | ||||||
|  |     std::stack<PDFOutputFormatter::Element> m_elementStack; | ||||||
|  |     std::vector<std::vector<TableCell>> m_table; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class PDFXmlOutputFormatterImpl : public PDFOutputFormatterImpl | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     PDFXmlOutputFormatterImpl(); | ||||||
|  |  | ||||||
|  |     virtual void beginElement(PDFOutputFormatter::Element type, QString name, QString description, Qt::Alignment alignment, int reference) override; | ||||||
|  |     virtual void endElement() override; | ||||||
|  |     virtual QString getString() const override; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     QString m_string; | ||||||
|  |     QString m_namespace; | ||||||
|  |     QString m_prefix; | ||||||
|  |     QXmlStreamWriter m_streamWriter; | ||||||
|  |     int m_depth; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class PDFHtmlOutputFormatterImpl : public PDFOutputFormatterImpl | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     PDFHtmlOutputFormatterImpl(); | ||||||
|  |  | ||||||
|  |     virtual void beginElement(PDFOutputFormatter::Element type, QString name, QString description, Qt::Alignment alignment, int reference) override; | ||||||
|  |     virtual void endElement() override; | ||||||
|  |     virtual QString getString() const override; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     QString m_string; | ||||||
|  |     QXmlStreamWriter m_streamWriter; | ||||||
|  |     int m_depth; | ||||||
|  |     int m_headerDepth; | ||||||
|  |     std::stack<PDFOutputFormatter::Element> m_elementStack; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | PDFTextOutputFormatterImpl::PDFTextOutputFormatterImpl() : | ||||||
|  |     m_string(), | ||||||
|  |     m_streamWriter(&m_string, QIODevice::WriteOnly), | ||||||
|  |     m_depth(0), | ||||||
|  |     m_elementStack() | ||||||
|  | { | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void PDFTextOutputFormatterImpl::beginElement(PDFOutputFormatter::Element type, QString name, QString description, Qt::Alignment alignment, int reference) | ||||||
|  | { | ||||||
|  |     Q_UNUSED(reference); | ||||||
|  |     m_elementStack.push(type); | ||||||
|  |  | ||||||
|  |     switch (type) | ||||||
|  |     { | ||||||
|  |         case PDFOutputFormatter::Element::Root: | ||||||
|  |         { | ||||||
|  |             m_streamWriter << description << Qt::endl; | ||||||
|  |             m_indent += INDENT_STEP; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::Table: | ||||||
|  |         case PDFOutputFormatter::Element::Header: | ||||||
|  |         { | ||||||
|  |             writeIndent(); | ||||||
|  |             m_streamWriter << description << Qt::endl; | ||||||
|  |             m_indent += INDENT_STEP; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::TableRow: | ||||||
|  |         case PDFOutputFormatter::Element::TableHeaderRow: | ||||||
|  |         { | ||||||
|  |             m_table.emplace_back(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::TableHeaderColumn: | ||||||
|  |         case PDFOutputFormatter::Element::TableColumn: | ||||||
|  |         { | ||||||
|  |             TableCell cell; | ||||||
|  |             cell.text = QString(" %1 ").arg(description); | ||||||
|  |             cell.alignment = alignment; | ||||||
|  |  | ||||||
|  |             Q_ASSERT(!m_table.empty()); | ||||||
|  |             m_table.back().emplace_back(qMove(cell)); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: | ||||||
|  |         { | ||||||
|  |             Q_ASSERT(false); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Increment depth by one | ||||||
|  |     ++m_depth; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void PDFTextOutputFormatterImpl::endElement() | ||||||
|  | { | ||||||
|  |     PDFOutputFormatter::Element type = m_elementStack.top(); | ||||||
|  |     m_elementStack.pop(); | ||||||
|  |     --m_depth; | ||||||
|  |  | ||||||
|  |     switch (type) | ||||||
|  |     { | ||||||
|  |         case PDFOutputFormatter::Element::Root: | ||||||
|  |         { | ||||||
|  |             m_indent -= INDENT_STEP; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::Table: | ||||||
|  |         { | ||||||
|  |             // Print the table | ||||||
|  |             const size_t rows = m_table.size(); | ||||||
|  |             const size_t columns = (*std::max_element(m_table.cbegin(), m_table.cend(), [](const auto& l, const auto& r) { return l.size() < r.size(); })).size(); | ||||||
|  |  | ||||||
|  |             // Detect maximal column size | ||||||
|  |             std::vector<int> columnSize(columns, 0); | ||||||
|  |             for (size_t row = 0; row < rows; ++row) | ||||||
|  |             { | ||||||
|  |                 for (size_t column = 0; column < columns; ++column) | ||||||
|  |                 { | ||||||
|  |                     const TableCell& tableCell = getTableCell(row, column); | ||||||
|  |                     columnSize[column] = qMax(columnSize[column], tableCell.text.size()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Print cells | ||||||
|  |             m_streamWriter.setPadChar(QChar(QChar::Space)); | ||||||
|  |             for (size_t row = 0; row < rows; ++row) | ||||||
|  |             { | ||||||
|  |                 for (size_t column = 0; column < columns; ++column) | ||||||
|  |                 { | ||||||
|  |                     const TableCell& tableCell = getTableCell(row, column); | ||||||
|  |                     m_streamWriter.setFieldWidth(columnSize[column]); | ||||||
|  |  | ||||||
|  |                     if (tableCell.alignment.testFlag(Qt::AlignLeft)) | ||||||
|  |                     { | ||||||
|  |                         m_streamWriter.setFieldAlignment(QTextStream::AlignLeft); | ||||||
|  |                     } | ||||||
|  |                     else if (tableCell.alignment.testFlag(Qt::AlignCenter)) | ||||||
|  |                     { | ||||||
|  |                         m_streamWriter.setFieldAlignment(QTextStream::AlignCenter); | ||||||
|  |                     } | ||||||
|  |                     else if (tableCell.alignment.testFlag(Qt::AlignRight)) | ||||||
|  |                     { | ||||||
|  |                         m_streamWriter.setFieldAlignment(QTextStream::AlignRight); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     m_streamWriter << tableCell.text; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 m_streamWriter.setFieldWidth(0); | ||||||
|  |                 m_streamWriter << Qt::endl; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             m_indent -= INDENT_STEP; | ||||||
|  |             m_table.clear(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::Header: | ||||||
|  |         { | ||||||
|  |             m_indent -= INDENT_STEP; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::TableRow: | ||||||
|  |         case PDFOutputFormatter::Element::TableHeaderRow: | ||||||
|  |         case PDFOutputFormatter::Element::TableHeaderColumn: | ||||||
|  |         case PDFOutputFormatter::Element::TableColumn: | ||||||
|  |         { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: | ||||||
|  |         { | ||||||
|  |             Q_ASSERT(false); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString PDFTextOutputFormatterImpl::getString() const | ||||||
|  | { | ||||||
|  |     return m_string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void PDFTextOutputFormatterImpl::writeIndent() | ||||||
|  | { | ||||||
|  |     QString str(m_indent, QChar(QChar::Space)); | ||||||
|  |     m_streamWriter << str; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const PDFTextOutputFormatterImpl::TableCell& PDFTextOutputFormatterImpl::getTableCell(size_t row, size_t column) const | ||||||
|  | { | ||||||
|  |     if (row < m_table.size()) | ||||||
|  |     { | ||||||
|  |         const auto& columns = m_table[row]; | ||||||
|  |         if (column < columns.size()) | ||||||
|  |         { | ||||||
|  |             return columns[column]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static const TableCell dummy; | ||||||
|  |     return dummy; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | PDFHtmlOutputFormatterImpl::PDFHtmlOutputFormatterImpl() : | ||||||
|  |     m_string(), | ||||||
|  |     m_streamWriter(&m_string), | ||||||
|  |     m_depth(0), | ||||||
|  |     m_headerDepth(1), | ||||||
|  |     m_elementStack() | ||||||
|  | { | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void PDFHtmlOutputFormatterImpl::beginElement(PDFOutputFormatter::Element type, QString name, QString description, Qt::Alignment alignment, int reference) | ||||||
|  | { | ||||||
|  |     Q_UNUSED(reference); | ||||||
|  |     m_elementStack.push(type); | ||||||
|  |  | ||||||
|  |     auto writeTableCellAlignment = [this, alignment]() | ||||||
|  |     { | ||||||
|  |         if (alignment.testFlag(Qt::AlignLeft)) | ||||||
|  |         { | ||||||
|  |             m_streamWriter.writeAttribute("align", "left"); | ||||||
|  |         } | ||||||
|  |         if (alignment.testFlag(Qt::AlignCenter)) | ||||||
|  |         { | ||||||
|  |             m_streamWriter.writeAttribute("align", "center"); | ||||||
|  |         } | ||||||
|  |         if (alignment.testFlag(Qt::AlignRight)) | ||||||
|  |         { | ||||||
|  |             m_streamWriter.writeAttribute("align", "right"); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     switch (type) | ||||||
|  |     { | ||||||
|  |         case PDFOutputFormatter::Element::Root: | ||||||
|  |         { | ||||||
|  |             m_streamWriter.writeStartDocument(); | ||||||
|  |  | ||||||
|  |             QString title = QString("%1 - Processed by %2 %3").arg(description, QCoreApplication::applicationName(), QCoreApplication::applicationVersion()); | ||||||
|  |             m_streamWriter.writeStartElement("html"); | ||||||
|  |             m_streamWriter.writeStartElement("head"); | ||||||
|  |             m_streamWriter.writeTextElement("title", title); | ||||||
|  |             m_streamWriter.writeEndElement(); | ||||||
|  |             m_streamWriter.writeStartElement("body"); | ||||||
|  |             m_streamWriter.writeStartElement("p"); | ||||||
|  |             m_streamWriter.writeTextElement("h1", title); | ||||||
|  |             m_streamWriter.writeEndElement(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::Header: | ||||||
|  |         { | ||||||
|  |             // Just print single paragraph with header | ||||||
|  |             ++m_headerDepth; | ||||||
|  |             int headerTagDepth = qBound(1, m_headerDepth, 6); | ||||||
|  |             QString headerTag = QString("h%1").arg(headerTagDepth); | ||||||
|  |             m_streamWriter.writeStartElement("p"); | ||||||
|  |             m_streamWriter.writeTextElement(headerTag, description); | ||||||
|  |             m_streamWriter.writeEndElement(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::Table: | ||||||
|  |         { | ||||||
|  |             m_streamWriter.writeStartElement("table"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::TableHeaderRow: | ||||||
|  |         { | ||||||
|  |             m_streamWriter.writeStartElement("tr"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::TableHeaderColumn: | ||||||
|  |         { | ||||||
|  |             m_streamWriter.writeStartElement("th"); | ||||||
|  |             writeTableCellAlignment(); | ||||||
|  |             m_streamWriter.writeCharacters(description); | ||||||
|  |             m_streamWriter.writeEndElement(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::TableRow: | ||||||
|  |         { | ||||||
|  |             m_streamWriter.writeStartElement("tr"); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::TableColumn: | ||||||
|  |         { | ||||||
|  |             m_streamWriter.writeStartElement("td"); | ||||||
|  |             writeTableCellAlignment(); | ||||||
|  |             m_streamWriter.writeCharacters(description); | ||||||
|  |             m_streamWriter.writeEndElement(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: | ||||||
|  |         { | ||||||
|  |             Q_ASSERT(false); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Increment depth by one | ||||||
|  |     ++m_depth; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void PDFHtmlOutputFormatterImpl::endElement() | ||||||
|  | { | ||||||
|  |     PDFOutputFormatter::Element type = m_elementStack.top(); | ||||||
|  |     m_elementStack.pop(); | ||||||
|  |     --m_depth; | ||||||
|  |  | ||||||
|  |     switch (type) | ||||||
|  |     { | ||||||
|  |         case PDFOutputFormatter::Element::Root: | ||||||
|  |         { | ||||||
|  |             Q_ASSERT(m_depth == 0); | ||||||
|  |             m_streamWriter.writeEndElement(); | ||||||
|  |             m_streamWriter.writeEndElement(); | ||||||
|  |             m_streamWriter.writeEndDocument(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::Header: | ||||||
|  |         { | ||||||
|  |             // Just decrement header depth | ||||||
|  |             --m_headerDepth; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         case PDFOutputFormatter::Element::Table: | ||||||
|  |         case PDFOutputFormatter::Element::TableHeaderRow: | ||||||
|  |         case PDFOutputFormatter::Element::TableRow: | ||||||
|  |         { | ||||||
|  |             m_streamWriter.writeEndElement(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::TableHeaderColumn: | ||||||
|  |         case PDFOutputFormatter::Element::TableColumn: | ||||||
|  |         { | ||||||
|  |             // Do nothing... | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: | ||||||
|  |         { | ||||||
|  |             Q_ASSERT(false); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString PDFHtmlOutputFormatterImpl::getString() const | ||||||
|  | { | ||||||
|  |     QString html = m_string; | ||||||
|  |     html.remove(0, html.indexOf("?>") + 2); | ||||||
|  |     html.prepend("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">"); | ||||||
|  |     return html; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | PDFXmlOutputFormatterImpl::PDFXmlOutputFormatterImpl() : | ||||||
|  |     m_string(), | ||||||
|  |     m_streamWriter(&m_string), | ||||||
|  |     m_depth(0) | ||||||
|  | { | ||||||
|  |     m_streamWriter.setAutoFormatting(true); | ||||||
|  |     m_streamWriter.setAutoFormattingIndent(2); | ||||||
|  |  | ||||||
|  |     m_namespace = "https://github.com/JakubMelka/PdfForQt"; | ||||||
|  |     m_prefix = "pdftool"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void PDFXmlOutputFormatterImpl::beginElement(PDFOutputFormatter::Element type, QString name, QString description, Qt::Alignment alignment, int reference) | ||||||
|  | { | ||||||
|  |     Q_UNUSED(alignment); | ||||||
|  |  | ||||||
|  |     switch (type) | ||||||
|  |     { | ||||||
|  |         case PDFOutputFormatter::Element::Root: | ||||||
|  |         { | ||||||
|  |             m_streamWriter.writeStartDocument(); | ||||||
|  |  | ||||||
|  |             QString comment = QString("Processed by %1 %2").arg(QCoreApplication::applicationName(), QCoreApplication::applicationVersion()); | ||||||
|  |  | ||||||
|  |             m_streamWriter.writeComment(comment); | ||||||
|  |             m_streamWriter.writeNamespace(m_namespace, m_prefix); | ||||||
|  |  | ||||||
|  |             m_streamWriter.writeStartElement(m_namespace, name); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         case PDFOutputFormatter::Element::TableColumn: | ||||||
|  |         case PDFOutputFormatter::Element::TableHeaderColumn: | ||||||
|  |         { | ||||||
|  |             m_streamWriter.writeTextElement(m_namespace, name, description); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         default: | ||||||
|  |         { | ||||||
|  |             m_streamWriter.writeStartElement(m_namespace, name); | ||||||
|  |  | ||||||
|  |             if (!description.isEmpty()) | ||||||
|  |             { | ||||||
|  |                 m_streamWriter.writeAttribute(m_namespace, "description", description); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (reference > 0) | ||||||
|  |             { | ||||||
|  |                 m_streamWriter.writeAttribute(m_namespace, "ref", QString::number(reference)); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Increment depth by one | ||||||
|  |     ++m_depth; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void PDFXmlOutputFormatterImpl::endElement() | ||||||
|  | { | ||||||
|  |     m_streamWriter.writeEndElement(); | ||||||
|  |  | ||||||
|  |     // Do we finish the document? If yes, then tell stream writer to end the document | ||||||
|  |     if (--m_depth == 0) | ||||||
|  |     { | ||||||
|  |         m_streamWriter.writeEndDocument(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString PDFXmlOutputFormatterImpl::getString() const | ||||||
|  | { | ||||||
|  |     return m_string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | PDFOutputFormatter::PDFOutputFormatter(Style style) : | ||||||
|  |     m_impl(nullptr) | ||||||
|  | { | ||||||
|  |     switch (style) | ||||||
|  |     { | ||||||
|  |         case Style::Text: | ||||||
|  |             m_impl = new PDFTextOutputFormatterImpl(); | ||||||
|  |             break; | ||||||
|  |  | ||||||
|  |         case Style::Xml: | ||||||
|  |             m_impl = new PDFXmlOutputFormatterImpl(); | ||||||
|  |             break; | ||||||
|  |  | ||||||
|  |         case Style::Html: | ||||||
|  |             m_impl = new PDFHtmlOutputFormatterImpl(); | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Q_ASSERT(m_impl); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | PDFOutputFormatter::~PDFOutputFormatter() | ||||||
|  | { | ||||||
|  |     delete m_impl; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void PDFOutputFormatter::beginElement(PDFOutputFormatter::Element type, QString name, QString description, Qt::Alignment alignment, int reference) | ||||||
|  | { | ||||||
|  |     m_impl->beginElement(type, name, description, alignment, reference); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void PDFOutputFormatter::endElement() | ||||||
|  | { | ||||||
|  |     m_impl->endElement(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString PDFOutputFormatter::getString() const | ||||||
|  | { | ||||||
|  |     return m_impl->getString(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }   // pdftool | ||||||
							
								
								
									
										78
									
								
								PdfTool/pdfoutputformatter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								PdfTool/pdfoutputformatter.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | |||||||
|  | //    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 <https://www.gnu.org/licenses/>. | ||||||
|  |  | ||||||
|  | #ifndef PDFOUTPUTFORMATTER_H | ||||||
|  | #define PDFOUTPUTFORMATTER_H | ||||||
|  |  | ||||||
|  | #include <QString> | ||||||
|  |  | ||||||
|  | namespace pdftool | ||||||
|  | { | ||||||
|  | class PDFOutputFormatterImpl; | ||||||
|  |  | ||||||
|  | /// Output formatter for text output in various format (text, xml, html...) | ||||||
|  | /// to the output console. Text output is in form of a structure tree, | ||||||
|  | /// for example, xml format. | ||||||
|  | class PDFOutputFormatter | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     enum class Style | ||||||
|  |     { | ||||||
|  |         Text, | ||||||
|  |         Xml, | ||||||
|  |         Html | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     explicit PDFOutputFormatter(Style style); | ||||||
|  |     ~PDFOutputFormatter(); | ||||||
|  |  | ||||||
|  |     enum class Element | ||||||
|  |     { | ||||||
|  |         Root,               ///< Root element, this must be used only once at start/end of writing | ||||||
|  |         Header,             ///< Header | ||||||
|  |         Table,              ///< Table of rows/columns (2D grid) | ||||||
|  |         TableHeaderRow,     ///< Table header row (consists of columns) | ||||||
|  |         TableHeaderColumn,  ///< Table header column | ||||||
|  |         TableRow,           ///< Table row (consists of columns) | ||||||
|  |         TableColumn         ///< Table column | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /// Starts a new element in structure tree. Each call of this function must be | ||||||
|  |     /// accompanied with matching call to \p endElement function. Element can have | ||||||
|  |     /// internal name (in xml file), text description for user (as string), and reference | ||||||
|  |     /// number. Also alignment can also be specified. Element type and name must | ||||||
|  |     /// always be specified. | ||||||
|  |     /// \param type Element type | ||||||
|  |     /// \param name Internal element name (for example, xml tag if style is XML) | ||||||
|  |     /// \param description Text description for user | ||||||
|  |     /// \param alignment Cell alignment in table | ||||||
|  |     /// \param reference Reference number | ||||||
|  |     void beginElement(Element type, QString name, QString description = QString(), Qt::Alignment alignment = Qt::AlignLeft, int reference = 0); | ||||||
|  |  | ||||||
|  |     /// Ends current element. Must match with a call of \p beginElement | ||||||
|  |     void endElement(); | ||||||
|  |  | ||||||
|  |     /// Get result string in unicode. | ||||||
|  |     QString getString() const; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     PDFOutputFormatterImpl* m_impl; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }   // namespace pdftool | ||||||
|  |  | ||||||
|  | #endif // PDFOUTPUTFORMATTER_H | ||||||
		Reference in New Issue
	
	Block a user