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

0001 /* -*- mode: c++; c-basic-offset:4 -*-
0002     crypto/gui/resultlistwidget.cpp
0003 
0004     This file is part of Kleopatra, the KDE keymanager
0005     SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include <config-kleopatra.h>
0011 
0012 #include "resultlistwidget.h"
0013 
0014 #include "emailoperationspreferences.h"
0015 
0016 #include <crypto/decryptverifytask.h>
0017 #include <crypto/gui/resultitemwidget.h>
0018 
0019 #include <utils/gui-helper.h>
0020 #include <utils/scrollarea.h>
0021 
0022 #include <Libkleo/Stl_Util>
0023 
0024 #include <KLocalizedString>
0025 #include <KStandardGuiItem>
0026 #include <QPushButton>
0027 
0028 #include <QLabel>
0029 #include <QVBoxLayout>
0030 
0031 #include <KGuiItem>
0032 
0033 using namespace Kleo;
0034 using namespace Kleo::Crypto;
0035 using namespace Kleo::Crypto::Gui;
0036 
0037 class ResultListWidget::Private
0038 {
0039     ResultListWidget *const q;
0040 
0041 public:
0042     explicit Private(ResultListWidget *qq);
0043 
0044     void result(const std::shared_ptr<const Task::Result> &result);
0045     void started(const std::shared_ptr<Task> &task);
0046     void allTasksDone();
0047 
0048     void addResultWidget(ResultItemWidget *widget);
0049     void resizeIfStandalone();
0050 
0051     std::vector<std::shared_ptr<TaskCollection>> m_collections;
0052     bool m_standaloneMode = false;
0053     int m_lastErrorItemIndex = 0;
0054     ScrollArea *m_scrollArea = nullptr;
0055     QPushButton *m_closeButton = nullptr;
0056     QVBoxLayout *m_layout = nullptr;
0057     QLabel *m_progressLabel = nullptr;
0058 };
0059 
0060 ResultListWidget::Private::Private(ResultListWidget *qq)
0061     : q(qq)
0062     , m_collections()
0063 {
0064     m_layout = new QVBoxLayout(q);
0065     m_layout->setContentsMargins(0, 0, 0, 0);
0066     m_layout->setSpacing(0);
0067 
0068     m_scrollArea = new ScrollArea;
0069     m_scrollArea->setFocusPolicy(Qt::NoFocus);
0070     auto scrollAreaLayout = qobject_cast<QBoxLayout *>(m_scrollArea->widget()->layout());
0071     Q_ASSERT(scrollAreaLayout);
0072     scrollAreaLayout->setContentsMargins(0, 0, 0, 0);
0073     scrollAreaLayout->setSpacing(2);
0074     scrollAreaLayout->addStretch();
0075     m_layout->addWidget(m_scrollArea);
0076 
0077     m_progressLabel = new QLabel;
0078     m_progressLabel->setWordWrap(true);
0079     m_layout->addWidget(m_progressLabel);
0080     m_progressLabel->setVisible(false);
0081 
0082     m_closeButton = new QPushButton;
0083     KGuiItem::assign(m_closeButton, KStandardGuiItem::close());
0084     q->connect(m_closeButton, &QPushButton::clicked, q, &ResultListWidget::close);
0085     m_layout->addWidget(m_closeButton);
0086     m_closeButton->setVisible(false);
0087     m_closeButton->setEnabled(false);
0088 }
0089 
0090 ResultListWidget::ResultListWidget(QWidget *parent, Qt::WindowFlags f)
0091     : QWidget(parent, f)
0092     , d(new Private(this))
0093 {
0094 }
0095 
0096 ResultListWidget::~ResultListWidget()
0097 {
0098     if (!d->m_standaloneMode) {
0099         return;
0100     }
0101     EMailOperationsPreferences prefs;
0102     prefs.setDecryptVerifyPopupGeometry(geometry());
0103     prefs.save();
0104 }
0105 
0106 void ResultListWidget::Private::resizeIfStandalone()
0107 {
0108     if (m_standaloneMode) {
0109         q->resize(q->size().expandedTo(q->sizeHint()));
0110     }
0111 }
0112 
0113 void ResultListWidget::Private::addResultWidget(ResultItemWidget *widget)
0114 {
0115     Q_ASSERT(widget);
0116     Q_ASSERT(std::any_of(m_collections.cbegin(), m_collections.cend(), [](const std::shared_ptr<TaskCollection> &t) {
0117         return !t->isEmpty();
0118     }));
0119 
0120     Q_ASSERT(m_scrollArea);
0121     Q_ASSERT(m_scrollArea->widget());
0122     auto scrollAreaLayout = qobject_cast<QBoxLayout *>(m_scrollArea->widget()->layout());
0123     Q_ASSERT(scrollAreaLayout);
0124     // insert new widget after last widget showing error or before the trailing stretch
0125     const auto insertIndex = widget->hasErrorResult() ? m_lastErrorItemIndex++ : scrollAreaLayout->count() - 1;
0126     scrollAreaLayout->insertWidget(insertIndex, widget);
0127     if (insertIndex == 0) {
0128         forceSetTabOrder(m_scrollArea->widget(), widget);
0129     } else {
0130         auto previousResultWidget = qobject_cast<ResultItemWidget *>(scrollAreaLayout->itemAt(insertIndex - 1)->widget());
0131         QWidget::setTabOrder(previousResultWidget, widget);
0132     }
0133 
0134     widget->show();
0135     resizeIfStandalone();
0136 }
0137 
0138 void ResultListWidget::Private::allTasksDone()
0139 {
0140     if (!q->isComplete()) {
0141         return;
0142     }
0143     m_progressLabel->setVisible(false);
0144     resizeIfStandalone();
0145     Q_EMIT q->completeChanged();
0146 }
0147 
0148 void ResultListWidget::Private::result(const std::shared_ptr<const Task::Result> &result)
0149 {
0150     Q_ASSERT(result);
0151     Q_ASSERT(std::any_of(m_collections.cbegin(), m_collections.cend(), [](const std::shared_ptr<TaskCollection> &t) {
0152         return !t->isEmpty();
0153     }));
0154     auto wid = new ResultItemWidget(result);
0155     q->connect(wid, &ResultItemWidget::linkActivated, q, &ResultListWidget::linkActivated);
0156     q->connect(wid, &ResultItemWidget::closeButtonClicked, q, &ResultListWidget::close);
0157 
0158     const auto viewableContentType = result->viewableContentType();
0159 
0160     if (viewableContentType == Task::Result::ContentType::Mime || viewableContentType == Task::Result::ContentType::Mbox) {
0161         wid->setShowButton(i18nc("@action:button", "Show Email"), true);
0162         q->connect(wid, &ResultItemWidget::showButtonClicked, q, [this, result] {
0163             Q_EMIT q->showButtonClicked(result);
0164         });
0165     }
0166 
0167     addResultWidget(wid);
0168 }
0169 
0170 bool ResultListWidget::isComplete() const
0171 {
0172     return std::all_of(d->m_collections.cbegin(), d->m_collections.cend(), std::mem_fn(&TaskCollection::allTasksCompleted));
0173 }
0174 
0175 unsigned int ResultListWidget::totalNumberOfTasks() const
0176 {
0177     return kdtools::accumulate_transform(d->m_collections.cbegin(), d->m_collections.cend(), std::mem_fn(&TaskCollection::size), 0U);
0178 }
0179 
0180 unsigned int ResultListWidget::numberOfCompletedTasks() const
0181 {
0182     return kdtools::accumulate_transform(d->m_collections.cbegin(), d->m_collections.cend(), std::mem_fn(&TaskCollection::numberOfCompletedTasks), 0U);
0183 }
0184 
0185 void ResultListWidget::setTaskCollection(const std::shared_ptr<TaskCollection> &coll)
0186 {
0187     // clear(); ### PENDING(marc) implement
0188     addTaskCollection(coll);
0189 }
0190 
0191 void ResultListWidget::addTaskCollection(const std::shared_ptr<TaskCollection> &coll)
0192 {
0193     Q_ASSERT(coll);
0194     Q_ASSERT(!coll->isEmpty());
0195     d->m_collections.push_back(coll);
0196     connect(coll.get(),
0197             SIGNAL(result(std::shared_ptr<const Kleo::Crypto::Task::Result>)),
0198             this,
0199             SLOT(result(std::shared_ptr<const Kleo::Crypto::Task::Result>)));
0200     connect(coll.get(), SIGNAL(started(std::shared_ptr<Kleo::Crypto::Task>)), this, SLOT(started(std::shared_ptr<Kleo::Crypto::Task>)));
0201     connect(coll.get(), SIGNAL(done()), this, SLOT(allTasksDone()));
0202     setStandaloneMode(d->m_standaloneMode);
0203 }
0204 
0205 void ResultListWidget::Private::started(const std::shared_ptr<Task> &task)
0206 {
0207     Q_ASSERT(task);
0208     Q_ASSERT(m_progressLabel);
0209     m_progressLabel->setText(i18nc("number, operation description", "Operation %1: %2", q->numberOfCompletedTasks() + 1, task->label()));
0210     resizeIfStandalone();
0211 }
0212 
0213 void ResultListWidget::setStandaloneMode(bool standalone)
0214 {
0215     d->m_standaloneMode = standalone;
0216     if (totalNumberOfTasks() == 0) {
0217         return;
0218     }
0219     d->m_closeButton->setVisible(standalone);
0220     d->m_closeButton->setEnabled(standalone);
0221     d->m_progressLabel->setVisible(standalone);
0222 }
0223 
0224 #include "moc_resultlistwidget.cpp"