Asynchronous document loading

This commit is contained in:
Jakub Melka 2019-12-23 15:58:40 +01:00
parent 38748340fa
commit fb47d22225
2 changed files with 100 additions and 17 deletions

View File

@ -50,6 +50,7 @@
#include <QLabel>
#include <QDoubleSpinBox>
#include <QDesktopServices>
#include <QtConcurrent/QtConcurrent>
#ifdef Q_OS_WIN
#include "Windows.h"
@ -188,11 +189,14 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget *parent) :
connect(m_progress, &pdf::PDFProgress::progressStarted, this, &PDFViewerMainWindow::onProgressStarted);
connect(m_progress, &pdf::PDFProgress::progressStep, this, &PDFViewerMainWindow::onProgressStep);
connect(m_progress, &pdf::PDFProgress::progressFinished, this, &PDFViewerMainWindow::onProgressFinished);
connect(&m_futureWatcher, &QFutureWatcher<AsyncReadingResult>::finished, this, &PDFViewerMainWindow::onDocumentReadingFinished);
connect(this, &PDFViewerMainWindow::queryPasswordRequest, this, &PDFViewerMainWindow::onQueryPasswordRequest, Qt::BlockingQueuedConnection);
readActionSettings();
updatePageLayoutActions();
updateUI(true);
onViewerSettingsChanged();
updateActionsAvailability();
}
PDFViewerMainWindow::~PDFViewerMainWindow()
@ -688,6 +692,23 @@ void PDFViewerMainWindow::updateUI(bool fullUpdate)
m_pageZoomSpinBox->setValue(m_pdfWidget->getDrawWidgetProxy()->getZoom() * 100);
}
void PDFViewerMainWindow::updateActionsAvailability()
{
const bool isReading = m_futureWatcher.isRunning();
const bool hasDocument = m_pdfDocument;
const bool hasValidDocument = !isReading && hasDocument;
ui->actionOpen->setEnabled(!isReading);
ui->actionClose->setEnabled(hasValidDocument);
ui->actionQuit->setEnabled(!isReading);
ui->actionOptions->setEnabled(!isReading);
ui->actionAbout->setEnabled(!isReading);
ui->actionFitPage->setEnabled(hasValidDocument);
ui->actionFitWidth->setEnabled(hasValidDocument);
ui->actionFitHeight->setEnabled(hasValidDocument);
ui->actionRendering_Errors->setEnabled(hasValidDocument);
}
void PDFViewerMainWindow::onViewerSettingsChanged()
{
m_pdfWidget->updateRenderer(m_settings->getRendererEngine(), m_settings->isMultisampleAntialiasingEnabled() ? m_settings->getRendererSamples() : -1);
@ -725,37 +746,61 @@ void PDFViewerMainWindow::openDocument(const QString& fileName)
m_fileInfo.lastModifiedTime = fileInfo.lastModified();
m_fileInfo.lastReadTime = fileInfo.lastRead();
// Password callback
auto getPasswordCallback = [this](bool* ok) -> QString
{
return QInputDialog::getText(this, tr("Encrypted document"), tr("Enter password to acces document content"), QLineEdit::Password, QString(), ok);
};
// Try to open a new document
QApplication::setOverrideCursor(Qt::WaitCursor);
pdf::PDFDocumentReader reader(m_progress, qMove(getPasswordCallback));
pdf::PDFDocument document = reader.readFromFile(fileName);
auto readDocument = [this, fileName]() -> AsyncReadingResult
{
AsyncReadingResult result;
auto queryPassword = [this](bool* ok)
{
QString result;
*ok = false;
emit queryPasswordRequest(&result, ok);
return result;
};
// Try to open a new document
pdf::PDFDocumentReader reader(m_progress, qMove(queryPassword));
pdf::PDFDocument document = reader.readFromFile(fileName);
result.errorMessage = reader.getErrorMessage();
result.result = reader.getReadingResult();
if (result.result == pdf::PDFDocumentReader::Result::OK)
{
result.document.reset(new pdf::PDFDocument(qMove(document)));
}
return result;
};
m_future = QtConcurrent::run(readDocument);
m_futureWatcher.setFuture(m_future);
updateActionsAvailability();
}
void PDFViewerMainWindow::onDocumentReadingFinished()
{
QApplication::restoreOverrideCursor();
switch (reader.getReadingResult())
AsyncReadingResult result = m_future.result();
switch (result.result)
{
case pdf::PDFDocumentReader::Result::OK:
{
// Mark current directory as this
QFileInfo fileInfo(fileName);
QFileInfo fileInfo(m_fileInfo.originalFileName);
m_settings->setDirectory(fileInfo.dir().absolutePath());
m_currentFile = fileInfo.fileName();
m_pdfDocument.reset(new pdf::PDFDocument(std::move(document)));
m_pdfDocument = result.document;
setDocument(m_pdfDocument.data());
statusBar()->showMessage(tr("Document '%1' was successfully loaded!").arg(fileName), 4000);
statusBar()->showMessage(tr("Document '%1' was successfully loaded!").arg(m_fileInfo.fileName), 4000);
break;
}
case pdf::PDFDocumentReader::Result::Failed:
{
QMessageBox::critical(this, tr("PDF Viewer"), tr("Document read error: %1").arg(reader.getErrorMessage()));
QMessageBox::critical(this, tr("PDF Viewer"), tr("Document read error: %1").arg(result.errorMessage));
break;
}
@ -805,6 +850,8 @@ void PDFViewerMainWindow::setDocument(const pdf::PDFDocument* document)
onActionTriggered(action);
}
}
updateActionsAvailability();
}
void PDFViewerMainWindow::closeDocument()
@ -837,9 +884,18 @@ int PDFViewerMainWindow::adjustDpiX(int value)
void PDFViewerMainWindow::closeEvent(QCloseEvent* event)
{
writeSettings();
closeDocument();
event->accept();
if (m_futureWatcher.isRunning())
{
// Jakub Melka: Do not allow to close the application, if document
// reading is running.
event->ignore();
}
else
{
writeSettings();
closeDocument();
event->accept();
}
}
void PDFViewerMainWindow::showEvent(QShowEvent* event)
@ -848,6 +904,11 @@ void PDFViewerMainWindow::showEvent(QShowEvent* event)
m_taskbarButton->setWindow(windowHandle());
}
void PDFViewerMainWindow::onQueryPasswordRequest(QString* password, bool* ok)
{
*password = QInputDialog::getText(this, tr("Encrypted document"), tr("Enter password to access document content"), QLineEdit::Password, QString(), ok);
}
void PDFViewerMainWindow::on_actionPageLayoutSinglePage_triggered()
{
setPageLayout(pdf::PageLayout::SinglePage);

View File

@ -21,14 +21,18 @@
#include "pdfcatalog.h"
#include "pdfrenderer.h"
#include "pdfprogress.h"
#include "pdfdocument.h"
#include "pdfviewersettings.h"
#include "pdfdocumentreader.h"
#include "pdfdocumentpropertiesdialog.h"
#include <QFuture>
#include <QTreeView>
#include <QMainWindow>
#include <QSharedPointer>
#include <QWinTaskbarButton>
#include <QWinTaskbarProgress>
#include <QFutureWatcher>
class QLabel;
class QSpinBox;
@ -63,7 +67,12 @@ public:
virtual void closeEvent(QCloseEvent* event) override;
virtual void showEvent(QShowEvent* event) override;
signals:
void queryPasswordRequest(QString* password, bool* ok);
private slots:
void onQueryPasswordRequest(QString* password, bool* ok);
void on_actionPageLayoutSinglePage_triggered();
void on_actionPageLayoutContinuous_triggered();
void on_actionPageLayoutTwoPages_triggered();
@ -96,6 +105,8 @@ private:
void onProgressStep(int percentage);
void onProgressFinished();
void onDocumentReadingFinished();
void readSettings();
void readActionSettings();
void writeSettings();
@ -104,6 +115,7 @@ private:
void updatePageLayoutActions();
void updateRenderingOptionActions();
void updateUI(bool fullUpdate);
void updateActionsAvailability();
void onViewerSettingsChanged();
void onRenderingOptionTriggered(bool checked);
@ -119,6 +131,13 @@ private:
int adjustDpiX(int value);
struct AsyncReadingResult
{
QSharedPointer<pdf::PDFDocument> document;
QString errorMessage;
pdf::PDFDocumentReader::Result result = pdf::PDFDocumentReader::Result::Cancelled;
};
Ui::PDFViewerMainWindow* ui;
PDFViewerSettings* m_settings;
pdf::PDFWidget* m_pdfWidget;
@ -135,6 +154,9 @@ private:
QWinTaskbarButton* m_taskbarButton;
QWinTaskbarProgress* m_progressTaskbarIndicator;
PDFFileInfo m_fileInfo;
QFuture<AsyncReadingResult> m_future;
QFutureWatcher<AsyncReadingResult> m_futureWatcher;
};
} // namespace pdfviewer