Mailcommon

collectionexpirywidget.cpp
1/*
2 SPDX-FileCopyrightText: 2020-2024 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "collectionexpirywidget.h"
8#include "attributes/expirecollectionattribute.h"
9#include "collectionexpiryjob.h"
10#include "folder/foldersettings.h"
11#include "folderrequester.h"
12#include "kernel/mailkernel.h"
13#include "util/mailutil.h"
14#include <KLocalization>
15
16#include <Akonadi/CollectionModifyJob>
17
18#include <KMessageBox>
19#include <QCheckBox>
20#include <QFormLayout>
21#include <QGroupBox>
22#include <QHBoxLayout>
23#include <QPushButton>
24#include <QRadioButton>
25#include <QSpinBox>
26
27using namespace MailCommon;
28
29class DaysSpinBox : public QSpinBox
30{
31public:
32 DaysSpinBox(QWidget *parent)
34 {
35 setMaximum(999999);
36#if KI18N_VERSION > QT_VERSION_CHECK(6, 5, 0)
37 KLocalization::setupSpinBoxFormatString(this, ki18ncp("Expire messages after %1", "%v day", "%v days"));
38#endif
39 setSpecialValueText(i18n("Never"));
40 }
41
42 [[nodiscard]] QString textFromValue(int value) const override
43 {
44 if (value == 0) {
45 return i18n("Never");
46 }
48 }
49
50 [[nodiscard]] int valueFromText(const QString &text) const override
51 {
53 }
54
55 QValidator::State validate(QString &text, int &pos) const override
56 {
57 if (text == i18n("Never")) {
59 }
61 }
62};
63
64CollectionExpiryWidget::CollectionExpiryWidget(QWidget *parent)
65 : QWidget(parent)
66 , mExpireReadMailSB(new DaysSpinBox(this))
67 , mExpireUnreadMailSB(new DaysSpinBox(this))
68 , mFolderSelector(new FolderRequester(this))
69 , mExpireNowPB(new QPushButton(i18nc("@action:button", "Save Settings and Expire Now"), this))
70 , mExpireMailWithInvalidDateCB(new QCheckBox(i18nc("@option:check", "Expire messages with invalid date"), this))
71{
72 auto formLayout = new QFormLayout(this);
73 formLayout->setContentsMargins({});
74
75 connect(mExpireReadMailSB, &QSpinBox::valueChanged, this, &CollectionExpiryWidget::slotChanged);
76 formLayout->addRow(i18n("Expire read messages after:"), mExpireReadMailSB);
77
78 connect(mExpireUnreadMailSB, &QSpinBox::valueChanged, this, &CollectionExpiryWidget::slotChanged);
79 formLayout->addRow(i18n("Expire unread messages after:"), mExpireUnreadMailSB);
80
81 connect(mExpireMailWithInvalidDateCB, &QCheckBox::toggled, this, &CollectionExpiryWidget::slotChanged);
82 formLayout->addRow(QString(), mExpireMailWithInvalidDateCB);
83
84 auto actionsGroup = new QGroupBox(this);
85 actionsGroup->setFlat(true); // for mutual exclusion of the radio buttons
86 formLayout->addRow(actionsGroup);
87
88 auto moveToHBox = new QHBoxLayout();
89 moveToHBox->setContentsMargins({});
90 moveToHBox->setSpacing(6);
91
92 mMoveToRB = new QRadioButton(actionsGroup);
93 mMoveToRB->setText(i18n("Move expired messages to:"));
94 connect(mMoveToRB, &QRadioButton::toggled, this, &CollectionExpiryWidget::slotChanged);
95 moveToHBox->addWidget(mMoveToRB);
96
97 mFolderSelector->setMustBeReadWrite(true);
98 mFolderSelector->setShowOutbox(false);
99 moveToHBox->addWidget(mFolderSelector);
100 formLayout->addRow(QString(), moveToHBox);
101 connect(mFolderSelector, &FolderRequester::folderChanged, this, &CollectionExpiryWidget::slotChanged);
102
103 mDeletePermanentlyRB = new QRadioButton(actionsGroup);
104 mDeletePermanentlyRB->setText(i18n("Delete expired messages permanently"));
105 connect(mDeletePermanentlyRB, &QRadioButton::toggled, this, &CollectionExpiryWidget::slotChanged);
106
107 formLayout->addRow(QString(), mDeletePermanentlyRB);
108
109 connect(mExpireNowPB, &QPushButton::clicked, this, &CollectionExpiryWidget::saveAndExpireRequested);
110 formLayout->addRow(QString(), mExpireNowPB);
111
112 mDeletePermanentlyRB->setChecked(true);
113 slotChanged();
114}
115
116CollectionExpiryWidget::~CollectionExpiryWidget() = default;
117
118void CollectionExpiryWidget::hideExpireNowButton()
119{
120 mExpireNowPB->setVisible(false);
121}
122
123void CollectionExpiryWidget::slotChanged()
124{
125 const bool showExpiryActions = mExpireReadMailSB->value() != 0 || mExpireUnreadMailSB->value() != 0;
126 mMoveToRB->setEnabled(showExpiryActions);
127 mFolderSelector->setEnabled(showExpiryActions && mMoveToRB->isChecked());
128 mDeletePermanentlyRB->setEnabled(showExpiryActions);
129 mExpireNowPB->setEnabled(showExpiryActions);
130
131 Q_EMIT configChanged();
132}
133
134void CollectionExpiryWidget::load(const MailCommon::CollectionExpirySettings &settings)
135{
136 if (settings.isValid()) {
137 bool expiryGloballyOn = settings.expiryGloballyOn;
138 if (expiryGloballyOn && settings.mReadExpireUnits != ExpireCollectionAttribute::ExpireNever && settings.daysToExpireRead >= 0) {
139 mExpireReadMailSB->setValue(settings.daysToExpireRead);
140 } else {
141 mExpireReadMailSB->setValue(0);
142 }
143 if (expiryGloballyOn && settings.mUnreadExpireUnits != ExpireCollectionAttribute::ExpireNever && settings.daysToExpireUnread >= 0) {
144 mExpireUnreadMailSB->setValue(settings.daysToExpireUnread);
145 } else {
146 mExpireUnreadMailSB->setValue(0);
147 }
148
149 if (settings.mExpireAction == ExpireCollectionAttribute::ExpireDelete) {
150 mDeletePermanentlyRB->setChecked(true);
151 } else {
152 mMoveToRB->setChecked(true);
153 }
154
155 mExpireMailWithInvalidDateCB->setChecked(settings.expiryMessagesWithInvalidDate);
156 Akonadi::Collection::Id destFolderID = settings.mExpireToFolderId;
157 if (destFolderID > 0) {
158 Akonadi::Collection destFolder = Kernel::self()->collectionFromId(destFolderID);
159 if (destFolder.isValid()) {
160 mFolderSelector->setCollection(destFolder);
161 }
162 }
163 } else {
164 mDeletePermanentlyRB->setChecked(true);
165 }
166 slotChanged();
167}
168
169bool CollectionExpiryWidget::validateExpireFolder(bool expireNow)
170{
171 const bool enableGlobally = mExpireReadMailSB->value() != 0 || mExpireUnreadMailSB->value() != 0;
172 const Akonadi::Collection expireToFolder = mFolderSelector->collection();
173 if (enableGlobally && mMoveToRB->isChecked() && !expireToFolder.isValid()) {
175 i18n("Please select a folder to expire messages into.\nIf this is not done, expired messages will be permanently deleted."),
176 i18nc("@title:window", "No Folder Selected"));
177 mDeletePermanentlyRB->setChecked(true);
178 expireNow = false; // settings are not valid
179 }
180 return expireNow;
181}
182
183MailCommon::ExpireCollectionAttribute *CollectionExpiryWidget::assignFolderAttribute(Akonadi::Collection &collection, bool &expireNow)
184{
185 const Akonadi::Collection expireToFolder = mFolderSelector->collection();
186 MailCommon::ExpireCollectionAttribute *attribute = nullptr;
187 if (expireToFolder.isValid() && mMoveToRB->isChecked()) {
188 if (expireToFolder.id() == collection.id()) {
190 i18n("Please select a different folder than the current folder to expire messages into.\nIf this is not done, expired messages "
191 "will be permanently deleted."),
192 i18nc("@title:window", "Wrong Folder Selected"));
193 mDeletePermanentlyRB->setChecked(true);
194 expireNow = false; // settings are not valid
195 } else {
196 attribute = collection.attribute<MailCommon::ExpireCollectionAttribute>(Akonadi::Collection::AddIfMissing);
197 attribute->setExpireToFolderId(expireToFolder.id());
198 }
199 }
200 if (!attribute) {
201 attribute = collection.attribute<MailCommon::ExpireCollectionAttribute>(Akonadi::Collection::AddIfMissing);
202 }
203 return attribute;
204}
205
206CollectionExpirySettings CollectionExpiryWidget::settings() const
207{
208 CollectionExpirySettings settings;
209 settings.expiryGloballyOn = mExpireReadMailSB->value() != 0 || mExpireUnreadMailSB->value() != 0;
210 settings.expiryMessagesWithInvalidDate = mExpireMailWithInvalidDateCB->isChecked();
211 // we always write out days now
212 settings.daysToExpireRead = mExpireReadMailSB->value();
213 settings.daysToExpireUnread = mExpireUnreadMailSB->value();
214 settings.mReadExpireUnits =
215 mExpireReadMailSB->value() != 0 ? MailCommon::ExpireCollectionAttribute::ExpireDays : MailCommon::ExpireCollectionAttribute::ExpireNever;
216 settings.mUnreadExpireUnits =
217 mExpireUnreadMailSB->value() != 0 ? MailCommon::ExpireCollectionAttribute::ExpireDays : MailCommon::ExpireCollectionAttribute::ExpireNever;
218
219 if (mDeletePermanentlyRB->isChecked()) {
220 settings.mExpireAction = ExpireCollectionAttribute::ExpireDelete;
221 } else {
222 settings.mExpireAction = ExpireCollectionAttribute::ExpireMove;
223 }
224 return settings;
225}
226
227void CollectionExpiryWidget::save(const CollectionExpirySettings &collectionExpirySettings, Akonadi::Collection &collection, bool saveSettings, bool expireNow)
228{
229 expireNow = validateExpireFolder(expireNow);
230 MailCommon::ExpireCollectionAttribute *attribute = assignFolderAttribute(collection, expireNow);
231 attribute->setAutoExpire(collectionExpirySettings.expiryGloballyOn);
232 // we always write out days now
233 attribute->setReadExpireAge(collectionExpirySettings.daysToExpireRead);
234 attribute->setUnreadExpireAge(collectionExpirySettings.daysToExpireUnread);
235 attribute->setReadExpireUnits(collectionExpirySettings.mReadExpireUnits);
236 attribute->setUnreadExpireUnits(collectionExpirySettings.mUnreadExpireUnits);
237 attribute->setExpireAction(collectionExpirySettings.mExpireAction);
238
239 if (saveSettings) {
240 auto job = new CollectionExpiryJob;
241 job->setExpireNow(expireNow);
242 job->setCollection(collection);
243 job->start();
244 } else {
245 if (expireNow) {
246 MailCommon::Util::expireOldMessages(collection, true /*immediate*/);
247 }
248 }
249 Q_EMIT configChanged(false);
250}
251
252void CollectionExpiryWidget::save(Akonadi::Collection &collection, bool saveSettings, bool expireNow)
253{
254 const CollectionExpirySettings collectionExpirySettings = settings();
255 save(collectionExpirySettings, collection, saveSettings, expireNow);
256}
257
258bool CollectionExpiryWidget::canHandle(const Akonadi::Collection &col)
259{
260 QSharedPointer<FolderSettings> fd = FolderSettings::forCollection(col, false);
261 return fd->canDeleteMessages() && !fd->isStructural() && !MailCommon::Util::isVirtualCollection(col);
262}
263
264bool CollectionExpirySettings::isValid() const
265{
266 const bool valid = daysToExpireRead != -1 || daysToExpireUnread != -1 || mUnreadExpireUnits != ExpireCollectionAttribute::ExpireNever
267 || mReadExpireUnits != ExpireCollectionAttribute::ExpireNever || mExpireAction != ExpireCollectionAttribute::ExpireDelete || mExpireToFolderId != -1;
268 return valid;
269}
270
271QDebug operator<<(QDebug d, const CollectionExpirySettings &t)
272{
273 d << " expiryGloballyOn " << t.expiryGloballyOn;
274 d << " expiryMessagesWithInvalidDate " << t.expiryMessagesWithInvalidDate;
275 d << " daysToExpireRead " << t.daysToExpireRead;
276 d << " daysToExpireUnread " << t.daysToExpireUnread;
277 d << " mUnreadExpireUnits " << t.mUnreadExpireUnits;
278 d << " mReadExpireUnits " << t.mReadExpireUnits;
279 d << " mExpireAction " << t.mExpireAction;
280 d << " mExpireToFolderId " << t.mExpireToFolderId;
281 return d;
282}
283
284#include "moc_collectionexpirywidget.cpp"
bool isValid() const
const T * attribute() const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
KLocalizedString KI18N_EXPORT ki18ncp(const char *context, const char *singular, const char *plural)
QString i18n(const char *text, const TYPE &arg...)
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
void setupSpinBoxFormatString(T *spinBox, const KLocalizedString &formatString)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
The filter dialog.
bool isChecked() const const
void clicked(bool checked)
void toggled(bool checked)
void setSpecialValueText(const QString &txt)
Q_EMITQ_EMIT
QObject * parent() const const
void setMaximum(int max)
virtual QString textFromValue(int value) const const
virtual QValidator::State validate(QString &text, int &pos) const const override
void valueChanged(int i)
virtual int valueFromText(const QString &text) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setEnabled(bool)
virtual void setVisible(bool visible)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Sep 27 2024 12:04:09 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.