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 "extractfileitemaction.h"
0009 
0010 #include <QFileInfo>
0011 #include <QMenu>
0012 
0013 #include <KIO/CopyJob>
0014 #include <KIO/JobUiDelegate>
0015 #include <KIO/OpenFileManagerWindowJob>
0016 #include <KLocalizedString>
0017 #include <KPluginFactory>
0018 
0019 #include "batchextract.h"
0020 #include "mimetypes.h"
0021 #include "pluginmanager.h"
0022 #include "settings.h"
0023 
0024 K_PLUGIN_CLASS_WITH_JSON(ExtractFileItemAction, "extractfileitemaction.json")
0025 
0026 using namespace Kerfuffle;
0027 
0028 ExtractFileItemAction::ExtractFileItemAction(QObject *parent, const QVariantList &)
0029     : KAbstractFileItemActionPlugin(parent)
0030     , m_pluginManager(new PluginManager(this))
0031 {
0032 }
0033 
0034 QList<QAction *> ExtractFileItemAction::actions(const KFileItemListProperties &fileItemInfos, QWidget *parentWidget)
0035 {
0036     QList<QAction *> actions;
0037     const QIcon icon = QIcon::fromTheme(QStringLiteral("archive-extract"));
0038 
0039     bool readOnlyParentDir = false;
0040     QList<QUrl> supportedUrls;
0041     // Filter URLs by supported mimetypes.
0042     const auto urlList = fileItemInfos.urlList();
0043     for (const QUrl &url : urlList) {
0044         if (!url.isLocalFile()) {
0045             continue;
0046         }
0047         const QMimeType mimeType = determineMimeType(url.toLocalFile());
0048         if (m_pluginManager->preferredPluginsFor(mimeType).isEmpty()) {
0049             continue;
0050         }
0051         supportedUrls << url;
0052         // Check whether we can write in the parent directory of the file.
0053         if (!readOnlyParentDir) {
0054             const QString directory = url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toLocalFile();
0055             if (!QFileInfo(directory).isWritable()) {
0056                 readOnlyParentDir = true;
0057             }
0058         }
0059     }
0060 
0061     if (supportedUrls.isEmpty()) {
0062         return {};
0063     }
0064 
0065     QAction *extractToAction = createAction(icon,
0066                                             i18nc("@action:inmenu Part of Extract submenu in Dolphin context menu", "Extract to…"),
0067                                             parentWidget,
0068                                             supportedUrls,
0069                                             AdditionalJobOptions::ShowDialog);
0070 
0071     // #189177: disable "extract here" actions in read-only folders.
0072     if (readOnlyParentDir) {
0073         actions << extractToAction;
0074     } else {
0075         QMenu *extractMenu = new QMenu(parentWidget);
0076 
0077         extractMenu->addAction(createAction(icon,
0078                                             i18nc("@action:inmenu Part of Extract submenu in Dolphin context menu", "Extract here"),
0079                                             parentWidget,
0080                                             supportedUrls,
0081                                             AdditionalJobOptions::None));
0082 
0083         extractMenu->addAction(createAction(QIcon::fromTheme(QStringLiteral("archive-remove")),
0084                                             i18nc("@action:inmenu Part of Extract submenu in Dolphin context menu", "Extract here and delete archive"),
0085                                             parentWidget,
0086                                             supportedUrls,
0087                                             AdditionalJobOptions::AutoDelete));
0088 
0089         extractMenu->addAction(extractToAction);
0090 
0091         QAction *extractMenuAction = new QAction(i18nc("@action:inmenu Extract submenu in Dolphin context menu", "Extract"), parentWidget);
0092         extractMenuAction->setMenu(extractMenu);
0093         extractMenuAction->setIcon(icon);
0094 
0095         actions << extractMenuAction;
0096     }
0097 
0098     return actions;
0099 }
0100 
0101 QAction *ExtractFileItemAction::createAction(const QIcon &icon, const QString &name, QWidget *parent, const QList<QUrl> &urls, AdditionalJobOptions option)
0102 {
0103     QAction *action = new QAction(icon, name, parent);
0104     connect(action, &QAction::triggered, this, [urls, option, this]() {
0105         // Don't pass a parent to the job, otherwise it will be killed if dolphin gets closed.
0106         auto *batchExtractJob = new BatchExtract(nullptr);
0107         batchExtractJob->setDestinationFolder(QFileInfo(urls.first().toLocalFile()).path());
0108         batchExtractJob->setOpenDestinationAfterExtraction(ArkSettings::openDestinationFolderAfterExtraction());
0109         if (option == ShowDialog) {
0110             if (!batchExtractJob->showExtractDialog()) {
0111                 delete batchExtractJob;
0112                 return;
0113             }
0114         } else {
0115             batchExtractJob->setAutoSubfolder(true);
0116         }
0117         for (const QUrl &url : urls) {
0118             batchExtractJob->addInput(url);
0119         }
0120         batchExtractJob->start();
0121         connect(batchExtractJob, &KJob::finished, this, [this, batchExtractJob, option, urls]() {
0122             if (batchExtractJob->error()) {
0123                 Q_EMIT error(batchExtractJob->errorString());
0124             } else if (option == AutoDelete) {
0125                 KIO::Job *job = KIO::trash(urls);
0126                 job->uiDelegate()->setAutoErrorHandlingEnabled(true);
0127             }
0128             batchExtractJob->deleteLater();
0129         });
0130     });
0131     return action;
0132 }
0133 
0134 #include "extractfileitemaction.moc"
0135 #include "moc_extractfileitemaction.cpp"