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"