diff --git a/Pdf4QtDocDiff/mainwindow.cpp b/Pdf4QtDocDiff/mainwindow.cpp index f17aa6b..8a42919 100644 --- a/Pdf4QtDocDiff/mainwindow.cpp +++ b/Pdf4QtDocDiff/mainwindow.cpp @@ -563,6 +563,31 @@ void MainWindow::performOperation(Operation operation) break; case Operation::SaveDifferencesToXML: + { + if (!m_filteredDiffResult.isSame()) + { + QString fileName = QFileDialog::getSaveFileName(this, tr("Select PDF document"), m_settings.directory, tr("XML file (*.xml)")); + if (!fileName.isEmpty()) + { + QFile file(fileName); + if (file.open(QFile::WriteOnly | QFile::Truncate)) + { + m_filteredDiffResult.saveToXML(&file); + file.close(); + } + else + { + QMessageBox::critical(this, tr("Error"), tr("File '%1' cannot be opened. %2").arg(fileName, file.errorString())); + } + } + } + else + { + QMessageBox::information(this, tr("Save results to XML"), tr("Displayed results are empty. Cannot save empty results.")); + } + + break; + } case Operation::CreateCompareReport: Q_ASSERT(false); break; diff --git a/Pdf4QtLib/sources/pdfdiff.cpp b/Pdf4QtLib/sources/pdfdiff.cpp index 29bfd86..5563803 100644 --- a/Pdf4QtLib/sources/pdfdiff.cpp +++ b/Pdf4QtLib/sources/pdfdiff.cpp @@ -1074,6 +1074,128 @@ void PDFDiffResult::addTextReplaced(PDFInteger pageIndex1, m_differences.emplace_back(std::move(difference)); } +void PDFDiffResult::saveToStream(QXmlStreamWriter* stream) const +{ + stream->setAutoFormatting(true); + stream->setAutoFormattingIndent(2); + stream->writeStartDocument(); + stream->writeNamespace("https://github.com/JakubMelka/PDF4QT", "pdf4qt"); + stream->writeStartElement("difference-report"); + + // Jakub Melka: write all differences + stream->writeStartElement("differences"); + for (const Difference& difference : m_differences) + { + stream->writeStartElement("difference"); + + QString type; + switch (difference.type) + { + case Type::PageMoved: + type = "page-moved"; + break; + + case Type::PageAdded: + type = "page-added"; + break; + + case Type::PageRemoved: + type = "page-removed"; + break; + + case Type::RemovedTextCharContent: + type = "removed-text-char"; + break; + + case Type::RemovedVectorGraphicContent: + type = "removed-vector-graphics"; + break; + + case Type::RemovedImageContent: + type = "removed-image"; + break; + + case Type::RemovedShadingContent: + type = "removed-shading"; + break; + + case Type::AddedTextCharContent: + type = "added-text-char"; + break; + + case Type::AddedVectorGraphicContent: + type = "added-vector-graphics"; + break; + + case Type::AddedImageContent: + type = "added-image"; + break; + + case Type::AddedShadingContent: + type = "added-shading"; + break; + + case Type::TextAdded: + type = "text-added"; + break; + + case Type::TextRemoved: + type = "text-removed"; + break; + + case Type::TextReplaced: + type = "text-replaced"; + break; + + default: + Q_ASSERT(false); + break; + } + stream->writeAttribute("type", type); + + if (difference.pageIndex1 != -1) + { + stream->writeAttribute("left", QString::number(difference.pageIndex1 + 1)); + } + + if (difference.pageIndex2 != -1) + { + stream->writeAttribute("right", QString::number(difference.pageIndex2 + 1)); + } + + if (difference.textAddedIndex != -1) + { + stream->writeTextElement("text-added", m_strings[difference.textAddedIndex]); + } + + if (difference.textRemovedIndex != -1) + { + stream->writeTextElement("text-removed", m_strings[difference.textRemovedIndex]); + } + + stream->writeEndElement(); + } + stream->writeEndElement(); + + stream->writeStartElement("page-sequence"); + for (const PageSequenceItem& item : m_pageSequence) + { + stream->writeStartElement("item"); + + QString left = item.leftPage != -1 ? QString::number(item.leftPage + 1) : QString("none"); + QString right = item.rightPage != -1 ? QString::number(item.rightPage + 1) : QString("none"); + + stream->writeAttribute("left", left); + stream->writeAttribute("right", right); + + stream->writeEndElement(); + } + stream->writeEndElement(); + + stream->writeEndElement(); + stream->writeEndDocument(); +} + void PDFDiffResult::finalize() { auto predicate = [](const Difference& l, const Difference& r) @@ -1345,6 +1467,24 @@ void PDFDiffResult::setPageSequence(PageSequence pageSequence) m_pageSequence = pageSequence; } +void PDFDiffResult::saveToXML(QIODevice* device) const +{ + QXmlStreamWriter stream(device); + saveToStream(&stream); +} + +void PDFDiffResult::saveToXML(QByteArray* byteArray) const +{ + QXmlStreamWriter stream(byteArray); + saveToStream(&stream); +} + +void PDFDiffResult::saveToXML(QString* string) const +{ + QXmlStreamWriter stream(string); + saveToStream(&stream); +} + PDFDiffHelper::Differences PDFDiffHelper::calculateDifferences(const GraphicPieceInfos& left, const GraphicPieceInfos& right, PDFReal epsilon) diff --git a/Pdf4QtLib/sources/pdfdiff.h b/Pdf4QtLib/sources/pdfdiff.h index 45ce13e..93ed911 100644 --- a/Pdf4QtLib/sources/pdfdiff.h +++ b/Pdf4QtLib/sources/pdfdiff.h @@ -30,6 +30,9 @@ #include +class QIODevice; +class QXmlStreamWriter; + namespace pdf { @@ -139,6 +142,19 @@ public: const PageSequence& getPageSequence() const; void setPageSequence(PageSequence pageSequence); + /// Saves all differences to a XML stream + /// represented by device + /// \param device Output device + void saveToXML(QIODevice* device) const; + + /// Saves all differences to a byte array + /// \param byteArray Output byte array + void saveToXML(QByteArray* byteArray) const; + + /// Saves all differences to a string + /// \param string Output string + void saveToXML(QString* string) const; + private: friend class PDFDiff; @@ -177,6 +193,8 @@ private: const RectInfos& rectInfos1, const RectInfos& rectInfos2); + void saveToStream(QXmlStreamWriter* stream) const; + void finalize(); uint32_t getTypeFlags(size_t index) const;