File indexing completed on 2024-04-28 05:47:34

0001 /*
0002     SPDX-FileCopyrightText: 2016 Elvis Angelaccio <elvis.angelaccio@kde.org>
0003     SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "compressfileitemaction.h"
0009 
0010 #include <QDir>
0011 #include <QMenu>
0012 #include <QMimeDatabase>
0013 
0014 #include <KFileItem>
0015 #include <KIO/ApplicationLauncherJob>
0016 #include <KLocalizedString>
0017 #include <KPluginFactory>
0018 
0019 #include <KIO/OpenFileManagerWindowJob>
0020 #include <algorithm>
0021 
0022 #include "addtoarchive.h"
0023 #include "pluginmanager.h"
0024 
0025 K_PLUGIN_CLASS_WITH_JSON(CompressFileItemAction, "compressfileitemaction.json")
0026 
0027 using namespace Kerfuffle;
0028 
0029 CompressFileItemAction::CompressFileItemAction(QObject *parent, const QVariantList &)
0030     : KAbstractFileItemActionPlugin(parent)
0031     , m_pluginManager(new PluginManager(this))
0032 {
0033 }
0034 
0035 QList<QAction *> CompressFileItemAction::actions(const KFileItemListProperties &fileItemInfos, QWidget *parentWidget)
0036 {
0037     // #268163: don't offer compression on already compressed archives, unless the user selected 2 or more of them.
0038     if (fileItemInfos.items().count() == 1 && m_pluginManager->supportedMimeTypes().contains(fileItemInfos.mimeType())) {
0039         return {};
0040     }
0041 
0042     // KFileItemListProperties::isLocal() doesn't check target URL (e.g. files on the desktop)
0043     const auto urlList = fileItemInfos.urlList();
0044     const bool hasLocalUrl = std::any_of(urlList.begin(), urlList.end(), [](const QUrl &url) {
0045         return url.isLocalFile();
0046     });
0047 
0048     if (!hasLocalUrl) {
0049         return {};
0050     }
0051 
0052     QList<QAction *> actions;
0053     const QIcon icon = QIcon::fromTheme(QStringLiteral("archive-insert"));
0054 
0055     QMenu *compressMenu = new QMenu(parentWidget);
0056 
0057     compressMenu->addAction(createAction(icon, parentWidget, urlList, QStringLiteral("tar.gz")));
0058 
0059     const QMimeType zipMime = QMimeDatabase().mimeTypeForName(QStringLiteral("application/zip"));
0060     // Don't offer zip compression if no zip plugin is available.
0061     if (!m_pluginManager->preferredWritePluginsFor(zipMime).isEmpty()) {
0062         compressMenu->addAction(createAction(icon, parentWidget, urlList, QStringLiteral("zip")));
0063     }
0064 
0065     compressMenu->addAction(createAction(icon, parentWidget, urlList, QString()));
0066 
0067     QAction *compressMenuAction = new QAction(i18nc("@action:inmenu Compress submenu in Dolphin context menu", "Compress"), parentWidget);
0068     compressMenuAction->setMenu(compressMenu);
0069     compressMenuAction->setEnabled(fileItemInfos.isLocal() && fileItemInfos.supportsWriting() && !m_pluginManager->availableWritePlugins().isEmpty());
0070     compressMenuAction->setIcon(icon);
0071 
0072     actions << compressMenuAction;
0073     return actions;
0074 }
0075 
0076 QAction *CompressFileItemAction::createAction(const QIcon &icon, QWidget *parent, const QList<QUrl> &urls, const QString &fileExtension)
0077 {
0078     QString name;
0079     if (fileExtension.isEmpty()) {
0080         name = i18nc("@action:inmenu Part of Compress submenu in Dolphin context menu", "Compress to...");
0081     } else {
0082         QString fileName = AddToArchive::getFileNameForUrls(urls, fileExtension).section(QDir::separator(), -1);
0083         if (fileName.length() > 21) {
0084             fileName = fileName.left(10) + QStringLiteral("…") + fileName.right(10);
0085         }
0086 
0087         name = i18nc("@action:inmenu Part of Compress submenu in Dolphin context menu, %1 filename", "Here as \"%1\"", fileName);
0088     }
0089 
0090     QAction *action = new QAction(icon, name, parent);
0091 
0092     connect(action, &QAction::triggered, this, [fileExtension, urls, parent, this]() {
0093         // Don't pass a parent to the job, otherwise it will be killed if dolphin gets closed.
0094         auto *addToArchiveJob = new AddToArchive(nullptr);
0095         addToArchiveJob->setImmediateProgressReporting(true);
0096         addToArchiveJob->setChangeToFirstPath(true);
0097         for (const QUrl &url : urls) {
0098             addToArchiveJob->addInput(url);
0099         }
0100         if (!fileExtension.isEmpty()) {
0101             addToArchiveJob->setAutoFilenameSuffix(fileExtension);
0102         } else {
0103             if (!addToArchiveJob->showAddDialog(parent)) {
0104                 delete addToArchiveJob;
0105                 return;
0106             }
0107         }
0108         addToArchiveJob->start();
0109         connect(addToArchiveJob, &KJob::finished, this, [this, addToArchiveJob]() {
0110             if (addToArchiveJob->error() == 0) {
0111                 KIO::highlightInFileManager({QUrl::fromLocalFile(addToArchiveJob->fileName())});
0112             } else if (!addToArchiveJob->errorString().isEmpty()) {
0113                 Q_EMIT error(addToArchiveJob->errorString());
0114             }
0115             addToArchiveJob->deleteLater();
0116         });
0117     });
0118 
0119     return action;
0120 }
0121 
0122 #include "compressfileitemaction.moc"
0123 #include "moc_compressfileitemaction.cpp"