File indexing completed on 2024-05-12 15:50:10

0001 #include <QDomDocument>
0002 #include <QEventLoop>
0003 #include <QFile>
0004 #include <QNetworkAccessManager>
0005 #include <QNetworkReply>
0006 #include <QNetworkRequest>
0007 #include <QThread>
0008 
0009 #include <ThreadWeaver/Exception>
0010 #include <ThreadWeaver/ThreadWeaver>
0011 
0012 #include "MainWidget.h"
0013 #include "ViewController.h"
0014 
0015 ViewController::ViewController(MainWidget *mainwidget)
0016     : QObject() // no parent
0017     , m_apiPostUrl(QStringLiteral("http://fickedinger.tumblr.com/api/read?id=94635924143"))
0018 //@@snippet_begin(hellointernet-sequence)
0019 {
0020     connect(this, SIGNAL(setImage(QImage)), mainwidget, SLOT(setImage(QImage)));
0021     connect(this, SIGNAL(setCaption(QString)), mainwidget, SLOT(setCaption(QString)));
0022     connect(this, SIGNAL(setStatus(QString)), mainwidget, SLOT(setStatus(QString)));
0023 
0024     using namespace ThreadWeaver;
0025     auto s = new Sequence;
0026     *s << make_job([=]() {
0027         loadPlaceholderFromResource();
0028     }) << make_job([=]() {
0029         loadPostFromTumblr();
0030     }) << make_job([=]() {
0031         loadImageFromTumblr();
0032     });
0033     stream() << s;
0034 }
0035 //@@snippet_end
0036 
0037 ViewController::~ViewController()
0038 {
0039     ThreadWeaver::Queue::instance()->finish();
0040 }
0041 
0042 //@@snippet_begin(hellointernet-loadresource)
0043 void ViewController::loadPlaceholderFromResource()
0044 {
0045     QThread::msleep(500);
0046     showResourceImage("IMG_20140813_004131.png");
0047     Q_EMIT setStatus(tr("Downloading post..."));
0048 }
0049 //@@snippet_end
0050 
0051 //@@snippet_begin(hellointernet-loadpost)
0052 void ViewController::loadPostFromTumblr()
0053 {
0054     const QUrl url(m_apiPostUrl);
0055 
0056     auto const data = download(url);
0057     Q_EMIT setStatus(tr("Post downloaded..."));
0058 
0059     QDomDocument doc;
0060     if (!doc.setContent(data)) {
0061         error(tr("Post format not recognized!"));
0062     }
0063 
0064     auto textOfFirst = [&doc](const char *name) {
0065         auto const s = QString::fromLatin1(name);
0066         auto elements = doc.elementsByTagName(s);
0067         if (elements.isEmpty()) {
0068             return QString();
0069         }
0070         return elements.at(0).toElement().text();
0071     };
0072 
0073     auto const caption = textOfFirst("photo-caption");
0074     if (caption.isEmpty()) {
0075         error(tr("Post does not contain a caption!"));
0076     }
0077     Q_EMIT setCaption(caption);
0078     auto const imageUrl = textOfFirst("photo-url");
0079     if (imageUrl.isEmpty()) {
0080         error(tr("Post does not contain an image!"));
0081     }
0082 
0083     m_fullPostUrl = attributeTextFor(doc, "post", "url-with-slug");
0084     if (m_fullPostUrl.isEmpty()) {
0085         error(tr("Response does not contain URL with slug!"));
0086     }
0087     m_imageUrl = QUrl(imageUrl);
0088     showResourceImage("IMG_20140813_004131-colors-cubed.png");
0089     Q_EMIT setStatus(tr("Downloading image..."));
0090     QThread::msleep(500);
0091 }
0092 //@@snippet_end
0093 
0094 void ViewController::loadImageFromTumblr()
0095 {
0096     auto const data = download(m_imageUrl);
0097     Q_EMIT setStatus(tr("Image downloaded..."));
0098     const QImage image = QImage::fromData(data);
0099     if (!image.isNull()) {
0100         Q_EMIT setImage(image);
0101         Q_EMIT setStatus(tr("Download complete (see %1).").arg(m_fullPostUrl));
0102     } else {
0103         error(tr("Image format error!"));
0104     }
0105 }
0106 
0107 QByteArray ViewController::download(const QUrl &url)
0108 {
0109     QNetworkAccessManager manager;
0110     QEventLoop loop;
0111     QObject::connect(&manager, SIGNAL(finished(QNetworkReply *)), &loop, SLOT(quit()));
0112     auto reply = manager.get(QNetworkRequest(url));
0113     loop.exec();
0114     if (reply->error() == QNetworkReply::NoError) {
0115         const QByteArray data = reply->readAll();
0116         return data;
0117     } else {
0118         error(tr("Unable to download data for \"%1\"!").arg(url.toString()));
0119         return QByteArray();
0120     }
0121 }
0122 
0123 //@@snippet_begin(hellointernet-error)
0124 void ViewController::error(const QString &message)
0125 {
0126     showResourceImage("IMG_20140813_004131-colors-cubed.png");
0127     Q_EMIT setCaption(tr("Error"));
0128     Q_EMIT setStatus(tr("%1").arg(message));
0129     throw ThreadWeaver::JobFailed(message);
0130 }
0131 //@@snippet_end
0132 
0133 void ViewController::showResourceImage(const char *file)
0134 {
0135     const QString path(QStringLiteral("://resources/%1").arg(QString::fromLatin1(file)));
0136     Q_ASSERT(QFile::exists(path));
0137     const QImage i(path);
0138     Q_ASSERT(!i.isNull());
0139     Q_EMIT setImage(i);
0140 }
0141 
0142 QString ViewController::attributeTextFor(const QDomDocument &doc, const char *tag, const char *attribute)
0143 {
0144     auto const tagString = QString::fromLatin1(tag);
0145     auto const attributeString = QString::fromLatin1(attribute);
0146     auto elements = doc.elementsByTagName(tagString);
0147     if (elements.isEmpty()) {
0148         return QString();
0149     }
0150     const QString content = elements.at(0).toElement().attribute(attributeString);
0151     return content;
0152 }
0153 
0154 #include "moc_ViewController.cpp"