File indexing completed on 2024-04-28 16:54:22

0001 /*
0002     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "clipboardjob.h"
0008 #include "history.h"
0009 #include "historyitem.h"
0010 #include "historystringitem.h"
0011 #include "klipper.h"
0012 
0013 #include "klipper_debug.h"
0014 #include <KIO/PreviewJob>
0015 #include <QFutureWatcher>
0016 #include <QIcon>
0017 #include <QtConcurrent>
0018 
0019 #include <Prison/Prison>
0020 
0021 const static QString s_iconKey = QStringLiteral("icon");
0022 const static QString s_previewKey = QStringLiteral("preview");
0023 const static QString s_previewWidthKey = QStringLiteral("previewWidth");
0024 const static QString s_previewHeightKey = QStringLiteral("previewHeight");
0025 const static QString s_urlKey = QStringLiteral("url");
0026 
0027 ClipboardJob::ClipboardJob(Klipper *klipper, const QString &destination, const QString &operation, const QVariantMap &parameters, QObject *parent)
0028     : Plasma::ServiceJob(destination, operation, parameters, parent)
0029     , m_klipper(klipper)
0030 {
0031 }
0032 
0033 void ClipboardJob::start()
0034 {
0035     const QString operation = operationName();
0036     // first check for operations not needing an item
0037     if (operation == QLatin1String("clearHistory")) {
0038         m_klipper->slotAskClearHistory();
0039         setResult(true);
0040         return;
0041     } else if (operation == QLatin1String("configureKlipper")) {
0042         m_klipper->slotConfigure();
0043         setResult(true);
0044         return;
0045     }
0046 
0047     // other operations need the item
0048     HistoryItemConstPtr item = m_klipper->history()->find(QByteArray::fromBase64(destination().toUtf8()));
0049     if (item.isNull()) {
0050         setResult(false);
0051         return;
0052     }
0053     if (operation == QLatin1String("select")) {
0054         m_klipper->history()->slotMoveToTop(item->uuid());
0055         setResult(true);
0056     } else if (operation == QLatin1String("remove")) {
0057         m_klipper->history()->remove(item);
0058         setResult(true);
0059     } else if (operation == QLatin1String("edit")) {
0060         if (parameters().contains(QLatin1String("text"))) {
0061             const QString text = parameters()[QLatin1String("text")].toString();
0062             if (item) {
0063                 m_klipper->history()->remove(item);
0064             }
0065             m_klipper->history()->insert(HistoryItemPtr(new HistoryStringItem(text)));
0066             if (m_klipper->urlGrabber()) {
0067                 m_klipper->urlGrabber()->checkNewData(HistoryItemConstPtr(m_klipper->history()->first()));
0068             }
0069             setResult(true);
0070             return;
0071         }
0072         connect(m_klipper, &Klipper::editFinished, this, [this, item](HistoryItemConstPtr editedItem, int result) {
0073             if (item != editedItem) {
0074                 // not our item
0075                 return;
0076             }
0077             setResult(result);
0078         });
0079         m_klipper->editData(item);
0080         return;
0081     } else if (operation == QLatin1String("barcode")) {
0082         int pixelWidth = parameters().value(QStringLiteral("width")).toInt();
0083         int pixelHeight = parameters().value(QStringLiteral("height")).toInt();
0084         Prison::AbstractBarcode *code = nullptr;
0085         switch (parameters().value(QStringLiteral("barcodeType")).toInt()) {
0086         case 1: {
0087             code = Prison::createBarcode(Prison::DataMatrix);
0088             const int size = qMin(pixelWidth, pixelHeight);
0089             pixelWidth = size;
0090             pixelHeight = size;
0091             break;
0092         }
0093         case 2: {
0094             code = Prison::createBarcode(Prison::Code39);
0095             break;
0096         }
0097         case 3: {
0098             code = Prison::createBarcode(Prison::Code93);
0099             break;
0100         }
0101         case 4: {
0102             code = Prison::createBarcode(Prison::Aztec);
0103             break;
0104         }
0105         case 0:
0106         default: {
0107             code = Prison::createBarcode(Prison::QRCode);
0108             const int size = qMin(pixelWidth, pixelHeight);
0109             pixelWidth = size;
0110             pixelHeight = size;
0111             break;
0112         }
0113         }
0114         if (code) {
0115             code->setData(item->text());
0116             QFutureWatcher<QImage> *watcher = new QFutureWatcher<QImage>(this);
0117             connect(watcher, &QFutureWatcher<QImage>::finished, this, [this, watcher, code] {
0118                 setResult(watcher->result());
0119                 watcher->deleteLater();
0120                 delete code;
0121             });
0122 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0123             auto future = QtConcurrent::run(code, &Prison::AbstractBarcode::toImage, QSizeF(pixelWidth, pixelHeight));
0124 #else
0125             auto future = QtConcurrent::run(&Prison::AbstractBarcode::toImage, code, QSizeF(pixelWidth, pixelHeight));
0126 #endif
0127             watcher->setFuture(future);
0128             return;
0129         } else {
0130             setResult(false);
0131         }
0132     } else if (operation == QLatin1String("action")) {
0133         m_klipper->urlGrabber()->invokeAction(item);
0134         setResult(true);
0135 
0136     } else if (operation == s_previewKey) {
0137         const int pixelWidth = parameters().value(s_previewWidthKey).toInt();
0138         const int pixelHeight = parameters().value(s_previewHeightKey).toInt();
0139         QUrl url = parameters().value(s_urlKey).toUrl();
0140         qCDebug(KLIPPER_LOG) << "URL: " << url;
0141         KFileItem item(url);
0142 
0143         if (pixelWidth <= 0 || pixelHeight <= 0) {
0144             qCWarning(KLIPPER_LOG) << "Preview size invalid: " << pixelWidth << "x" << pixelHeight;
0145             iconResult(item);
0146             return;
0147         }
0148 
0149         if (!url.isValid() || !url.isLocalFile()) { // no remote files
0150             qCWarning(KLIPPER_LOG) << "Invalid or non-local url for preview: " << url;
0151             iconResult(item);
0152             return;
0153         }
0154 
0155         KFileItemList urls;
0156         urls << item;
0157 
0158         KIO::PreviewJob *job = KIO::filePreview(urls, QSize(pixelWidth, pixelHeight));
0159         job->setIgnoreMaximumSize(true);
0160         connect(job, &KIO::PreviewJob::gotPreview, this, [this](const KFileItem &item, const QPixmap &preview) {
0161             QVariantMap res;
0162             res.insert(s_urlKey, item.url());
0163             res.insert(s_previewKey, preview);
0164             res.insert(s_iconKey, false);
0165             res.insert(s_previewWidthKey, preview.size().width());
0166             res.insert(s_previewHeightKey, preview.size().height());
0167             setResult(res);
0168         });
0169         connect(job, &KIO::PreviewJob::failed, this, [this](const KFileItem &item) {
0170             iconResult(item);
0171         });
0172 
0173         job->start();
0174 
0175         return;
0176     } else {
0177         setResult(false);
0178     }
0179     emitResult();
0180 }
0181 
0182 void ClipboardJob::iconResult(const KFileItem &item)
0183 {
0184     QVariantMap res;
0185     res.insert(s_urlKey, item.url());
0186     QPixmap pix = QIcon::fromTheme(item.determineMimeType().iconName()).pixmap(128, 128);
0187     res.insert(s_previewKey, pix);
0188     res.insert(s_iconKey, true);
0189     res.insert(QStringLiteral("iconName"), item.currentMimeType().iconName());
0190     res.insert(s_previewWidthKey, pix.size().width());
0191     res.insert(s_previewHeightKey, pix.size().height());
0192     setResult(res);
0193 }