File indexing completed on 2024-05-12 05:09:50

0001 /***************************************************************************
0002     Copyright (C) 2017 Robby Stephenson <robby@periapsis.org>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 #include "imagejob.h"
0026 #include "../tellico_debug.h"
0027 
0028 #include <KLocalizedString>
0029 
0030 #include <QTimer>
0031 #include <QFileInfo>
0032 #include <QBuffer>
0033 #include <QImageReader>
0034 
0035 namespace {
0036   static const int IMAGEJOB_TIMEOUT = 5; // seconds
0037 }
0038 
0039 using Tellico::ImageJob;
0040 
0041 ImageJob::ImageJob(const QUrl& url_, const QString& id_, bool quiet_) : KIO::Job()
0042     , m_url(url_), m_id(id_), m_linkOnly(false), m_quiet(quiet_) {
0043   QTimer::singleShot(0, this, &ImageJob::slotStart);
0044 }
0045 
0046 ImageJob::~ImageJob() {
0047 }
0048 
0049 QString ImageJob::errorString() const {
0050   // by default, KIO::Job returns an error string depending on the error code and
0051   // using errorText() as a url or file name. Instead, just set a full error text and use it
0052   return errorText();
0053 }
0054 
0055 const Tellico::Data::Image& ImageJob::image() const {
0056   return m_image;
0057 }
0058 
0059 void ImageJob::setLinkOnly(bool linkOnly_) {
0060   m_linkOnly = linkOnly_;
0061 }
0062 
0063 void ImageJob::setReferrer(const QUrl& referrer_) {
0064   m_referrer = referrer_;
0065 }
0066 
0067 void ImageJob::slotStart() {
0068   if(!m_url.isValid()) {
0069     setError(KIO::ERR_MALFORMED_URL);
0070     emitResult();
0071   } else if(m_url.isLocalFile()) {
0072     const QString fileName = m_url.toLocalFile();
0073     if(!QFileInfo(fileName).isReadable()) {
0074       setError(KIO::ERR_CANNOT_OPEN_FOR_READING);
0075       setErrorText(i18n("Tellico is unable to load the image - %1.", fileName));
0076     } else {
0077       m_image = Data::Image(fileName, m_id);
0078       if(m_image.isNull()) {
0079         setError(KIO::ERR_UNKNOWN);
0080         m_image = Data::Image::null;
0081       }
0082       if(m_linkOnly) {
0083         m_image.setLinkOnly(true);
0084         m_image.setID(m_url.url());
0085       }
0086     }
0087     emitResult();
0088   } else {
0089     KIO::JobFlags flags = KIO::DefaultFlags;
0090     if(m_quiet) {
0091       flags |= KIO::HideProgressInfo;
0092     }
0093     // non-local valid url
0094     // KIO::storedGet seems to handle Content-Encoding: gzip ok
0095     KIO::StoredTransferJob* getJob = KIO::storedGet(m_url, KIO::NoReload, flags);
0096     QObject::connect(getJob, &KJob::result, this, &ImageJob::getJobResult);
0097     if(!m_referrer.isEmpty()) {
0098       getJob->addMetaData(QStringLiteral("referrer"), m_referrer.url());
0099     }
0100     if(!addSubjob(getJob)) {
0101       myDebug() << "ImageJob:: error adding subjob";
0102       emitResult();
0103     }
0104     QTimer::singleShot(IMAGEJOB_TIMEOUT * 1000, this, &ImageJob::getJobTimeout);
0105   }
0106 }
0107 
0108 void ImageJob::getJobResult(KJob* job_) {
0109   const auto errorText = i18n("Tellico is unable to load the image - %1.", m_url.toDisplayString());
0110   KIO::StoredTransferJob* getJob = qobject_cast<KIO::StoredTransferJob*>(job_);
0111   if(!getJob || getJob->error()) {
0112     // error handling for subjob is handled by KCompositeJob
0113     setErrorText(errorText);
0114     emitResult();
0115     return;
0116   }
0117 
0118   // If we used the Image() c'tor that take a bytearray of data, I'm not sure how to
0119   // figure out the image format directly. Instead, write into a buffer and use QImageReader
0120   QByteArray data = getJob->data();
0121   QBuffer buffer(&data);
0122   buffer.open(QIODevice::ReadOnly);
0123   const auto format = QString::fromLatin1(QImageReader::imageFormat(&buffer));
0124   m_image = Data::Image(data, format, m_id);
0125   if(m_image.isNull()) {
0126     setErrorText(errorText);
0127     setError(KIO::ERR_UNKNOWN);
0128     m_image = Data::Image::null;
0129   } else {
0130     // if we can't write the input format, then change to one we can
0131     const auto outputFormat = Data::Image::outputFormat(m_image.format());
0132     if(m_image.format() != outputFormat) {
0133       m_image.setFormat(outputFormat);
0134       // recalculate m_id if necessary, since the format is included in the id
0135       if(m_id.isEmpty()) {
0136         m_image.calculateID();
0137       }
0138     }
0139     if(m_linkOnly) {
0140       m_image.setLinkOnly(true);
0141       m_image.setID(m_url.url());
0142     }
0143   }
0144   emitResult();
0145 }
0146 
0147 void ImageJob::getJobTimeout() {
0148   setError(KIO::ERR_SERVER_TIMEOUT);
0149   for(auto job : subjobs()) {
0150     job->kill(KIO::Job::EmitResult);
0151   }
0152 }