on xenial help sign in
Make CroppedImageSizer async
54f979aAlbert Astals
plugins/Dash/CMakeLists.txt+2−2
@@ -11,7 +11,6 @@ include_directories(
11 ${CMAKE_CURRENT_SOURCE_DIR}
11 ${CMAKE_CURRENT_SOURCE_DIR}
12 ${CMAKE_CURRENT_BINARY_DIR}
12 ${CMAKE_CURRENT_BINARY_DIR}
13 ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
13 ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
14− ${Qt5Quick_INCLUDE_DIRS}
15 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
14 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
16 ${Qt5V8_PRIVATE_INCLUDE_DIR}
15 ${Qt5V8_PRIVATE_INCLUDE_DIR}
17)
16)
@@ -26,6 +25,7 @@ set(QMLPLUGIN_SRC
26 horizontaljournal.cpp
25 horizontaljournal.cpp
27 organicgrid.cpp
26 organicgrid.cpp
28 croppedimagesizer.cpp
27 croppedimagesizer.cpp
28+ croppedimagesizerasyncworker.cpp
29 )
29 )
30
30
31add_library(Dash-qml MODULE
31add_library(Dash-qml MODULE
@@ -37,6 +37,6 @@ target_link_libraries(Dash-qml
37 ${Qt5Quick_LIBRARIES}
37 ${Qt5Quick_LIBRARIES}
38 )
38 )
39
39
40−qt5_use_modules(Dash-qml Qml Quick)
40+qt5_use_modules(Dash-qml Qml Quick Concurrent)
41
41
42add_unity8_plugin(Dash 0.1 Dash TARGETS Dash-qml)
42add_unity8_plugin(Dash 0.1 Dash TARGETS Dash-qml)
plugins/Dash/croppedimagesizer.cpp+21−26
@@ -16,17 +16,18 @@
16
16
17#include "croppedimagesizer.h"
17#include "croppedimagesizer.h"
18
18
19−#include <QDebug>
19+#include "croppedimagesizerasyncworker.h"
20−#include <QNetworkReply>
20+
21+#include <QNetworkAccessManager>
21#include <QNetworkRequest>
22#include <QNetworkRequest>
22#include <QQmlEngine>
23#include <QQmlEngine>
23#include <QQuickItem>
24#include <QQuickItem>
24−#include <QQuickView>
25
25
26CroppedImageSizer::CroppedImageSizer()
26CroppedImageSizer::CroppedImageSizer()
27 : m_width(0),
27 : m_width(0),
28 m_height(0),
28 m_height(0),
29− m_sourceSize(QSize(-1, -1))
29+ m_sourceSize(QSize(-1, -1)),
30+ m_worker(nullptr)
30{
31{
31 connect(this, &CroppedImageSizer::inputParamsChanged, this, &CroppedImageSizer::calculateSourceSize);
32 connect(this, &CroppedImageSizer::inputParamsChanged, this, &CroppedImageSizer::calculateSourceSize);
32 connect(this, &CroppedImageSizer::sourceChanged, this, &CroppedImageSizer::requestImage);
33 connect(this, &CroppedImageSizer::sourceChanged, this, &CroppedImageSizer::requestImage);
@@ -34,8 +35,8 @@ CroppedImageSizer::CroppedImageSizer()
34
35
35CroppedImageSizer::~CroppedImageSizer()
36CroppedImageSizer::~CroppedImageSizer()
36{
37{
37− if (m_reply) {
38+ if (m_worker) {
38− m_reply->deleteLater();
39+ m_worker->abort();
39 }
40 }
40}
41}
41
42
@@ -91,38 +92,32 @@ void CroppedImageSizer::setSourceSize(const QSize &sourceSize)
91 }
92 }
92}
93}
93
94
95+void CroppedImageSizer::setImageSize(const QSize &imageSize)
96+{
97+ m_imageSize = imageSize;
98+ m_worker = nullptr;
99+ calculateSourceSize();
100+}
101+
94void CroppedImageSizer::requestImage()
102void CroppedImageSizer::requestImage()
95{
103{
96− if (m_reply) {
104+ if (m_worker) {
97− m_reply->disconnect();
98− m_reply->abort();
105+ m_worker->abort();
99− m_reply->deleteLater();
100− m_reply = nullptr;
106+ m_worker = nullptr;
101 }
107 }
102
108
103 if (m_source.isValid() && qmlEngine(this) && qmlEngine(this)->networkAccessManager()) {
109 if (m_source.isValid() && qmlEngine(this) && qmlEngine(this)->networkAccessManager()) {
104 QNetworkRequest request(m_source);
110 QNetworkRequest request(m_source);
105− m_reply = qmlEngine(this)->networkAccessManager()->get(request);
111+ QNetworkReply *reply = qmlEngine(this)->networkAccessManager()->get(request);
106− connect(m_reply, &QNetworkReply::finished, this, &CroppedImageSizer::requestFinished);
112+ m_worker = new CroppedImageSizerAsyncWorker(this, reply);
107− } else {
113+ } else {
108 setSourceSize(QSize(-1, -1));
114 setSourceSize(QSize(-1, -1));
109 }
115 }
110}
116}
111
117
112−void CroppedImageSizer::requestFinished()
113−{
114− QImageReader m_reader(m_reply);
115− m_imageSize = m_reader.size();
116−
117− m_reply->deleteLater();
118− m_reply = nullptr;
119−
120− calculateSourceSize();
121−}
122−
123void CroppedImageSizer::calculateSourceSize()
118void CroppedImageSizer::calculateSourceSize()
124{
119{
125− if (m_source.isValid() && m_width > 0 && m_height > 0 && !m_reply) {
120+ if (m_source.isValid() && m_width > 0 && m_height > 0 && !m_worker) {
126 if (!m_imageSize.isEmpty()) {
121 if (!m_imageSize.isEmpty()) {
127 const qreal ar = m_width / m_height;
122 const qreal ar = m_width / m_height;
128 const qreal ssar = m_imageSize.width() / (qreal)m_imageSize.height();
123 const qreal ssar = m_imageSize.width() / (qreal)m_imageSize.height();
plugins/Dash/croppedimagesizer.h+4−3
@@ -22,7 +22,7 @@
22#include <QSize>
22#include <QSize>
23#include <QUrl>
23#include <QUrl>
24
24
25−class QNetworkReply;
25+class CroppedImageSizerAsyncWorker;
26
26
27class CroppedImageSizer : public QObject
27class CroppedImageSizer : public QObject
28{
28{
@@ -49,6 +49,8 @@ public:
49 QSize sourceSize() const;
49 QSize sourceSize() const;
50 void setSourceSize(const QSize &sourceSize);
50 void setSourceSize(const QSize &sourceSize);
51
51
52+ Q_INVOKABLE void setImageSize(const QSize &imageSize);
53+
52Q_SIGNALS:
54Q_SIGNALS:
53 void inputParamsChanged();
55 void inputParamsChanged();
54 void sourceChanged();
56 void sourceChanged();
@@ -56,7 +58,6 @@ Q_SIGNALS:
56
58
57private Q_SLOT:
59private Q_SLOT:
58 void calculateSourceSize();
60 void calculateSourceSize();
59− void requestFinished();
60 void requestImage();
61 void requestImage();
61
62
62private:
63private:
@@ -65,7 +66,7 @@ private:
65 qreal m_height;
66 qreal m_height;
66 QSize m_sourceSize;
67 QSize m_sourceSize;
67 QSize m_imageSize;
68 QSize m_imageSize;
68− QNetworkReply *m_reply = nullptr;
69+ QPointer<CroppedImageSizerAsyncWorker> m_worker;
69};
70};
70
71
71#endif
72#endif
plugins/Dash/croppedimagesizerasyncworker.cppnew file+74
@@ -0,0 +1,74 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "croppedimagesizerasyncworker.h"
18+
19+#include "croppedimagesizer.h"
20+
21+#include <QNetworkReply>
22+#include <QtConcurrentRun>
23+
24+CroppedImageSizerAsyncWorker::CroppedImageSizerAsyncWorker(CroppedImageSizer *sizer, QNetworkReply *reply)
25+ : m_sizer(sizer),
26+ m_reply(reply),
27+ m_ignoreAbort(false)
28+{
29+ connect(m_reply, &QNetworkReply::finished, this, &CroppedImageSizerAsyncWorker::requestFinished);
30+}
31+
32+void CroppedImageSizerAsyncWorker::abort()
33+{
34+ // This runs on main thread
35+ QMutexLocker locker(&m_mutex);
36+ m_sizer = nullptr;
37+ // If we already started the future run we can't abort the reply
38+ // since we don't know at which stage the future is, just let it finish
39+ if (!m_ignoreAbort) {
40+ QMetaObject::invokeMethod(m_reply, "abort", Qt::QueuedConnection);
41+ }
42+}
43+
44+void CroppedImageSizerAsyncWorker::requestFinished()
45+{
46+ // This runs on main thread
47+ QMutexLocker locker(&m_mutex);
48+ if (m_sizer) {
49+ m_ignoreAbort = true;
50+ QtConcurrent::run(processRequestFinished, this);
51+ } else {
52+ // We were aborted delete ourselves
53+ m_reply->deleteLater();
54+ deleteLater();
55+ }
56+}
57+
58+void CroppedImageSizerAsyncWorker::processRequestFinished(CroppedImageSizerAsyncWorker *worker)
59+{
60+ // This runs on non main thread
61+ // m_reply has finished at this point and is protected against change by m_ignoreAbort
62+ QImageReader reader(worker->m_reply);
63+ const QSize imageSize = reader.size();
64+
65+ worker->m_mutex.lock();
66+ if (worker->m_sizer) {
67+ QMetaObject::invokeMethod(worker->m_sizer, "setImageSize", Qt::QueuedConnection, Q_ARG(QSize, imageSize));
68+ }
69+ worker->m_mutex.unlock();
70+
71+ // All work is done, delete ourselves
72+ worker->m_reply->deleteLater();
73+ worker->deleteLater();
74+}
plugins/Dash/croppedimagesizerasyncworker.hnew file+47
@@ -0,0 +1,47 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef CROPPEDIMAGESIZERASYNCWORKER_H
18+#define CROPPEDIMAGESIZERASYNCWORKER_H
19+
20+#include <QMutex>
21+#include <QObject>
22+
23+class CroppedImageSizer;
24+
25+class QNetworkReply;
26+
27+class CroppedImageSizerAsyncWorker : public QObject
28+{
29+ Q_OBJECT
30+public:
31+ CroppedImageSizerAsyncWorker(CroppedImageSizer *sizer, QNetworkReply *reply);
32+
33+ void abort();
34+
35+private Q_SLOTS:
36+ void requestFinished();
37+
38+private:
39+ static void processRequestFinished(CroppedImageSizerAsyncWorker *worker);
40+
41+ QMutex m_mutex;
42+ CroppedImageSizer *m_sizer;
43+ QNetworkReply *m_reply;
44+ bool m_ignoreAbort;
45+};
46+
47+#endif