mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
DocDiff application: basic functionality, opening documents
This commit is contained in:
@@ -16,23 +16,34 @@
|
||||
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "pdfdiff.h"
|
||||
#include "pdfdocumenttextflow.h"
|
||||
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
PDFDiff::PDFDiff(QObject* parent) :
|
||||
BaseClass(parent),
|
||||
m_progress(nullptr),
|
||||
m_leftDocument(nullptr),
|
||||
m_rightDocument(nullptr)
|
||||
m_rightDocument(nullptr),
|
||||
m_options(Asynchronous),
|
||||
m_cancelled(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PDFDiff::~PDFDiff()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void PDFDiff::setLeftDocument(const PDFDocument* leftDocument)
|
||||
{
|
||||
if (m_leftDocument != leftDocument)
|
||||
{
|
||||
clear();
|
||||
stop();
|
||||
m_leftDocument = leftDocument;
|
||||
}
|
||||
}
|
||||
@@ -41,15 +52,147 @@ void PDFDiff::setRightDocument(const PDFDocument* rightDocument)
|
||||
{
|
||||
if (m_rightDocument != rightDocument)
|
||||
{
|
||||
clear();
|
||||
stop();
|
||||
m_rightDocument = rightDocument;
|
||||
}
|
||||
}
|
||||
|
||||
void PDFDiff::clear()
|
||||
void PDFDiff::setPagesForLeftDocument(PDFClosedIntervalSet pagesForLeftDocument)
|
||||
{
|
||||
stopEngine();
|
||||
stop();
|
||||
m_pagesForLeftDocument = std::move(pagesForLeftDocument);
|
||||
}
|
||||
|
||||
void PDFDiff::setPagesForRightDocument(PDFClosedIntervalSet pagesForRightDocument)
|
||||
{
|
||||
stop();
|
||||
m_pagesForRightDocument = std::move(pagesForRightDocument);
|
||||
}
|
||||
|
||||
void PDFDiff::start()
|
||||
{
|
||||
// Jakub Melka: First, we must ensure, that comparation
|
||||
// process is finished, otherwise we must wait for end.
|
||||
// Then, create a new future watcher.
|
||||
stop();
|
||||
|
||||
m_cancelled = false;
|
||||
|
||||
if (m_options.testFlag(Asynchronous))
|
||||
{
|
||||
m_futureWatcher = std::nullopt;
|
||||
m_futureWatcher.emplace();
|
||||
|
||||
m_future = QtConcurrent::run(std::bind(&PDFDiff::perform, this));
|
||||
connect(&*m_futureWatcher, &QFutureWatcher<PDFDiffResult>::finished, this, &PDFDiff::onComparationPerformed);
|
||||
m_futureWatcher->setFuture(m_future);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just do comparation immediately
|
||||
m_result = perform();
|
||||
emit comparationFinished();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFDiff::stop()
|
||||
{
|
||||
if (m_futureWatcher && !m_futureWatcher->isFinished())
|
||||
{
|
||||
// Do stop only if process doesn't finished already.
|
||||
// If we are finished, we do not want to set cancelled state.
|
||||
m_cancelled = true;
|
||||
m_futureWatcher->waitForFinished();
|
||||
}
|
||||
}
|
||||
|
||||
PDFDiffResult PDFDiff::perform()
|
||||
{
|
||||
PDFDiffResult result;
|
||||
|
||||
if (!m_leftDocument || !m_rightDocument)
|
||||
{
|
||||
result.setResult(tr("No document to be compared."));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (m_pagesForLeftDocument.isEmpty() || m_pagesForRightDocument.isEmpty())
|
||||
{
|
||||
result.setResult(tr("No page to be compared."));
|
||||
return result;
|
||||
}
|
||||
|
||||
auto leftPages = m_pagesForLeftDocument.unfold();
|
||||
auto rightPages = m_pagesForRightDocument.unfold();
|
||||
|
||||
const size_t leftDocumentPageCount = m_leftDocument->getCatalog()->getPageCount();
|
||||
const size_t rightDocumentPageCount = m_rightDocument->getCatalog()->getPageCount();
|
||||
|
||||
if (leftPages.front() < 0 ||
|
||||
leftPages.back() >= PDFInteger(leftDocumentPageCount) ||
|
||||
rightPages.front() < 0 ||
|
||||
rightPages.back() >= PDFInteger(rightDocumentPageCount))
|
||||
{
|
||||
result.setResult(tr("Invalid page range."));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (m_progress)
|
||||
{
|
||||
ProgressStartupInfo info;
|
||||
info.showDialog = false;
|
||||
info.text = tr("");
|
||||
m_progress->start(StepLast, std::move(info));
|
||||
}
|
||||
|
||||
// StepExtractContentLeftDocument
|
||||
stepProgress();
|
||||
|
||||
// StepExtractContentRightDocument
|
||||
stepProgress();
|
||||
|
||||
// StepExtractTextLeftDocument
|
||||
pdf::PDFDocumentTextFlowFactory factoryLeftDocumentTextFlow;
|
||||
factoryLeftDocumentTextFlow.setCalculateBoundingBoxes(true);
|
||||
PDFDocumentTextFlow leftTextFlow = factoryLeftDocumentTextFlow.create(m_leftDocument, leftPages, PDFDocumentTextFlowFactory::Algorithm::Auto);
|
||||
stepProgress();
|
||||
|
||||
// StepExtractTextRightDocument
|
||||
pdf::PDFDocumentTextFlowFactory factoryRightDocumentTextFlow;
|
||||
factoryRightDocumentTextFlow.setCalculateBoundingBoxes(true);
|
||||
PDFDocumentTextFlow rightTextFlow = factoryRightDocumentTextFlow.create(m_rightDocument, rightPages, PDFDocumentTextFlowFactory::Algorithm::Auto);
|
||||
stepProgress();
|
||||
|
||||
// StepCompare
|
||||
stepProgress();
|
||||
|
||||
if (m_progress)
|
||||
{
|
||||
m_progress->finish();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PDFDiff::stepProgress()
|
||||
{
|
||||
if (m_progress)
|
||||
{
|
||||
m_progress->step();
|
||||
}
|
||||
}
|
||||
|
||||
void PDFDiff::onComparationPerformed()
|
||||
{
|
||||
m_cancelled = false;
|
||||
m_result = m_future.result();
|
||||
emit comparationFinished();
|
||||
}
|
||||
|
||||
PDFDiffResult::PDFDiffResult() :
|
||||
m_result(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
@@ -19,14 +19,32 @@
|
||||
#define PDFDIFF_H
|
||||
|
||||
#include "pdfdocument.h"
|
||||
#include "pdfprogress.h"
|
||||
#include "pdfutils.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
class PDFDiffResult
|
||||
{
|
||||
public:
|
||||
explicit PDFDiffResult();
|
||||
|
||||
void setResult(PDFOperationResult result) { m_result = std::move(result); }
|
||||
const PDFOperationResult& getResult() const { return m_result; }
|
||||
|
||||
private:
|
||||
PDFOperationResult m_result;
|
||||
};
|
||||
|
||||
/// Diff engine for comparing two pdf documents.
|
||||
class PDFDiff : public QObject
|
||||
class PDF4QTLIBSHARED_EXPORT PDFDiff : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -35,19 +53,84 @@ private:
|
||||
|
||||
public:
|
||||
explicit PDFDiff(QObject* parent);
|
||||
virtual ~PDFDiff() override;
|
||||
|
||||
enum Option
|
||||
{
|
||||
None = 0x0000,
|
||||
Asynchronous = 0x0001, ///< Compare document asynchronously
|
||||
};
|
||||
Q_DECLARE_FLAGS(Options, Option)
|
||||
|
||||
/// Source document (left)
|
||||
/// \param leftDocument Document
|
||||
void setLeftDocument(const PDFDocument* leftDocument);
|
||||
|
||||
/// Source document (right)(
|
||||
/// \param rightDocument Document
|
||||
void setRightDocument(const PDFDocument* rightDocument);
|
||||
|
||||
/// Clears data (but not source document pointers,
|
||||
/// for them, use setters), also stops comparing engine.
|
||||
void clear();
|
||||
/// Source pages to be compared (left document)
|
||||
/// \param pagesForLeftDocument Page indices
|
||||
void setPagesForLeftDocument(PDFClosedIntervalSet pagesForLeftDocument);
|
||||
|
||||
/// Source pages to be compared (right document)
|
||||
/// \param pagesForRightDocument Page indices
|
||||
void setPagesForRightDocument(PDFClosedIntervalSet pagesForRightDocument);
|
||||
|
||||
/// Sets progress object
|
||||
/// \param progress Progress object
|
||||
void setProgress(PDFProgress* progress) { m_progress = progress; }
|
||||
|
||||
/// Enables or disables comparator engine option
|
||||
/// \param option Option
|
||||
/// \param enable Enable or disable option?
|
||||
void setOption(Option option, bool enable) { m_options.setFlag(option, enable); }
|
||||
|
||||
/// Starts comparator engine. If asynchronous engine option
|
||||
/// is enabled, then separate thread is started, in which two
|
||||
/// document is compared, and then signal \p comparationFinished,
|
||||
/// otherwise this function is blocking until comparation process
|
||||
/// is finished.
|
||||
void start();
|
||||
|
||||
/// Stops comparator engine. Result data are cleared.
|
||||
void stop();
|
||||
|
||||
/// Returns result of a comparation process
|
||||
const PDFDiffResult& getResult() const { return m_result; }
|
||||
|
||||
signals:
|
||||
void comparationFinished();
|
||||
|
||||
private:
|
||||
void stopEngine();
|
||||
|
||||
enum Steps
|
||||
{
|
||||
StepExtractContentLeftDocument,
|
||||
StepExtractContentRightDocument,
|
||||
StepExtractTextLeftDocument,
|
||||
StepExtractTextRightDocument,
|
||||
StepCompare,
|
||||
StepLast
|
||||
};
|
||||
|
||||
PDFDiffResult perform();
|
||||
void stepProgress();
|
||||
|
||||
void onComparationPerformed();
|
||||
|
||||
PDFProgress* m_progress;
|
||||
const PDFDocument* m_leftDocument;
|
||||
const PDFDocument* m_rightDocument;
|
||||
PDFClosedIntervalSet m_pagesForLeftDocument;
|
||||
PDFClosedIntervalSet m_pagesForRightDocument;
|
||||
Options m_options;
|
||||
std::atomic_bool m_cancelled;
|
||||
PDFDiffResult m_result;
|
||||
|
||||
QFuture<PDFDiffResult> m_future;
|
||||
std::optional<QFutureWatcher<PDFDiffResult>> m_futureWatcher;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
@@ -367,6 +367,15 @@ std::vector<PDFInteger> PDFClosedIntervalSet::unfold() const
|
||||
return result;
|
||||
}
|
||||
|
||||
void PDFClosedIntervalSet::translate(PDFInteger offset)
|
||||
{
|
||||
for (auto& interval : m_intervals)
|
||||
{
|
||||
interval.first += offset;
|
||||
interval.second += offset;
|
||||
}
|
||||
}
|
||||
|
||||
PDFClosedIntervalSet PDFClosedIntervalSet::parse(PDFInteger first, PDFInteger last, const QString& text, QString* errorMessage)
|
||||
{
|
||||
PDFClosedIntervalSet result;
|
||||
|
@@ -694,6 +694,10 @@ public:
|
||||
/// Returns true, if interval set is empty
|
||||
bool isEmpty() const { return m_intervals.empty(); }
|
||||
|
||||
/// Translates interval set by a given offset
|
||||
/// \param offset Offset
|
||||
void translate(PDFInteger offset);
|
||||
|
||||
/// Parses text into closed interval set, text should be in form "1,3,4,7,-11,12-,52-53,-",
|
||||
/// where 1,3,4,7 means single pages, -11 means range from \p first to 11, 12- means range
|
||||
/// from 12 to \p last, and 52-53 means closed interval [52, 53]. If text is not in this form,
|
||||
|
Reference in New Issue
Block a user