mirror of
				https://github.com/JakubMelka/PDF4QT.git
				synced 2025-06-05 21:59:17 +02:00 
			
		
		
		
	Asynchronous document loading
This commit is contained in:
		| @@ -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 |  | ||||||
|     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); |     QApplication::setOverrideCursor(Qt::WaitCursor); | ||||||
|     pdf::PDFDocumentReader reader(m_progress, qMove(getPasswordCallback)); |     auto readDocument = [this, fileName]() -> AsyncReadingResult | ||||||
|     pdf::PDFDocument document = reader.readFromFile(fileName); |     { | ||||||
|  |         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(); |     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) | ||||||
| { | { | ||||||
|     writeSettings(); |     if (m_futureWatcher.isRunning()) | ||||||
|     closeDocument(); |     { | ||||||
|     event->accept(); |         // 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) | 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); | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user