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

0001 /*
0002   SPDX-FileCopyrightText: 2010 Bertjan Broeksema <broeksema@kde.org>
0003   SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
0004 
0005   SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "incidenceattachment.h"
0009 #include "attachmenteditdialog.h"
0010 #include "attachmenticonview.h"
0011 #include "ui_dialogdesktop.h"
0012 
0013 #include <CalendarSupport/UriHandler>
0014 
0015 #include <KContacts/VCardDrag>
0016 
0017 #include <KMime/Message>
0018 
0019 #include <KActionCollection>
0020 #include <KIO/FileCopyJob>
0021 #include <KIO/JobUiDelegate>
0022 #include <KIO/JobUiDelegateFactory>
0023 #include <KIO/OpenUrlJob>
0024 #include <KIO/StoredTransferJob>
0025 #include <KJobWidgets>
0026 #include <KLocalizedString>
0027 #include <KMessageBox>
0028 #include <KProtocolManager>
0029 #include <QAction>
0030 #include <QFileDialog>
0031 #include <QIcon>
0032 #include <QMenu>
0033 #include <QUrl>
0034 
0035 #include <QClipboard>
0036 #include <QMimeData>
0037 #include <QMimeDatabase>
0038 #include <QMimeType>
0039 
0040 using namespace IncidenceEditorNG;
0041 
0042 IncidenceAttachment::IncidenceAttachment(Ui::EventOrTodoDesktop *ui)
0043     : IncidenceEditor(nullptr)
0044     , mUi(ui)
0045     , mPopupMenu(new QMenu)
0046 {
0047     setupActions();
0048     setupAttachmentIconView();
0049     setObjectName(QLatin1StringView("IncidenceAttachment"));
0050 
0051     connect(mUi->mAddButton, &QPushButton::clicked, this, &IncidenceAttachment::addAttachment);
0052     connect(mUi->mRemoveButton, &QPushButton::clicked, this, &IncidenceAttachment::removeSelectedAttachments);
0053 }
0054 
0055 IncidenceAttachment::~IncidenceAttachment()
0056 {
0057     delete mPopupMenu;
0058 }
0059 
0060 void IncidenceAttachment::load(const KCalendarCore::Incidence::Ptr &incidence)
0061 {
0062     mLoadedIncidence = incidence;
0063     mAttachmentView->clear();
0064 
0065     KCalendarCore::Attachment::List attachments = incidence->attachments();
0066     for (KCalendarCore::Attachment::List::ConstIterator it = attachments.constBegin(), end = attachments.constEnd(); it != end; ++it) {
0067         new AttachmentIconItem((*it), mAttachmentView);
0068     }
0069 
0070     mWasDirty = false;
0071 }
0072 
0073 void IncidenceAttachment::save(const KCalendarCore::Incidence::Ptr &incidence)
0074 {
0075     incidence->clearAttachments();
0076 
0077     for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
0078         QListWidgetItem *item = mAttachmentView->item(itemIndex);
0079         auto attitem = dynamic_cast<AttachmentIconItem *>(item);
0080         Q_ASSERT(item);
0081         incidence->addAttachment(attitem->attachment());
0082     }
0083 }
0084 
0085 bool IncidenceAttachment::isDirty() const
0086 {
0087     if (mLoadedIncidence) {
0088         if (mAttachmentView->count() != mLoadedIncidence->attachments().count()) {
0089             return true;
0090         }
0091 
0092         KCalendarCore::Attachment::List origAttachments = mLoadedIncidence->attachments();
0093         for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
0094             QListWidgetItem *item = mAttachmentView->item(itemIndex);
0095             Q_ASSERT(dynamic_cast<AttachmentIconItem *>(item));
0096 
0097             const KCalendarCore::Attachment listAttachment = static_cast<AttachmentIconItem *>(item)->attachment();
0098 
0099             for (int i = 0; i < origAttachments.count(); ++i) {
0100                 const KCalendarCore::Attachment attachment = origAttachments.at(i);
0101 
0102                 if (attachment == listAttachment) {
0103                     origAttachments.remove(i);
0104                     break;
0105                 }
0106             }
0107         }
0108         // All attachments are removed from the list, meaning, the items in mAttachmentView
0109         // are equal to the attachments set on mLoadedIncidence.
0110         return !origAttachments.isEmpty();
0111     } else {
0112         // No incidence loaded, so if the user added attachments we're dirty.
0113         return mAttachmentView->count() != 0;
0114     }
0115 }
0116 
0117 int IncidenceAttachment::attachmentCount() const
0118 {
0119     return mAttachmentView->count();
0120 }
0121 
0122 /// Private slots
0123 
0124 void IncidenceAttachment::addAttachment()
0125 {
0126     QPointer<QObject> that(this);
0127     auto item = new AttachmentIconItem(KCalendarCore::Attachment(), mAttachmentView);
0128 
0129     QPointer<AttachmentEditDialog> dialog(new AttachmentEditDialog(item, mAttachmentView));
0130     dialog->setWindowTitle(i18nc("@title", "Add Attachment"));
0131     auto dialogResult = dialog->exec();
0132     if (!that) {
0133         return;
0134     }
0135 
0136     if (dialogResult == QDialog::Rejected) {
0137         delete item;
0138     } else {
0139         Q_EMIT attachmentCountChanged(mAttachmentView->count());
0140     }
0141     delete dialog;
0142 
0143     checkDirtyStatus();
0144 }
0145 
0146 void IncidenceAttachment::copyToClipboard()
0147 {
0148 #ifndef QT_NO_CLIPBOARD
0149     QApplication::clipboard()->setMimeData(mAttachmentView->mimeData(), QClipboard::Clipboard);
0150 #endif
0151 }
0152 
0153 void IncidenceAttachment::openURL(const QUrl &url)
0154 {
0155     QString uri = url.url();
0156     CalendarSupport::UriHandler::process(uri);
0157 }
0158 
0159 void IncidenceAttachment::pasteFromClipboard()
0160 {
0161 #ifndef QT_NO_CLIPBOARD
0162     handlePasteOrDrop(QApplication::clipboard()->mimeData());
0163 #endif
0164 }
0165 
0166 void IncidenceAttachment::removeSelectedAttachments()
0167 {
0168     QList<QListWidgetItem *> selected;
0169     QStringList labels;
0170     selected.reserve(mAttachmentView->count());
0171     labels.reserve(mAttachmentView->count());
0172 
0173     for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
0174         QListWidgetItem *it = mAttachmentView->item(itemIndex);
0175         if (it->isSelected()) {
0176             auto attitem = static_cast<AttachmentIconItem *>(it);
0177             if (attitem) {
0178                 const KCalendarCore::Attachment att = attitem->attachment();
0179                 labels << att.label();
0180                 selected << it;
0181             }
0182         }
0183     }
0184 
0185     if (selected.isEmpty()) {
0186         return;
0187     }
0188 
0189     QString labelsStr = labels.join(QLatin1StringView("<nl/>"));
0190 
0191     if (KMessageBox::questionTwoActions(nullptr,
0192                                         xi18nc("@info", "Do you really want to remove these attachments?<nl/>%1", labelsStr),
0193                                         i18nc("@title:window", "Remove Attachments?"),
0194                                         KStandardGuiItem::remove(),
0195                                         KStandardGuiItem::cancel(),
0196                                         QStringLiteral("calendarRemoveAttachments"))
0197         != KMessageBox::ButtonCode::PrimaryAction) {
0198         return;
0199     }
0200 
0201     for (QList<QListWidgetItem *>::iterator it(selected.begin()), end(selected.end()); it != end; ++it) {
0202         int row = mAttachmentView->row(*it);
0203         QListWidgetItem *next = mAttachmentView->item(++row);
0204         QListWidgetItem *prev = mAttachmentView->item(--row);
0205         if (next) {
0206             next->setSelected(true);
0207         } else if (prev) {
0208             prev->setSelected(true);
0209         }
0210         delete *it;
0211     }
0212 
0213     mAttachmentView->update();
0214     Q_EMIT attachmentCountChanged(mAttachmentView->count());
0215     checkDirtyStatus();
0216 }
0217 
0218 void IncidenceAttachment::saveAttachment(QListWidgetItem *item)
0219 {
0220     Q_ASSERT(item);
0221     Q_ASSERT(dynamic_cast<AttachmentIconItem *>(item));
0222 
0223     auto attitem = static_cast<AttachmentIconItem *>(item);
0224     if (attitem->attachment().isEmpty()) {
0225         return;
0226     }
0227 
0228     KCalendarCore::Attachment att = attitem->attachment();
0229 
0230     // get the saveas file name
0231     const QString saveAsFile = QFileDialog::getSaveFileName(nullptr, i18nc("@title", "Save Attachment"), att.label());
0232 
0233     if (saveAsFile.isEmpty()) {
0234         return;
0235     }
0236 
0237     QUrl sourceUrl;
0238     if (att.isUri()) {
0239         sourceUrl = QUrl(att.uri());
0240     } else {
0241         sourceUrl = attitem->tempFileForAttachment();
0242     }
0243     // save the attachment url
0244     auto job = KIO::file_copy(sourceUrl, QUrl::fromLocalFile(saveAsFile));
0245     if (!job->exec() && job->error()) {
0246         KMessageBox::error(nullptr, job->errorString());
0247     }
0248 }
0249 
0250 void IncidenceAttachment::saveSelectedAttachments()
0251 {
0252     for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
0253         QListWidgetItem *item = mAttachmentView->item(itemIndex);
0254         if (item->isSelected()) {
0255             saveAttachment(item);
0256         }
0257     }
0258 }
0259 
0260 void IncidenceAttachment::showAttachment(QListWidgetItem *item)
0261 {
0262     Q_ASSERT(item);
0263     Q_ASSERT(dynamic_cast<AttachmentIconItem *>(item));
0264     auto attitem = static_cast<AttachmentIconItem *>(item);
0265     if (attitem->attachment().isEmpty()) {
0266         return;
0267     }
0268 
0269     const KCalendarCore::Attachment att = attitem->attachment();
0270     if (att.isUri()) {
0271         openURL(QUrl(att.uri()));
0272     } else {
0273         auto job = new KIO::OpenUrlJob(attitem->tempFileForAttachment(), att.mimeType());
0274         job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, mAttachmentView));
0275         job->setDeleteTemporaryFile(true);
0276         job->start();
0277     }
0278 }
0279 
0280 void IncidenceAttachment::showContextMenu(const QPoint &pos) // clazy:exclude=function-args-by-value
0281 {
0282     const bool enable = mAttachmentView->itemAt(pos) != nullptr;
0283 
0284     int numSelected = 0;
0285     for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
0286         QListWidgetItem *item = mAttachmentView->item(itemIndex);
0287         if (item->isSelected()) {
0288             numSelected++;
0289         }
0290     }
0291 
0292     mOpenAction->setEnabled(enable);
0293     // TODO: support saving multiple attachments into a directory
0294     mSaveAsAction->setEnabled(enable && numSelected == 1);
0295 #ifndef QT_NO_CLIPBOARD
0296     mCopyAction->setEnabled(enable && numSelected == 1);
0297     mCutAction->setEnabled(enable && numSelected == 1);
0298 #endif
0299     mDeleteAction->setEnabled(enable);
0300     mEditAction->setEnabled(enable);
0301     mPopupMenu->exec(mAttachmentView->mapToGlobal(pos));
0302 }
0303 
0304 void IncidenceAttachment::showSelectedAttachments()
0305 {
0306     for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
0307         QListWidgetItem *item = mAttachmentView->item(itemIndex);
0308         if (item->isSelected()) {
0309             showAttachment(item);
0310         }
0311     }
0312 }
0313 
0314 void IncidenceAttachment::cutToClipboard()
0315 {
0316 #ifndef QT_NO_CLIPBOARD
0317     copyToClipboard();
0318     removeSelectedAttachments();
0319 #endif
0320 }
0321 
0322 void IncidenceAttachment::editSelectedAttachments()
0323 {
0324     for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
0325         QListWidgetItem *item = mAttachmentView->item(itemIndex);
0326         if (item->isSelected()) {
0327             Q_ASSERT(dynamic_cast<AttachmentIconItem *>(item));
0328 
0329             auto attitem = static_cast<AttachmentIconItem *>(item);
0330             if (attitem->attachment().isEmpty()) {
0331                 return;
0332             }
0333 
0334             QPointer<AttachmentEditDialog> dialog(new AttachmentEditDialog(attitem, mAttachmentView, false));
0335             dialog->setModal(false);
0336             dialog->setAttribute(Qt::WA_DeleteOnClose, true);
0337             dialog->show();
0338         }
0339     }
0340 }
0341 
0342 void IncidenceAttachment::slotItemRenamed(QListWidgetItem *item)
0343 {
0344     Q_ASSERT(item);
0345     Q_ASSERT(dynamic_cast<AttachmentIconItem *>(item));
0346     static_cast<AttachmentIconItem *>(item)->setLabel(item->text());
0347     checkDirtyStatus();
0348 }
0349 
0350 void IncidenceAttachment::slotSelectionChanged()
0351 {
0352     bool selected = false;
0353     for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
0354         QListWidgetItem *item = mAttachmentView->item(itemIndex);
0355         if (item->isSelected()) {
0356             selected = true;
0357             break;
0358         }
0359     }
0360     mUi->mRemoveButton->setEnabled(selected);
0361 }
0362 
0363 /// Private functions
0364 
0365 void IncidenceAttachment::handlePasteOrDrop(const QMimeData *mimeData)
0366 {
0367     if (!mimeData) {
0368         return;
0369     }
0370     QList<QUrl> urls;
0371     bool probablyWeHaveUris = false;
0372     QStringList labels;
0373 
0374     if (KContacts::VCardDrag::canDecode(mimeData)) {
0375         KContacts::Addressee::List addressees;
0376         KContacts::VCardDrag::fromMimeData(mimeData, addressees);
0377         urls.reserve(addressees.count());
0378         labels.reserve(addressees.count());
0379         const KContacts::Addressee::List::ConstIterator end(addressees.constEnd());
0380         for (KContacts::Addressee::List::ConstIterator it = addressees.constBegin(); it != end; ++it) {
0381             urls.append(QUrl(QStringLiteral("uid:") + (*it).uid()));
0382             // there is some weirdness about realName(), hence fromUtf8
0383             labels.append(QString::fromUtf8((*it).realName().toLatin1()));
0384         }
0385         probablyWeHaveUris = true;
0386     } else if (mimeData->hasUrls()) {
0387         QMap<QString, QString> metadata;
0388 
0389         // QT5
0390         // urls = QList<QUrl>::fromMimeData( mimeData, &metadata );
0391         probablyWeHaveUris = true;
0392         labels = metadata[QStringLiteral("labels")].split(QLatin1Char(':'), Qt::SkipEmptyParts);
0393         const QStringList::Iterator end(labels.end());
0394         for (QStringList::Iterator it = labels.begin(); it != end; ++it) {
0395             *it = QUrl::fromPercentEncoding((*it).toLatin1());
0396         }
0397     } else if (mimeData->hasText()) {
0398         const QString text = mimeData->text();
0399         QStringList lst = text.split(QLatin1Char('\n'), Qt::SkipEmptyParts);
0400         urls.reserve(lst.count());
0401         QStringList::ConstIterator end(lst.constEnd());
0402         for (QStringList::ConstIterator it = lst.constBegin(); it != end; ++it) {
0403             urls.append(QUrl(*it));
0404         }
0405         probablyWeHaveUris = true;
0406     }
0407     QMenu menu;
0408     QAction *linkAction = nullptr;
0409     QAction *cancelAction = nullptr;
0410     if (probablyWeHaveUris) {
0411         linkAction = menu.addAction(QIcon::fromTheme(QStringLiteral("insert-link")), i18nc("@action:inmenu", "&Link here"));
0412         // we need to check if we can reasonably expect to copy the objects
0413         bool weCanCopy = true;
0414         QList<QUrl>::ConstIterator end(urls.constEnd());
0415         for (QList<QUrl>::ConstIterator it = urls.constBegin(); it != end; ++it) {
0416             if (!(weCanCopy = KProtocolManager::supportsReading(*it))) {
0417                 break; // either we can copy them all, or no copying at all
0418             }
0419         }
0420         if (weCanCopy) {
0421             menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18nc("@action:inmenu", "&Copy here"));
0422         }
0423     } else {
0424         menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18nc("@action:inmenu", "&Copy here"));
0425     }
0426 
0427     menu.addSeparator();
0428     cancelAction = menu.addAction(QIcon::fromTheme(QStringLiteral("process-stop")), i18nc("@action:inmenu", "C&ancel"));
0429 
0430     QByteArray data;
0431     QString mimeType;
0432     QString label;
0433 
0434     if (!mimeData->formats().isEmpty() && !probablyWeHaveUris) {
0435         mimeType = mimeData->formats().first();
0436         data = mimeData->data(mimeType);
0437         QMimeDatabase db;
0438         QMimeType mime = db.mimeTypeForName(mimeType);
0439         if (mime.isValid()) {
0440             label = mime.comment();
0441         }
0442     }
0443 
0444     QAction *ret = menu.exec(QCursor::pos());
0445     if (linkAction == ret) {
0446         QStringList::ConstIterator jt = labels.constBegin();
0447         const QList<QUrl>::ConstIterator jtEnd = urls.constEnd();
0448         for (QList<QUrl>::ConstIterator it = urls.constBegin(); it != jtEnd; ++it) {
0449             addUriAttachment((*it).url(), QString(), (jt == labels.constEnd() ? QString() : *(jt++)), true);
0450         }
0451     } else if (cancelAction != ret) {
0452         if (probablyWeHaveUris) {
0453             QList<QUrl>::ConstIterator end = urls.constEnd();
0454             for (QList<QUrl>::ConstIterator it = urls.constBegin(); it != end; ++it) {
0455                 KIO::Job *job = KIO::storedGet(*it);
0456                 // TODO verify if slot exist !
0457                 connect(job, &KIO::Job::result, this, &IncidenceAttachment::downloadComplete);
0458             }
0459         } else { // we take anything
0460             addDataAttachment(data, mimeType, label);
0461         }
0462     }
0463 }
0464 
0465 void IncidenceAttachment::downloadComplete(KJob *)
0466 {
0467     // TODO
0468 }
0469 
0470 void IncidenceAttachment::setupActions()
0471 {
0472     auto ac = new KActionCollection(this);
0473     //  ac->addAssociatedWidget( this );
0474 
0475     mOpenAction = new QAction(QIcon::fromTheme(QStringLiteral("document-open")), i18nc("@action:inmenu open the attachment in a viewer", "&Open"), this);
0476     connect(mOpenAction, &QAction::triggered, this, &IncidenceAttachment::showSelectedAttachments);
0477     ac->addAction(QStringLiteral("view"), mOpenAction);
0478     mPopupMenu->addAction(mOpenAction);
0479 
0480     mSaveAsAction =
0481         new QAction(QIcon::fromTheme(QStringLiteral("document-save-as")), i18nc("@action:inmenu save the attachment to a file", "Save As..."), this);
0482     connect(mSaveAsAction, &QAction::triggered, this, &IncidenceAttachment::saveSelectedAttachments);
0483     mPopupMenu->addAction(mSaveAsAction);
0484     mPopupMenu->addSeparator();
0485 
0486 #ifndef QT_NO_CLIPBOARD
0487     mCopyAction = KStandardAction::copy(this, &IncidenceAttachment::copyToClipboard, ac);
0488     mPopupMenu->addAction(mCopyAction);
0489 
0490     mCutAction = KStandardAction::cut(this, &IncidenceAttachment::cutToClipboard, ac);
0491     mPopupMenu->addAction(mCutAction);
0492 
0493     QAction *action = KStandardAction::paste(this, &IncidenceAttachment::pasteFromClipboard, ac);
0494     mPopupMenu->addAction(action);
0495     mPopupMenu->addSeparator();
0496 #endif
0497 
0498     mDeleteAction = new QAction(QIcon::fromTheme(QStringLiteral("list-remove")), i18nc("@action:inmenu remove the attachment", "&Remove"), this);
0499     connect(mDeleteAction, &QAction::triggered, this, &IncidenceAttachment::removeSelectedAttachments);
0500     ac->addAction(QStringLiteral("remove"), mDeleteAction);
0501     mDeleteAction->setShortcut(Qt::Key_Delete);
0502     mPopupMenu->addAction(mDeleteAction);
0503     mPopupMenu->addSeparator();
0504 
0505     mEditAction = new QAction(QIcon::fromTheme(QStringLiteral("document-properties")),
0506                               i18nc("@action:inmenu show a dialog used to edit the attachment", "&Properties..."),
0507                               this);
0508     connect(mEditAction, &QAction::triggered, this, &IncidenceAttachment::editSelectedAttachments);
0509     ac->addAction(QStringLiteral("edit"), mEditAction);
0510     mPopupMenu->addAction(mEditAction);
0511 }
0512 
0513 void IncidenceAttachment::setupAttachmentIconView()
0514 {
0515     mAttachmentView = new AttachmentIconView;
0516     mAttachmentView->setWhatsThis(i18nc("@info:whatsthis",
0517                                         "Displays items (files, mail, etc.) that "
0518                                         "have been associated with this event or to-do."));
0519 
0520     connect(mAttachmentView, &AttachmentIconView::itemDoubleClicked, this, &IncidenceAttachment::showAttachment);
0521     connect(mAttachmentView, &AttachmentIconView::itemChanged, this, &IncidenceAttachment::slotItemRenamed);
0522     connect(mAttachmentView, &AttachmentIconView::itemSelectionChanged, this, &IncidenceAttachment::slotSelectionChanged);
0523     connect(mAttachmentView, &AttachmentIconView::customContextMenuRequested, this, &IncidenceAttachment::showContextMenu);
0524 
0525     auto layout = new QGridLayout(mUi->mAttachmentViewPlaceHolder);
0526     layout->setContentsMargins(0, 0, 0, 0);
0527     layout->addWidget(mAttachmentView);
0528     QWidget::setTabOrder(mUi->mAddButton, mAttachmentView);
0529 }
0530 
0531 // void IncidenceAttachmentEditor::addAttachment( KCalendarCore::Attachment *attachment )
0532 // {
0533 //   new AttachmentIconItem( attachment, mAttachmentView );
0534 // }
0535 
0536 void IncidenceAttachment::addDataAttachment(const QByteArray &data, const QString &mimeType, const QString &label)
0537 {
0538     auto item = new AttachmentIconItem(KCalendarCore::Attachment(), mAttachmentView);
0539 
0540     QString nlabel = label;
0541     if (mimeType == QLatin1StringView("message/rfc822")) {
0542         // mail message. try to set the label from the mail Subject:
0543         KMime::Message msg;
0544         msg.setContent(data);
0545         msg.parse();
0546         nlabel = msg.subject()->asUnicodeString();
0547     }
0548 
0549     item->setData(data);
0550     item->setLabel(nlabel);
0551     if (mimeType.isEmpty()) {
0552         QMimeDatabase db;
0553         item->setMimeType(db.mimeTypeForData(data).name());
0554     } else {
0555         item->setMimeType(mimeType);
0556     }
0557 
0558     checkDirtyStatus();
0559 }
0560 
0561 void IncidenceAttachment::addUriAttachment(const QString &uri, const QString &mimeType, const QString &label, bool inLine)
0562 {
0563     if (!inLine) {
0564         auto item = new AttachmentIconItem(KCalendarCore::Attachment(), mAttachmentView);
0565         item->setUri(uri);
0566         item->setLabel(label);
0567         if (mimeType.isEmpty()) {
0568             if (uri.startsWith(QLatin1StringView("uid:"))) {
0569                 item->setMimeType(QStringLiteral("text/directory"));
0570             } else if (uri.startsWith(QLatin1StringView("kmail:"))) {
0571                 item->setMimeType(QStringLiteral("message/rfc822"));
0572             } else if (uri.startsWith(QLatin1StringView("urn:x-ical"))) {
0573                 item->setMimeType(QStringLiteral("text/calendar"));
0574             } else if (uri.startsWith(QLatin1StringView("news:"))) {
0575                 item->setMimeType(QStringLiteral("message/news"));
0576             } else {
0577                 QMimeDatabase db;
0578                 item->setMimeType(db.mimeTypeForUrl(QUrl(uri)).name());
0579             }
0580         }
0581     } else {
0582         auto job = KIO::storedGet(QUrl(uri));
0583         KJobWidgets::setWindow(job, nullptr);
0584         if (job->exec()) {
0585             const QByteArray data = job->data();
0586             addDataAttachment(data, mimeType, label);
0587         }
0588     }
0589 }
0590 
0591 #include "moc_incidenceattachment.cpp"