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"