1#include <QDomDocument>
2#include <QEventLoop>
3#include <QFile>
4#include <QNetworkAccessManager>
5#include <QNetworkReply>
6#include <QNetworkRequest>
7#include <QThread>
8
9#include <ThreadWeaver/Exception>
10#include <ThreadWeaver/ThreadWeaver>
11
12#include "MainWidget.h"
13#include "ViewController.h"
14
15ViewController::ViewController(MainWidget *mainwidget)
16 : QObject() // no parent
17 , m_apiPostUrl(QStringLiteral("http://fickedinger.tumblr.com/api/read?id=94635924143"))
18//@@snippet_begin(hellointernet-sequence)
19{
20 connect(sender: this, SIGNAL(setImage(QImage)), receiver: mainwidget, SLOT(setImage(QImage)));
21 connect(sender: this, SIGNAL(setCaption(QString)), receiver: mainwidget, SLOT(setCaption(QString)));
22 connect(sender: this, SIGNAL(setStatus(QString)), receiver: mainwidget, SLOT(setStatus(QString)));
23
24 using namespace ThreadWeaver;
25 auto s = new Sequence;
26 *s << make_job(t: [this]() {
27 loadPlaceholderFromResource();
28 }) << make_job(t: [this]() {
29 loadPostFromTumblr();
30 }) << make_job(t: [this]() {
31 loadImageFromTumblr();
32 });
33 stream() << s;
34}
35//@@snippet_end
36
37ViewController::~ViewController()
38{
39 ThreadWeaver::Queue::instance()->finish();
40}
41
42//@@snippet_begin(hellointernet-loadresource)
43void ViewController::loadPlaceholderFromResource()
44{
45 QThread::msleep(500);
46 showResourceImage(file: "IMG_20140813_004131.png");
47 Q_EMIT setStatus(tr(s: "Downloading post..."));
48}
49//@@snippet_end
50
51//@@snippet_begin(hellointernet-loadpost)
52void ViewController::loadPostFromTumblr()
53{
54 const QUrl url(m_apiPostUrl);
55
56 auto const data = download(url);
57 Q_EMIT setStatus(tr(s: "Post downloaded..."));
58
59 QDomDocument doc;
60 if (!doc.setContent(data)) {
61 error(message: tr(s: "Post format not recognized!"));
62 }
63
64 auto textOfFirst = [&doc](const char *name) {
65 auto const s = QString::fromLatin1(ba: name);
66 auto elements = doc.elementsByTagName(tagname: s);
67 if (elements.isEmpty()) {
68 return QString();
69 }
70 return elements.at(index: 0).toElement().text();
71 };
72
73 auto const caption = textOfFirst("photo-caption");
74 if (caption.isEmpty()) {
75 error(message: tr(s: "Post does not contain a caption!"));
76 }
77 Q_EMIT setCaption(caption);
78 auto const imageUrl = textOfFirst("photo-url");
79 if (imageUrl.isEmpty()) {
80 error(message: tr(s: "Post does not contain an image!"));
81 }
82
83 m_fullPostUrl = attributeTextFor(doc, tag: "post", attribute: "url-with-slug");
84 if (m_fullPostUrl.isEmpty()) {
85 error(message: tr(s: "Response does not contain URL with slug!"));
86 }
87 m_imageUrl = QUrl(imageUrl);
88 showResourceImage(file: "IMG_20140813_004131-colors-cubed.png");
89 Q_EMIT setStatus(tr(s: "Downloading image..."));
90 QThread::msleep(500);
91}
92//@@snippet_end
93
94void ViewController::loadImageFromTumblr()
95{
96 auto const data = download(url: m_imageUrl);
97 Q_EMIT setStatus(tr(s: "Image downloaded..."));
98 const QImage image = QImage::fromData(data);
99 if (!image.isNull()) {
100 Q_EMIT setImage(image);
101 Q_EMIT setStatus(tr(s: "Download complete (see %1).").arg(a: m_fullPostUrl));
102 } else {
103 error(message: tr(s: "Image format error!"));
104 }
105}
106
107QByteArray ViewController::download(const QUrl &url)
108{
109 QNetworkAccessManager manager;
110 QEventLoop loop;
111 QObject::connect(sender: &manager, SIGNAL(finished(QNetworkReply *)), receiver: &loop, SLOT(quit()));
112 auto reply = manager.get(request: QNetworkRequest(url));
113 loop.exec();
114 if (reply->error() == QNetworkReply::NoError) {
115 const QByteArray data = reply->readAll();
116 return data;
117 } else {
118 error(message: tr(s: "Unable to download data for \"%1\"!").arg(a: url.toString()));
119 return QByteArray();
120 }
121}
122
123//@@snippet_begin(hellointernet-error)
124void ViewController::error(const QString &message)
125{
126 showResourceImage(file: "IMG_20140813_004131-colors-cubed.png");
127 Q_EMIT setCaption(tr(s: "Error"));
128 Q_EMIT setStatus(tr(s: "%1").arg(a: message));
129 throw ThreadWeaver::JobFailed(message);
130}
131//@@snippet_end
132
133void ViewController::showResourceImage(const char *file)
134{
135 const QString path(QStringLiteral("://resources/%1").arg(a: QString::fromLatin1(ba: file)));
136 Q_ASSERT(QFile::exists(path));
137 const QImage i(path);
138 Q_ASSERT(!i.isNull());
139 Q_EMIT setImage(i);
140}
141
142QString ViewController::attributeTextFor(const QDomDocument &doc, const char *tag, const char *attribute)
143{
144 auto const tagString = QString::fromLatin1(ba: tag);
145 auto const attributeString = QString::fromLatin1(ba: attribute);
146 auto elements = doc.elementsByTagName(tagname: tagString);
147 if (elements.isEmpty()) {
148 return QString();
149 }
150 const QString content = elements.at(index: 0).toElement().attribute(name: attributeString);
151 return content;
152}
153
154#include "moc_ViewController.cpp"
155

source code of threadweaver/examples/HelloInternet/ViewController.cpp