File indexing completed on 2024-05-05 08:25:41
0001 // vim: set tabstop=4 shiftwidth=4 expandtab 0002 /* 0003 Gwenview - A simple image viewer for KDE 0004 Copyright 2006 Aurelien Gateau <agateau@kde.org> 0005 0006 This program is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU General Public License 0008 as published by the Free Software Foundation; either version 2 0009 of the License, or (at your option) any later version. 0010 0011 This program is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 GNU General Public License for more details. 0015 0016 You should have received a copy of the GNU General Public License 0017 along with this program; if not, write to the Free Software 0018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 0019 0020 */ 0021 #include "mimetypeutils.h" 0022 #include "mimetypeutils_p.h" 0023 0024 // Qt 0025 #include <QFileInfo> 0026 #include <QImageReader> 0027 #include <QMimeData> 0028 #include <QMimeDatabase> 0029 #include <QUrl> 0030 0031 // KF 0032 #include <KFileItem> 0033 #include <KIO/TransferJob> 0034 0035 // Local 0036 #include "gwenview_lib_debug.h" 0037 #include <archiveutils.h> 0038 #include <gvdebug.h> 0039 #include <lib/document/documentfactory.h> 0040 0041 namespace Gwenview 0042 { 0043 namespace MimeTypeUtils 0044 { 0045 static inline QString resolveAlias(const QString &name) 0046 { 0047 QMimeDatabase db; 0048 return db.mimeTypeForName(name).name(); 0049 } 0050 0051 static void resolveAliasInList(QStringList *list) 0052 { 0053 QStringList::Iterator it = list->begin(), end = list->end(); 0054 for (; it != end; ++it) { 0055 *it = resolveAlias(*it); 0056 } 0057 } 0058 0059 static inline QStringList rawMimeTypes() 0060 { 0061 // need to invent more intelligent way to whitelist raws 0062 return {QStringLiteral("image/x-nikon-nef"), 0063 QStringLiteral("image/x-nikon-nrw"), 0064 QStringLiteral("image/x-canon-cr2"), 0065 QStringLiteral("image/x-canon-crw"), 0066 QStringLiteral("image/x-pentax-pef"), 0067 QStringLiteral("image/x-adobe-dng"), 0068 QStringLiteral("image/x-sony-arw"), 0069 QStringLiteral("image/x-minolta-mrw"), 0070 QStringLiteral("image/x-panasonic-raw"), 0071 QStringLiteral("image/x-panasonic-raw2"), 0072 QStringLiteral("image/x-panasonic-rw"), 0073 QStringLiteral("image/x-panasonic-rw2"), 0074 QStringLiteral("image/x-samsung-srw"), 0075 QStringLiteral("image/x-olympus-orf"), 0076 QStringLiteral("image/x-fuji-raf"), 0077 QStringLiteral("image/x-kodak-dcr"), 0078 QStringLiteral("image/x-sigma-x3f")}; 0079 } 0080 0081 const QStringList &rasterImageMimeTypes() 0082 { 0083 static QStringList list; 0084 if (list.isEmpty()) { 0085 const auto supported = QImageReader::supportedMimeTypes(); 0086 for (const auto &mime : supported) { 0087 const auto resolved = resolveAlias(QString::fromUtf8(mime)); 0088 if (resolved.isEmpty()) { 0089 qCWarning(GWENVIEW_LIB_LOG) << "Unresolved mime type " << mime; 0090 } else { 0091 list << resolved; 0092 } 0093 } 0094 // We don't want svg images to be considered as raster images 0095 const QStringList svgImageMimeTypesList = svgImageMimeTypes(); 0096 for (const QString &mimeType : svgImageMimeTypesList) { 0097 list.removeOne(mimeType); 0098 } 0099 for (const QString &rawMimetype : rawMimeTypes()) { 0100 const auto resolved = resolveAlias(rawMimetype); 0101 if (resolved.isEmpty()) { 0102 qCWarning(GWENVIEW_LIB_LOG) << "Unresolved raw mime type " << rawMimetype; 0103 } else { 0104 list << resolved; 0105 } 0106 } 0107 } 0108 return list; 0109 } 0110 0111 const QStringList &svgImageMimeTypes() 0112 { 0113 static QStringList list; 0114 if (list.isEmpty()) { 0115 list << QStringLiteral("image/svg+xml") << QStringLiteral("image/svg+xml-compressed"); 0116 resolveAliasInList(&list); 0117 } 0118 return list; 0119 } 0120 0121 const QStringList &imageMimeTypes() 0122 { 0123 static QStringList list; 0124 if (list.isEmpty()) { 0125 list = rasterImageMimeTypes(); 0126 list += svgImageMimeTypes(); 0127 } 0128 0129 return list; 0130 } 0131 0132 QString urlMimeType(const QUrl &url) 0133 { 0134 if (url.isEmpty()) { 0135 return QStringLiteral("unknown"); 0136 } 0137 0138 QMimeDatabase db; 0139 return db.mimeTypeForUrl(url).name(); 0140 } 0141 0142 Kind mimeTypeKind(const QString &mimeType) 0143 { 0144 if (rasterImageMimeTypes().contains(mimeType)) { 0145 return KIND_RASTER_IMAGE; 0146 } 0147 if (svgImageMimeTypes().contains(mimeType)) { 0148 return KIND_SVG_IMAGE; 0149 } 0150 if (mimeType.startsWith(QLatin1String("video/"))) { 0151 return KIND_VIDEO; 0152 } 0153 if (mimeType.startsWith(QLatin1String("inode/directory"))) { 0154 return KIND_DIR; 0155 } 0156 if (!ArchiveUtils::protocolForMimeType(mimeType).isEmpty()) { 0157 return KIND_ARCHIVE; 0158 } 0159 0160 return KIND_FILE; 0161 } 0162 0163 Kind fileItemKind(const KFileItem &item) 0164 { 0165 GV_RETURN_VALUE_IF_FAIL(!item.isNull(), KIND_UNKNOWN); 0166 return mimeTypeKind(item.mimetype()); 0167 } 0168 0169 Kind urlKind(const QUrl &url) 0170 { 0171 return mimeTypeKind(urlMimeType(url)); 0172 } 0173 0174 QMimeData *selectionMimeData(const KFileItemList &selectedFiles, MimeTarget mimeTarget) 0175 { 0176 auto mimeData = new QMimeData; 0177 0178 if (selectedFiles.count() == 1) { 0179 // When a single file is selected, there are a couple of cases: 0180 // - Pasting unmodified images: Set both image data and URL 0181 // (since some apps only support either image data or URL) 0182 // - Dragging unmodified images: Only set URL 0183 // (otherwise dragging to Chromium or the desktop fails, see https://phabricator.kde.org/D13249#300894) 0184 // - Dragging or pasting modified images: Only set image data 0185 // (otherwise some apps prefer the URL, which would only contain the unmodified image) 0186 0187 const QUrl url = selectedFiles.first().url(); 0188 const MimeTypeUtils::Kind mimeKind = MimeTypeUtils::urlKind(url); 0189 bool documentIsModified = false; 0190 0191 if (mimeKind == MimeTypeUtils::KIND_RASTER_IMAGE || mimeKind == MimeTypeUtils::KIND_SVG_IMAGE) { 0192 const Document::Ptr doc = DocumentFactory::instance()->load(url); 0193 doc->waitUntilLoaded(); 0194 documentIsModified = doc->isModified(); 0195 0196 if (mimeTarget == ClipboardTarget || (mimeTarget == DropTarget && documentIsModified)) { 0197 QString suggestedFileName; 0198 0199 if (mimeKind == MimeTypeUtils::KIND_RASTER_IMAGE) { 0200 mimeData->setImageData(doc->image()); 0201 0202 // Set the filename extension to PNG, as it is the first 0203 // entry in the combobox when pasting to Dolphin 0204 suggestedFileName = QFileInfo(url.fileName()).completeBaseName() + QStringLiteral(".png"); 0205 } else { 0206 mimeData->setData(MimeTypeUtils::urlMimeType(url), doc->rawData()); 0207 suggestedFileName = url.fileName(); 0208 } 0209 0210 mimeData->setData(QStringLiteral("application/x-kde-suggestedfilename"), QFile::encodeName(suggestedFileName)); 0211 } 0212 } 0213 0214 if (!documentIsModified) { 0215 mimeData->setUrls({url}); 0216 } 0217 } else { 0218 mimeData->setUrls(selectedFiles.urlList()); 0219 } 0220 0221 return mimeData; 0222 } 0223 0224 DataAccumulator::DataAccumulator(KIO::TransferJob *job) 0225 : QObject() 0226 , mFinished(false) 0227 { 0228 connect(job, &KIO::TransferJob::data, this, &DataAccumulator::slotDataReceived); 0229 connect(job, &KJob::result, this, &DataAccumulator::slotFinished); 0230 } 0231 0232 void DataAccumulator::slotDataReceived(KIO::Job *, const QByteArray &data) 0233 { 0234 mData += data; 0235 } 0236 0237 void DataAccumulator::slotFinished() 0238 { 0239 mFinished = true; 0240 } 0241 0242 } // namespace MimeTypeUtils 0243 } // namespace Gwenview 0244 0245 #include "moc_mimetypeutils_p.cpp"