File indexing completed on 2024-06-23 05:13:49

0001 /* crypto/gui/decryptverifyfilesdialog.cpp
0002 
0003     This file is part of Kleopatra, the KDE keymanager
0004     SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
0005     SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik
0006     SPDX-FileContributor: Intevation GmbH
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "decryptverifyfilesdialog.h"
0012 
0013 #include "kleopatra_debug.h"
0014 
0015 #include "crypto/decryptverifytask.h"
0016 #include "crypto/gui/resultlistwidget.h"
0017 #include "crypto/gui/resultpage.h"
0018 #include "crypto/taskcollection.h"
0019 #include "utils/path-helper.h"
0020 
0021 #include <Libkleo/FileNameRequester>
0022 
0023 #include <QLabel>
0024 #include <QProgressBar>
0025 #include <QPushButton>
0026 #include <QVBoxLayout>
0027 #include <QWindow>
0028 
0029 #include <vector>
0030 
0031 #include <KConfigGroup>
0032 #include <KLocalizedContext>
0033 #include <KLocalizedString>
0034 #include <KMessageBox>
0035 #include <KSharedConfig>
0036 #include <KWindowConfig>
0037 #include <MimeTreeParserWidgets/MessageViewerDialog>
0038 
0039 using namespace Kleo;
0040 using namespace Kleo::Crypto;
0041 using namespace Kleo::Crypto::Gui;
0042 using namespace MimeTreeParser::Widgets;
0043 
0044 DecryptVerifyFilesDialog::DecryptVerifyFilesDialog(const std::shared_ptr<TaskCollection> &coll, QWidget *parent)
0045     : QDialog(parent)
0046     , m_tasks(coll)
0047     , m_buttonBox(new QDialogButtonBox)
0048 {
0049     readConfig();
0050     auto vLay = new QVBoxLayout(this);
0051     auto labels = new QWidget;
0052     auto outputLayout = new QHBoxLayout;
0053 
0054     m_outputLocationFNR = new FileNameRequester;
0055     auto outLabel = new QLabel(i18n("&Output folder:"));
0056     outLabel->setBuddy(m_outputLocationFNR);
0057     outputLayout->addWidget(outLabel);
0058     outputLayout->addWidget(m_outputLocationFNR);
0059     m_outputLocationFNR->setFilter(QDir::Dirs);
0060 
0061     vLay->addLayout(outputLayout);
0062 
0063     m_progressLabelLayout = new QVBoxLayout(labels);
0064     vLay->addWidget(labels);
0065     m_progressBar = new QProgressBar;
0066     vLay->addWidget(m_progressBar);
0067     m_resultList = new ResultListWidget;
0068     connect(m_resultList, &ResultListWidget::showButtonClicked, this, &DecryptVerifyFilesDialog::showContent);
0069     vLay->addWidget(m_resultList);
0070 
0071     m_tasks = coll;
0072     Q_ASSERT(m_tasks);
0073     m_resultList->setTaskCollection(coll);
0074     connect(m_tasks.get(), &TaskCollection::progress, this, &DecryptVerifyFilesDialog::progress);
0075     connect(m_tasks.get(), &TaskCollection::done, this, &DecryptVerifyFilesDialog::allDone);
0076     connect(m_tasks.get(), &TaskCollection::started, this, &DecryptVerifyFilesDialog::started);
0077 
0078     connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0079     connect(m_buttonBox, &QDialogButtonBox::clicked, this, &DecryptVerifyFilesDialog::btnClicked);
0080 
0081     layout()->addWidget(m_buttonBox);
0082 
0083     bool hasOutputs = false;
0084     for (const auto &t : coll->tasks()) {
0085         if (!qobject_cast<VerifyDetachedTask *>(t.get())) {
0086             hasOutputs = true;
0087             break;
0088         }
0089     }
0090     if (hasOutputs) {
0091         setWindowTitle(i18nc("@title:window", "Decrypt/Verify Files"));
0092         m_saveButton = QDialogButtonBox::SaveAll;
0093         m_buttonBox->addButton(QDialogButtonBox::Discard);
0094         connect(m_buttonBox, &QDialogButtonBox::accepted, this, &DecryptVerifyFilesDialog::checkAccept);
0095     } else {
0096         outLabel->setVisible(false);
0097         m_outputLocationFNR->setVisible(false);
0098         setWindowTitle(i18nc("@title:window", "Verify Files"));
0099         m_buttonBox->addButton(QDialogButtonBox::Close);
0100         connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
0101     }
0102     if (m_saveButton) {
0103         m_buttonBox->addButton(m_saveButton);
0104         m_buttonBox->button(m_saveButton)->setEnabled(false);
0105     }
0106 }
0107 
0108 DecryptVerifyFilesDialog::~DecryptVerifyFilesDialog()
0109 {
0110     qCDebug(KLEOPATRA_LOG);
0111     writeConfig();
0112 }
0113 
0114 void DecryptVerifyFilesDialog::allDone()
0115 {
0116     qCDebug(KLEOPATRA_LOG) << "All done";
0117     Q_ASSERT(m_tasks);
0118     m_progressBar->setRange(0, 100);
0119     m_progressBar->setValue(100);
0120     for (const auto &i : m_progressLabelByTag.keys()) {
0121         if (!i.isEmpty()) {
0122             m_progressLabelByTag.value(i)->setText(i18n("%1: All operations completed.", i));
0123         } else {
0124             m_progressLabelByTag.value(i)->setText(i18n("All operations completed."));
0125         }
0126     }
0127 
0128     if (m_tasks->allTasksHaveErrors()) {
0129         return;
0130     }
0131     if (m_saveButton != QDialogButtonBox::NoButton) {
0132         m_buttonBox->button(m_saveButton)->setEnabled(true);
0133     } else {
0134         m_buttonBox->removeButton(m_buttonBox->button(QDialogButtonBox::Close));
0135         m_buttonBox->addButton(QDialogButtonBox::Ok);
0136     }
0137 }
0138 
0139 void DecryptVerifyFilesDialog::started(const std::shared_ptr<Task> &task)
0140 {
0141     Q_ASSERT(task);
0142     const auto tag = task->tag();
0143     auto label = labelForTag(tag);
0144     Q_ASSERT(label);
0145     if (tag.isEmpty()) {
0146         label->setText(i18nc("number, operation description", "Operation %1: %2", m_tasks->numberOfCompletedTasks() + 1, task->label()));
0147     } else {
0148         label->setText(i18nc(R"(tag( "OpenPGP" or "CMS"),  operation description)", "%1: %2", tag, task->label()));
0149     }
0150     if (m_saveButton != QDialogButtonBox::NoButton) {
0151         m_buttonBox->button(m_saveButton)->setEnabled(false);
0152     } else if (m_buttonBox->button(QDialogButtonBox::Ok)) {
0153         m_buttonBox->removeButton(m_buttonBox->button(QDialogButtonBox::Ok));
0154         m_buttonBox->addButton(QDialogButtonBox::Close);
0155     }
0156 }
0157 
0158 QLabel *DecryptVerifyFilesDialog::labelForTag(const QString &tag)
0159 {
0160     if (QLabel *const label = m_progressLabelByTag.value(tag)) {
0161         return label;
0162     }
0163     auto label = new QLabel;
0164     label->setTextFormat(Qt::RichText);
0165     label->setWordWrap(true);
0166     m_progressLabelLayout->addWidget(label);
0167     m_progressLabelByTag.insert(tag, label);
0168     return label;
0169 }
0170 
0171 void DecryptVerifyFilesDialog::progress(int progress, int total)
0172 {
0173     Q_ASSERT(progress >= 0);
0174     Q_ASSERT(total >= 0);
0175     m_progressBar->setRange(0, total);
0176     m_progressBar->setValue(progress);
0177 }
0178 
0179 void DecryptVerifyFilesDialog::setOutputLocation(const QString &dir)
0180 {
0181     m_outputLocationFNR->setFileName(dir);
0182 }
0183 
0184 QString DecryptVerifyFilesDialog::outputLocation() const
0185 {
0186     return m_outputLocationFNR->fileName();
0187 }
0188 
0189 void DecryptVerifyFilesDialog::btnClicked(QAbstractButton *btn)
0190 {
0191     if (m_buttonBox->buttonRole(btn) == QDialogButtonBox::DestructiveRole) {
0192         close();
0193     }
0194 }
0195 
0196 void DecryptVerifyFilesDialog::checkAccept()
0197 {
0198     const auto outLoc = outputLocation();
0199     if (outLoc.isEmpty()) {
0200         KMessageBox::information(this, i18n("Please select an output folder."), i18nc("@title:window", "No Output Folder"));
0201         return;
0202     }
0203     const QFileInfo fi(outLoc);
0204 
0205     if (!fi.exists()) {
0206         qCDebug(KLEOPATRA_LOG) << "Output dir does not exist. Trying to create.";
0207         const QDir dir(outLoc);
0208         if (!dir.mkdir(outLoc)) {
0209             KMessageBox::information(
0210                 this,
0211                 xi18nc("@info",
0212                        "<para>Failed to create output folder <filename>%1</filename>.</para><para>Please select a different output folder.</para>",
0213                        outLoc),
0214                 i18nc("@title:window", "Unusable Output Folder"));
0215         } else {
0216             accept();
0217         }
0218     } else if (!fi.isDir()) {
0219         KMessageBox::information(this, i18n("Please select a different output folder."), i18nc("@title:window", "Invalid Output Folder"));
0220     } else if (!Kleo::isWritable(fi)) {
0221         KMessageBox::information(
0222             this,
0223             xi18nc("@info",
0224                    "<para>Cannot write in the output folder <filename>%1</filename>.</para><para>Please select a different output folder.</para>",
0225                    outLoc),
0226             i18nc("@title:window", "Unusable Output Folder"));
0227     } else {
0228         accept();
0229     }
0230 }
0231 
0232 void DecryptVerifyFilesDialog::readConfig()
0233 {
0234     winId(); // ensure there's a window created
0235 
0236     // set default window size
0237     windowHandle()->resize(640, 480);
0238 
0239     // restore size from config file
0240     KConfigGroup cfgGroup(KSharedConfig::openStateConfig(), QStringLiteral("DecryptVerifyFilesDialog"));
0241     KWindowConfig::restoreWindowSize(windowHandle(), cfgGroup);
0242 
0243     // NOTICE: QWindow::setGeometry() does NOT impact the backing QWidget geometry even if the platform
0244     // window was created -> QTBUG-40584. We therefore copy the size here.
0245     // TODO: remove once this was resolved in QWidget QPA
0246     resize(windowHandle()->size());
0247 }
0248 
0249 void DecryptVerifyFilesDialog::writeConfig()
0250 {
0251     KConfigGroup cfgGroup(KSharedConfig::openStateConfig(), QStringLiteral("DecryptVerifyFilesDialog"));
0252     KWindowConfig::saveWindowSize(windowHandle(), cfgGroup);
0253     cfgGroup.sync();
0254 }
0255 
0256 void DecryptVerifyFilesDialog::showContent(const std::shared_ptr<const Task::Result> &result)
0257 {
0258     if (auto decryptVerifyResult = std::dynamic_pointer_cast<const DecryptVerifyResult>(result)) {
0259         MessageViewerDialog dialog(decryptVerifyResult->fileName());
0260         dialog.exec();
0261     }
0262 }
0263 
0264 #include "moc_decryptverifyfilesdialog.cpp"