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 <QLabel>
#include <QDoubleSpinBox> #include <QDoubleSpinBox>
#include <QDesktopServices> #include <QDesktopServices>
#include <QtConcurrent/QtConcurrent>
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include "Windows.h" #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::progressStarted, this, &PDFViewerMainWindow::onProgressStarted);
connect(m_progress, &pdf::PDFProgress::progressStep, this, &PDFViewerMainWindow::onProgressStep); connect(m_progress, &pdf::PDFProgress::progressStep, this, &PDFViewerMainWindow::onProgressStep);
connect(m_progress, &pdf::PDFProgress::progressFinished, this, &PDFViewerMainWindow::onProgressFinished); 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(); readActionSettings();
updatePageLayoutActions(); updatePageLayoutActions();
updateUI(true); updateUI(true);
onViewerSettingsChanged(); onViewerSettingsChanged();
updateActionsAvailability();
} }
PDFViewerMainWindow::~PDFViewerMainWindow() PDFViewerMainWindow::~PDFViewerMainWindow()
@ -688,6 +692,23 @@ void PDFViewerMainWindow::updateUI(bool fullUpdate)
m_pageZoomSpinBox->setValue(m_pdfWidget->getDrawWidgetProxy()->getZoom() * 100); 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() void PDFViewerMainWindow::onViewerSettingsChanged()
{ {
m_pdfWidget->updateRenderer(m_settings->getRendererEngine(), m_settings->isMultisampleAntialiasingEnabled() ? m_settings->getRendererSamples() : -1); 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.lastModifiedTime = fileInfo.lastModified();
m_fileInfo.lastReadTime = fileInfo.lastRead(); m_fileInfo.lastReadTime = fileInfo.lastRead();
// Password callback QApplication::setOverrideCursor(Qt::WaitCursor);
auto getPasswordCallback = [this](bool* ok) -> QString auto readDocument = [this, fileName]() -> AsyncReadingResult
{ {
return QInputDialog::getText(this, tr("Encrypted document"), tr("Enter password to acces document content"), QLineEdit::Password, QString(), ok); AsyncReadingResult result;
auto queryPassword = [this](bool* ok)
{
QString result;
*ok = false;
emit queryPasswordRequest(&result, ok);
return result;
}; };
// Try to open a new document // Try to open a new document
QApplication::setOverrideCursor(Qt::WaitCursor); pdf::PDFDocumentReader reader(m_progress, qMove(queryPassword));
pdf::PDFDocumentReader reader(m_progress, qMove(getPasswordCallback));
pdf::PDFDocument document = reader.readFromFile(fileName); 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(); QApplication::restoreOverrideCursor();
switch (reader.getReadingResult()) AsyncReadingResult result = m_future.result();
switch (result.result)
{ {
case pdf::PDFDocumentReader::Result::OK: case pdf::PDFDocumentReader::Result::OK:
{ {
// Mark current directory as this // Mark current directory as this
QFileInfo fileInfo(fileName); QFileInfo fileInfo(m_fileInfo.originalFileName);
m_settings->setDirectory(fileInfo.dir().absolutePath()); m_settings->setDirectory(fileInfo.dir().absolutePath());
m_currentFile = fileInfo.fileName(); m_currentFile = fileInfo.fileName();
m_pdfDocument.reset(new pdf::PDFDocument(std::move(document))); m_pdfDocument = result.document;
setDocument(m_pdfDocument.data()); 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; break;
} }
case pdf::PDFDocumentReader::Result::Failed: 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; break;
} }
@ -805,6 +850,8 @@ void PDFViewerMainWindow::setDocument(const pdf::PDFDocument* document)
onActionTriggered(action); onActionTriggered(action);
} }
} }
updateActionsAvailability();
} }
void PDFViewerMainWindow::closeDocument() void PDFViewerMainWindow::closeDocument()
@ -837,9 +884,18 @@ int PDFViewerMainWindow::adjustDpiX(int value)
void PDFViewerMainWindow::closeEvent(QCloseEvent* event) void PDFViewerMainWindow::closeEvent(QCloseEvent* event)
{ {
if (m_futureWatcher.isRunning())
{
// Jakub Melka: Do not allow to close the application, if document
// reading is running.
event->ignore();
}
else
{
writeSettings(); writeSettings();
closeDocument(); closeDocument();
event->accept(); event->accept();
}
} }
void PDFViewerMainWindow::showEvent(QShowEvent* event) void PDFViewerMainWindow::showEvent(QShowEvent* event)
@ -848,6 +904,11 @@ void PDFViewerMainWindow::showEvent(QShowEvent* event)
m_taskbarButton->setWindow(windowHandle()); 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() void PDFViewerMainWindow::on_actionPageLayoutSinglePage_triggered()
{ {
setPageLayout(pdf::PageLayout::SinglePage); setPageLayout(pdf::PageLayout::SinglePage);

View File

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