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 }