summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@theqtcompany.com>2014-12-16 12:11:13 +0100
committerSimon Hausmann <simon.hausmann@theqtcompany.com>2014-12-16 12:11:13 +0100
commit61138411a87d1c155fcb33f1966387ebdeaae3e2 (patch)
treea9f3bd78249d942e26dc02a0e11119c7ae194248
parent188d4a072bdca8facad1b1e0670ed440050384ae (diff)
WIP: network loadingwip/network-loading
-rw-r--r--examples/widgets/pdfviewer/main.cpp2
-rw-r--r--examples/widgets/pdfviewer/mainwindow.cpp7
-rw-r--r--examples/widgets/pdfviewer/pagerenderer.cpp113
-rw-r--r--examples/widgets/pdfviewer/pagerenderer.h30
-rw-r--r--examples/widgets/pdfviewer/pdfviewer.pro2
-rw-r--r--examples/widgets/pdfviewer/sequentialpagewidget.cpp12
-rw-r--r--examples/widgets/pdfviewer/sequentialpagewidget.h1
-rw-r--r--src/pdf/qpdfdocument.cpp25
-rw-r--r--src/pdf/qpdfdocument.h2
-rw-r--r--src/pdf/qpdfdocument_p.h2
10 files changed, 133 insertions, 63 deletions
diff --git a/examples/widgets/pdfviewer/main.cpp b/examples/widgets/pdfviewer/main.cpp
index 51a3f98..271c25f 100644
--- a/examples/widgets/pdfviewer/main.cpp
+++ b/examples/widgets/pdfviewer/main.cpp
@@ -9,7 +9,7 @@ int main(int argc, char *argv[])
QStringList args = a.arguments();
w.show();
if (args.length() > 1)
- w.open(QUrl::fromLocalFile(args[1]));
+ w.open(QUrl::fromUserInput(args[1]));
return a.exec();
}
diff --git a/examples/widgets/pdfviewer/mainwindow.cpp b/examples/widgets/pdfviewer/mainwindow.cpp
index f3fa000..0836012 100644
--- a/examples/widgets/pdfviewer/mainwindow.cpp
+++ b/examples/widgets/pdfviewer/mainwindow.cpp
@@ -45,12 +45,7 @@ MainWindow::~MainWindow()
void MainWindow::open(const QUrl &docLocation)
{
- if (docLocation.isLocalFile())
- m_pageWidget->openDocument(docLocation);
- else {
- qCDebug(lcExample) << docLocation << "is not a valid local file";
- QMessageBox::critical(this, tr("Failed to open"), tr("%1 is not a valid local file").arg(docLocation.toString()));
- }
+ m_pageWidget->openDocument(docLocation);
qCDebug(lcExample) << docLocation;
ui->scrollArea->ensureVisible(0, 0, 0, 0);
}
diff --git a/examples/widgets/pdfviewer/pagerenderer.cpp b/examples/widgets/pdfviewer/pagerenderer.cpp
index fca4a0f..5270728 100644
--- a/examples/widgets/pdfviewer/pagerenderer.cpp
+++ b/examples/widgets/pdfviewer/pagerenderer.cpp
@@ -4,69 +4,104 @@
#include <QLoggingCategory>
#include <QElapsedTimer>
#include <QUrl>
+#include <QNetworkRequest>
+#include <QNetworkReply>
Q_DECLARE_LOGGING_CATEGORY(lcExample)
PageRenderer::PageRenderer()
- : QThread(Q_NULLPTR)
- , m_doc(new QPdfDocument(this))
- , m_page(0)
- , m_zoom(1.)
+ : m_networkAccessManager(new QNetworkAccessManager(this))
, m_minRenderTime(1000000000.)
, m_maxRenderTime(0.)
, m_totalRenderTime(0.)
, m_totalPagesRendered(0)
{
+ qRegisterMetaType<QVector<QSizeF> >();
+
+ m_workerThread.start();
+ moveToThread(&m_workerThread);
+
+ connect(&m_doc, SIGNAL(documentLoadStarted()), this, SLOT(reportPageSizes()));
+ connect(&m_doc, SIGNAL(pageAvailable(int)), this, SLOT(renderPageIfRequested(int)));
}
PageRenderer::~PageRenderer()
{
+ m_workerThread.exit();
}
-QVector<QSizeF> PageRenderer::openDocument(const QUrl &location)
+void PageRenderer::openDocument(const QUrl &location)
{
- if (location.isLocalFile())
- m_doc.load(location.toLocalFile());
- else {
- qCWarning(lcExample, "non-local file loading is not implemented");
- return QVector<QSizeF>();
- }
- // TODO maybe do in run() if it takes too long
- QVector<QSizeF> pageSizes;
- for (int page = 0; page < m_doc.pageCount(); ++page)
- pageSizes.append(m_doc.pageSize(page));
- return pageSizes;
+ QMetaObject::invokeMethod(this, "loadDocumentImpl", Qt::QueuedConnection, Q_ARG(QUrl, location));
+}
+
+void PageRenderer::requestPage(int page, qreal zoom)
+{
+ QMetaObject::invokeMethod(this, "requestPageImpl", Qt::QueuedConnection, Q_ARG(int, page), Q_ARG(qreal, zoom));
+}
+
+void PageRenderer::reportPageSizes()
+{
+ QVector<QSizeF> sizes;
+ for (int i = 0, count = m_doc.pageCount(); i < count; ++i)
+ sizes << m_doc.pageSize(i);
+ emit pageSizesAvailable(sizes);
+ if (!m_renderRequests.isEmpty())
+ QMetaObject::invokeMethod(this, "renderPages", Qt::QueuedConnection);
}
-void PageRenderer::requestPage(int page, qreal zoom, Priority priority)
+void PageRenderer::loadDocumentImpl(const QUrl &url)
{
- // TODO maybe queue up the requests
- m_page = page;
- m_zoom = zoom;
- start(priority);
+ m_renderRequests.clear();
+ QNetworkReply *reply = m_networkAccessManager->get(QNetworkRequest(url));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(handleNetworkRequestError()));
+ m_doc.load(reply);
+ connect(&m_doc, SIGNAL(documentLoadFinished()), reply, SLOT(deleteLater()));
}
-void PageRenderer::run()
+void PageRenderer::requestPageImpl(int page, qreal zoom)
{
- renderPage(m_page, m_zoom);
+ RenderRequest newRequest;
+ newRequest.page = page;
+ newRequest.zoom = zoom;
+ m_renderRequests << newRequest;
+ if (!m_doc.isLoading())
+ QMetaObject::invokeMethod(this, "renderPages", Qt::QueuedConnection);
}
-void PageRenderer::renderPage(int page, qreal zoom)
+void PageRenderer::renderPages()
{
- QSizeF size = m_doc.pageSize(page) * m_zoom;
- QElapsedTimer timer; timer.start();
- const QImage &img = m_doc.render(page, size);
- qreal secs = timer.nsecsElapsed() / 1000000000.0;
- if (secs < m_minRenderTime)
- m_minRenderTime = secs;
- if (secs > m_maxRenderTime)
- m_maxRenderTime = secs;
- m_totalRenderTime += secs;
- ++m_totalPagesRendered;
- emit pageReady(page, zoom, img);
+ for (int i = 0; i < m_renderRequests.count(); ++i) {
+ if (!m_doc.canRender(m_renderRequests.at(i).page))
+ continue;
+ RenderRequest request = m_renderRequests.takeAt(i);
- qCDebug(lcExample) << "page" << page << "zoom" << m_zoom << "size" << size << "in" << secs <<
- "secs; min" << m_minRenderTime <<
- "avg" << m_totalRenderTime / m_totalPagesRendered <<
- "max" << m_maxRenderTime;
+ QSizeF size = m_doc.pageSize(request.page) * request.zoom;
+ QElapsedTimer timer; timer.start();
+ QImage img = m_doc.render(request.page, size);
+ qreal secs = timer.nsecsElapsed() / 1000000000.0;
+ if (secs < m_minRenderTime)
+ m_minRenderTime = secs;
+ if (secs > m_maxRenderTime)
+ m_maxRenderTime = secs;
+ m_totalRenderTime += secs;
+ ++m_totalPagesRendered;
+ emit pageReady(request.page, request.zoom, img);
+
+ qCDebug(lcExample) << "page" << request.page << "zoom" << request.zoom << "size" << size << "in" << secs <<
+ "secs; min" << m_minRenderTime <<
+ "avg" << m_totalRenderTime / m_totalPagesRendered <<
+ "max" << m_maxRenderTime;
+ break;
+ }
+}
+
+void PageRenderer::renderPageIfRequested(int page)
+{
+ renderPages();
+}
+
+void PageRenderer::handleNetworkRequestError()
+{
+ qDebug() << static_cast<QNetworkReply*>(sender())->errorString();
}
diff --git a/examples/widgets/pdfviewer/pagerenderer.h b/examples/widgets/pdfviewer/pagerenderer.h
index 35c8939..a35bc74 100644
--- a/examples/widgets/pdfviewer/pagerenderer.h
+++ b/examples/widgets/pdfviewer/pagerenderer.h
@@ -7,10 +7,11 @@
#include <QRunnable>
#include <QThread>
#include <QPdfDocument>
+#include <QNetworkAccessManager>
class QPdfDocument;
-class PageRenderer : public QThread
+class PageRenderer : public QObject
{
Q_OBJECT
public:
@@ -18,24 +19,31 @@ public:
~PageRenderer();
public slots:
- QVector<QSizeF> openDocument(const QUrl &location);
- void requestPage(int page, qreal zoom, Priority priority = QThread::NormalPriority);
+ void openDocument(const QUrl &location);
+ void requestPage(int page, qreal zoom);
signals:
+ void pageSizesAvailable(const QVector<QSizeF> &sizes);
void pageReady(int page, qreal zoom, QImage image);
-protected:
- void run() Q_DECL_OVERRIDE;
-
-private:
- void renderPage(int page, qreal zoom);
+private slots:
+ void reportPageSizes();
+ void loadDocumentImpl(const QUrl &url);
+ void requestPageImpl(int page, qreal zoom);
+ void renderPages();
+ void renderPageIfRequested(int page);
+ void handleNetworkRequestError();
private:
+ QThread m_workerThread;
QPdfDocument m_doc;
- // current request only
- int m_page;
- qreal m_zoom;
+ struct RenderRequest {
+ int page;
+ qreal zoom;
+ };
+ QVector<RenderRequest> m_renderRequests;
+ QNetworkAccessManager *m_networkAccessManager;
// performance statistics
qreal m_minRenderTime;
diff --git a/examples/widgets/pdfviewer/pdfviewer.pro b/examples/widgets/pdfviewer/pdfviewer.pro
index e8269c4..9107983 100644
--- a/examples/widgets/pdfviewer/pdfviewer.pro
+++ b/examples/widgets/pdfviewer/pdfviewer.pro
@@ -1,4 +1,4 @@
-QT += core gui widgets pdf
+QT += core gui widgets pdf network
TARGET = pdfviewer
TEMPLATE = app
diff --git a/examples/widgets/pdfviewer/sequentialpagewidget.cpp b/examples/widgets/pdfviewer/sequentialpagewidget.cpp
index c85f784..4073302 100644
--- a/examples/widgets/pdfviewer/sequentialpagewidget.cpp
+++ b/examples/widgets/pdfviewer/sequentialpagewidget.cpp
@@ -21,6 +21,7 @@ SequentialPageWidget::SequentialPageWidget(QWidget *parent)
, m_zoom(1.)
, m_screenResolution(QGuiApplication::primaryScreen()->logicalDotsPerInch() / 72.0)
{
+ connect(m_pageRenderer, SIGNAL(pageSizesAvailable(QVector<QSizeF>)), this, SLOT(preparePages(QVector<QSizeF>)));
connect(m_pageRenderer, SIGNAL(pageReady(int, qreal, QImage)), this, SLOT(pageLoaded(int, qreal, QImage)), Qt::QueuedConnection);
}
@@ -31,9 +32,7 @@ SequentialPageWidget::~SequentialPageWidget()
void SequentialPageWidget::openDocument(const QUrl &url)
{
- m_pageSizes = m_pageRenderer->openDocument(url);
- m_topPageShowing = 0;
- invalidate();
+ m_pageRenderer->openDocument(url);
}
void SequentialPageWidget::setZoom(qreal factor)
@@ -66,6 +65,13 @@ void SequentialPageWidget::invalidate()
update();
}
+void SequentialPageWidget::preparePages(const QVector<QSizeF> &pageSizes)
+{
+ m_pageSizes = pageSizes;
+ m_topPageShowing = 0;
+ invalidate();
+}
+
void SequentialPageWidget::pageLoaded(int page, qreal zoom, QImage image)
{
Q_UNUSED(zoom)
diff --git a/examples/widgets/pdfviewer/sequentialpagewidget.h b/examples/widgets/pdfviewer/sequentialpagewidget.h
index 2a3025d..edf7d53 100644
--- a/examples/widgets/pdfviewer/sequentialpagewidget.h
+++ b/examples/widgets/pdfviewer/sequentialpagewidget.h
@@ -29,6 +29,7 @@ signals:
void zoomChanged(qreal factor);
private slots:
+ void preparePages(const QVector<QSizeF> &pageSizes);
void pageLoaded(int page, qreal zoom, QImage image);
private:
diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp
index b48bbda..4d7990d 100644
--- a/src/pdf/qpdfdocument.cpp
+++ b/src/pdf/qpdfdocument.cpp
@@ -57,6 +57,7 @@ void QPdfDocumentPrivate::clear()
avail = 0;
loadComplete = false;
+ reportedAvailablePages.clear();
asyncBuffer.close();
asyncBuffer.setData(QByteArray());
@@ -169,8 +170,11 @@ void QPdfDocumentPrivate::tryLoadDocument()
updateLastError();
if (lastError == QPdfDocument::IncorrectPasswordError)
emit q->passwordRequired();
- else if (doc)
+ else if (doc) {
emit q->documentLoadStarted();
+ reportedAvailablePages.resize(FPDF_GetPageCount(doc));
+ reportedAvailablePages.fill(false);
+ }
}
void QPdfDocumentPrivate::checkComplete()
@@ -187,8 +191,14 @@ void QPdfDocumentPrivate::checkComplete()
loadComplete = true;
for (int i = 0, count = FPDF_GetPageCount(doc); i < count; ++i)
- if (!FPDFAvail_IsPageAvail(avail, i, this))
+ if (FPDFAvail_IsPageAvail(avail, i, this)) {
+ if (!reportedAvailablePages.at(i)) {
+ reportedAvailablePages[i] = true;
+ emit q->pageAvailable(i);
+ }
+ } else {
loadComplete = false;
+ }
if (loadComplete)
emit q->documentLoadFinished();
}
@@ -285,6 +295,14 @@ QSizeF QPdfDocument::pageSize(int page) const
return result;
}
+bool QPdfDocument::canRender(int page) const
+{
+ QMutexLocker lock(pdfMutex());
+ if (!d->doc)
+ return false;
+ return d->reportedAvailablePages.at(page);
+}
+
QImage QPdfDocument::render(int page, const QSizeF &pageSize)
{
if (!d->doc)
@@ -292,6 +310,9 @@ QImage QPdfDocument::render(int page, const QSizeF &pageSize)
QMutexLocker lock(pdfMutex());
+ if (!FPDFAvail_IsPageAvail(d->avail, page, d.data()))
+ return QImage();
+
FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page);
if (!pdfPage)
return QImage();
diff --git a/src/pdf/qpdfdocument.h b/src/pdf/qpdfdocument.h
index 6459f39..c846333 100644
--- a/src/pdf/qpdfdocument.h
+++ b/src/pdf/qpdfdocument.h
@@ -44,11 +44,13 @@ public:
QSizeF pageSize(int page) const;
+ bool canRender(int page) const;
QImage render(int page, const QSizeF &pageSize);
Q_SIGNALS:
void passwordRequired();
void documentLoadStarted();
+ void pageAvailable(int page);
void documentLoadFinished();
void pageCountChanged();
diff --git a/src/pdf/qpdfdocument_p.h b/src/pdf/qpdfdocument_p.h
index 7850c65..2e19fb0 100644
--- a/src/pdf/qpdfdocument_p.h
+++ b/src/pdf/qpdfdocument_p.h
@@ -9,6 +9,7 @@
#include <qbuffer.h>
#include <qnetworkreply.h>
#include <qpointer.h>
+#include <qbitarray.h>
QT_BEGIN_NAMESPACE
@@ -23,6 +24,7 @@ public:
FPDF_AVAIL avail;
FPDF_DOCUMENT doc;
bool loadComplete;
+ QBitArray reportedAvailablePages;
QPointer<QIODevice> device;
QScopedPointer<QIODevice> ownDevice;