File indexing completed on 2024-04-28 05:11:30

0001 /*
0002   SPDX-FileCopyrightText: 2003 Cornelius Schumacher <schumacher@kde.org>
0003   SPDX-FileCopyrightText: 2005 Reinhold Kainhofer <reinhold@kainhofer.com>
0004   SPDX-FileCopyrightText: 2005 Rafal Rzepecki <divide@users.sourceforge.net>
0005   SPDX-FileCopyrightText: 2010 Bertjan Broeksema <broeksema@kde.org>
0006   SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
0007 
0008   SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
0009 
0010   NOTE: May, 2010. Extracted this code from
0011         kdepim/incidenceeditors/editorattachments.{h,cpp}
0012 */
0013 
0014 #include <config-enterprise.h>
0015 
0016 #include "attachmenticonview.h"
0017 
0018 #include <KIconLoader>
0019 #include <KUrlMimeData>
0020 #include <QDir>
0021 #include <QTemporaryFile>
0022 
0023 #include <KIconEngine>
0024 #include <QDrag>
0025 #include <QKeyEvent>
0026 #include <QMimeData>
0027 #include <QMimeDatabase>
0028 
0029 using namespace IncidenceEditorNG;
0030 
0031 AttachmentIconItem::AttachmentIconItem(const KCalendarCore::Attachment &att, QListWidget *parent)
0032     : QListWidgetItem(parent)
0033 {
0034     if (!att.isEmpty()) {
0035         mAttachment = att;
0036     } else {
0037         // for the enterprise, inline attachments are the default
0038 #if KDEPIM_ENTERPRISE_BUILD
0039         mAttachment = KCalendarCore::Attachment(QByteArray()); // use the non-uri constructor
0040         // as we want inline by default
0041 #else
0042         mAttachment = KCalendarCore::Attachment(QString());
0043 #endif
0044     }
0045     readAttachment();
0046     setFlags(flags() | Qt::ItemIsDragEnabled);
0047 }
0048 
0049 AttachmentIconItem::~AttachmentIconItem() = default;
0050 
0051 KCalendarCore::Attachment AttachmentIconItem::attachment() const
0052 {
0053     return mAttachment;
0054 }
0055 
0056 const QString AttachmentIconItem::uri() const
0057 {
0058     return mAttachment.uri();
0059 }
0060 
0061 const QString AttachmentIconItem::savedUri() const
0062 {
0063     return mSaveUri;
0064 }
0065 
0066 void AttachmentIconItem::setUri(const QString &uri)
0067 {
0068     mSaveUri = uri;
0069     mAttachment.setUri(mSaveUri);
0070     readAttachment();
0071 }
0072 
0073 void AttachmentIconItem::setData(const QByteArray &data)
0074 {
0075     mAttachment.setDecodedData(data);
0076     readAttachment();
0077 }
0078 
0079 const QString AttachmentIconItem::mimeType() const
0080 {
0081     return mAttachment.mimeType();
0082 }
0083 
0084 void AttachmentIconItem::setMimeType(const QString &mime)
0085 {
0086     mAttachment.setMimeType(mime);
0087     readAttachment();
0088 }
0089 
0090 const QString AttachmentIconItem::label() const
0091 {
0092     return mAttachment.label();
0093 }
0094 
0095 void AttachmentIconItem::setLabel(const QString &description)
0096 {
0097     if (mAttachment.label() == description) {
0098         return;
0099     }
0100     mAttachment.setLabel(description);
0101     readAttachment();
0102 }
0103 
0104 bool AttachmentIconItem::isBinary() const
0105 {
0106     return mAttachment.isBinary();
0107 }
0108 
0109 QPixmap AttachmentIconItem::icon() const
0110 {
0111     QMimeDatabase db;
0112     return icon(db.mimeTypeForName(mAttachment.mimeType()), mAttachment.uri(), mAttachment.isBinary());
0113 }
0114 
0115 QPixmap AttachmentIconItem::icon(const QMimeType &mimeType, const QString &uri, bool binary)
0116 {
0117     const QString iconStr = mimeType.iconName();
0118     QStringList overlays;
0119     if (!uri.isEmpty() && !binary) {
0120         overlays << QStringLiteral("emblem-link");
0121     }
0122     return QIcon(new KIconEngine(iconStr, KIconLoader::global(), overlays)).pixmap(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium);
0123 }
0124 
0125 void AttachmentIconItem::readAttachment()
0126 {
0127     setText(mAttachment.label());
0128     setFlags(flags() | Qt::ItemIsEditable);
0129 
0130     QMimeDatabase db;
0131     if (mAttachment.mimeType().isEmpty() || !(db.mimeTypeForName(mAttachment.mimeType()).isValid())) {
0132         QMimeType mimeType;
0133         if (mAttachment.isUri()) {
0134             mimeType = db.mimeTypeForUrl(QUrl(mAttachment.uri()));
0135         } else {
0136             mimeType = db.mimeTypeForData(mAttachment.decodedData());
0137         }
0138         mAttachment.setMimeType(mimeType.name());
0139     }
0140 
0141     setIcon(icon());
0142 }
0143 
0144 AttachmentIconView::AttachmentIconView(QWidget *parent)
0145     : QListWidget(parent)
0146 {
0147     setMovement(Static);
0148     setAcceptDrops(true);
0149     setSelectionMode(ExtendedSelection);
0150     setSelectionRectVisible(false);
0151     setIconSize(QSize(KIconLoader::SizeLarge, KIconLoader::SizeLarge));
0152     setFlow(LeftToRight);
0153     setWrapping(true);
0154 #ifndef QT_NO_DRAGANDDROP
0155     setDragDropMode(DragDrop);
0156     setDragEnabled(true);
0157 #endif
0158     setEditTriggers(EditKeyPressed);
0159     setContextMenuPolicy(Qt::CustomContextMenu);
0160 }
0161 
0162 QUrl AttachmentIconItem::tempFileForAttachment()
0163 {
0164     if (mTempFile.isValid()) {
0165         return mTempFile;
0166     }
0167     QTemporaryFile *file = nullptr;
0168 
0169     QMimeDatabase db;
0170     QStringList patterns = db.mimeTypeForName(mAttachment.mimeType()).globPatterns();
0171 
0172     if (!patterns.empty()) {
0173         file = new QTemporaryFile(QDir::tempPath() + QLatin1StringView("/attachementview_XXXXX") + patterns.first().remove(QLatin1Char('*')));
0174     } else {
0175         file = new QTemporaryFile();
0176     }
0177     file->setParent(listWidget());
0178 
0179     file->setAutoRemove(true);
0180     file->open();
0181     // read-only not to give the idea that it could be written to
0182     file->setPermissions(QFile::ReadUser);
0183     file->write(QByteArray::fromBase64(mAttachment.data()));
0184     mTempFile = QUrl::fromLocalFile(file->fileName());
0185     file->close();
0186     return mTempFile;
0187 }
0188 
0189 QMimeData *AttachmentIconView::mimeData(const QList<QListWidgetItem *> &items) const // clazy:exclude=function-args-by-ref
0190 {
0191     // create a list of the URL:s that we want to drag
0192     QList<QUrl> urls;
0193     QStringList labels;
0194     for (QListWidgetItem *it : items) {
0195         if (it->isSelected()) {
0196             auto item = static_cast<AttachmentIconItem *>(it);
0197             if (item->isBinary()) {
0198                 urls.append(item->tempFileForAttachment());
0199             } else {
0200                 urls.append(QUrl(item->uri()));
0201             }
0202             labels.append(QString::fromLatin1(QUrl::toPercentEncoding(item->label())));
0203         }
0204     }
0205     if (selectionMode() == NoSelection) {
0206         auto item = static_cast<AttachmentIconItem *>(currentItem());
0207         if (item) {
0208             urls.append(QUrl(item->uri()));
0209             labels.append(QString::fromLatin1(QUrl::toPercentEncoding(item->label())));
0210         }
0211     }
0212 
0213     QMap<QString, QString> metadata;
0214     metadata[QStringLiteral("labels")] = labels.join(QLatin1Char(':'));
0215 
0216     auto mimeData = new QMimeData;
0217     mimeData->setUrls(urls);
0218     KUrlMimeData::setMetaData(metadata, mimeData);
0219     return mimeData;
0220 }
0221 
0222 QMimeData *AttachmentIconView::mimeData() const
0223 {
0224     return mimeData(selectedItems());
0225 }
0226 
0227 void AttachmentIconView::startDrag(Qt::DropActions supportedActions)
0228 {
0229     Q_UNUSED(supportedActions)
0230 #ifndef QT_NO_DRAGANDDROP
0231     QPixmap pixmap;
0232     if (selectedItems().size() > 1) {
0233         pixmap = KIconLoader::global()->loadIcon(QStringLiteral("mail-attachment"), KIconLoader::Desktop);
0234     }
0235     if (pixmap.isNull()) {
0236         pixmap = static_cast<AttachmentIconItem *>(currentItem())->icon();
0237     }
0238 
0239     const QPoint hotspot(pixmap.width() / 2, pixmap.height() / 2);
0240 
0241     auto drag = new QDrag(this);
0242     drag->setMimeData(mimeData());
0243 
0244     drag->setPixmap(pixmap);
0245     drag->setHotSpot(hotspot);
0246     drag->exec(Qt::CopyAction);
0247 #endif
0248 }
0249 
0250 void AttachmentIconView::keyPressEvent(QKeyEvent *event)
0251 {
0252     if ((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) && currentItem() && state() != EditingState) {
0253         Q_EMIT itemDoubleClicked(currentItem()); // ugly, but itemActivated() also includes single click
0254         return;
0255     }
0256     QListWidget::keyPressEvent(event);
0257 }
0258 
0259 #include "moc_attachmenticonview.cpp"