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 KLocalization::setupSpinBoxFormatString(this, ki18ncp("Expire messages after %1", "%v day", "%v days"));
37 setSpecialValueText(i18n("Never"));
38 }
39
40 [[nodiscard]] QString textFromValue(int value) const override
41 {
42 if (value == 0) {
43 return i18n("Never");
44 }
46 }
47
48 [[nodiscard]] int valueFromText(const QString &text) const override
49 {
51 }
52
53 QValidator::State validate(QString &text, int &pos) const override
54 {
55 if (text == i18n("Never")) {
57 }
59 }
60};
61
62CollectionExpiryWidget::CollectionExpiryWidget(QWidget *parent)
63 : QWidget(parent)
64 , mExpireReadMailSB(new DaysSpinBox(this))
65 , mExpireUnreadMailSB(new DaysSpinBox(this))
66 , mFolderSelector(new FolderRequester(this))
67 , mExpireNowPB(new QPushButton(i18nc("@action:button", "Save Settings and Expire Now"), this))
68 , mExpireMailWithInvalidDateCB(new QCheckBox(i18nc("@option:check", "Expire messages with invalid date"), this))
69{
70 auto formLayout = new QFormLayout(this);
71 formLayout->setContentsMargins({});
72
73 connect(mExpireReadMailSB, &QSpinBox::valueChanged, this, &CollectionExpiryWidget::slotChanged);
74 formLayout->addRow(i18n("Expire read messages after:"), mExpireReadMailSB);
75
76 connect(mExpireUnreadMailSB, &QSpinBox::valueChanged, this, &CollectionExpiryWidget::slotChanged);
77 formLayout->addRow(i18n("Expire unread messages after:"), mExpireUnreadMailSB);
78
79 connect(mExpireMailWithInvalidDateCB, &QCheckBox::toggled, this, &CollectionExpiryWidget::slotChanged);
80 formLayout->addRow(QString(), mExpireMailWithInvalidDateCB);
81
82 auto actionsGroup = new QGroupBox(this);
83 actionsGroup->setFlat(true); // for mutual exclusion of the radio buttons
84 formLayout->addRow(actionsGroup);
85
86 auto moveToHBox = new QHBoxLayout();
87 moveToHBox->setContentsMargins({});
88 moveToHBox->setSpacing(6);
89
90 mMoveToRB = new QRadioButton(actionsGroup);
91 mMoveToRB->setText(i18n("Move expired messages to:"));
92 connect(mMoveToRB, &QRadioButton::toggled, this, &CollectionExpiryWidget::slotChanged);
93 moveToHBox->addWidget(mMoveToRB);
94
95 mFolderSelector->setMustBeReadWrite(true);
96 mFolderSelector->setShowOutbox(false);
97 moveToHBox->addWidget(mFolderSelector);
98 formLayout->addRow(QString(), moveToHBox);
99 connect(mFolderSelector, &FolderRequester::folderChanged, this, &CollectionExpiryWidget::slotChanged);
100
101 mDeletePermanentlyRB = new QRadioButton(actionsGroup);
102 mDeletePermanentlyRB->setText(i18n("Delete expired messages permanently"));
103 connect(mDeletePermanentlyRB, &QRadioButton::toggled, this, &CollectionExpiryWidget::slotChanged);
104
105 formLayout->addRow(QString(), mDeletePermanentlyRB);
106
107 connect(mExpireNowPB, &QPushButton::clicked, this, &CollectionExpiryWidget::saveAndExpireRequested);
108 formLayout->addRow(QString(), mExpireNowPB);
109
110 mDeletePermanentlyRB->setChecked(true);
111 slotChanged();
112}
113
114CollectionExpiryWidget::~CollectionExpiryWidget() = default;
115
116void CollectionExpiryWidget::hideExpireNowButton()
117{
118 mExpireNowPB->setVisible(false);
119}
120
121void CollectionExpiryWidget::slotChanged()
122{
123 const bool showExpiryActions = mExpireReadMailSB->value() != 0 || mExpireUnreadMailSB->value() != 0;
124 mMoveToRB->setEnabled(showExpiryActions);
125 mFolderSelector->setEnabled(showExpiryActions && mMoveToRB->isChecked());
126 mDeletePermanentlyRB->setEnabled(showExpiryActions);
127 mExpireNowPB->setEnabled(showExpiryActions);
128
129 Q_EMIT configChanged();
130}
131
132void CollectionExpiryWidget::load(const MailCommon::CollectionExpirySettings &settings)
133{
134 if (settings.isValid()) {
135 bool expiryGloballyOn = settings.expiryGloballyOn;
136 if (expiryGloballyOn && settings.mReadExpireUnits != ExpireCollectionAttribute::ExpireNever && settings.daysToExpireRead >= 0) {
137 mExpireReadMailSB->setValue(settings.daysToExpireRead);
138 } else {
139 mExpireReadMailSB->setValue(0);
140 }
141 if (expiryGloballyOn && settings.mUnreadExpireUnits != ExpireCollectionAttribute::ExpireNever && settings.daysToExpireUnread >= 0) {
142 mExpireUnreadMailSB->setValue(settings.daysToExpireUnread);
143 } else {
144 mExpireUnreadMailSB->setValue(0);
145 }
146
147 if (settings.mExpireAction == ExpireCollectionAttribute::ExpireDelete) {
148 mDeletePermanentlyRB->setChecked(true);
149 } else {
150 mMoveToRB->setChecked(true);
151 }
152
153 mExpireMailWithInvalidDateCB->setChecked(settings.expiryMessagesWithInvalidDate);
154 Akonadi::Collection::Id destFolderID = settings.mExpireToFolderId;
155 if (destFolderID > 0) {
156 Akonadi::Collection destFolder = Kernel::self()->collectionFromId(destFolderID);
157 if (destFolder.isValid()) {
158 mFolderSelector->setCollection(destFolder);
159 }
160 }
161 } else {
162 mDeletePermanentlyRB->setChecked(true);
163 }
164 slotChanged();
165}
166
167bool CollectionExpiryWidget::validateExpireFolder(bool expireNow)
168{
169 const bool enableGlobally = mExpireReadMailSB->value() != 0 || mExpireUnreadMailSB->value() != 0;
170 const Akonadi::Collection expireToFolder = mFolderSelector->collection();
171 if (enableGlobally && mMoveToRB->isChecked() && !expireToFolder.isValid()) {
173 i18n("Please select a folder to expire messages into.\nIf this is not done, expired messages will be permanently deleted."),
174 i18nc("@title:window", "No Folder Selected"));
175 mDeletePermanentlyRB->setChecked(true);
176 expireNow = false; // settings are not valid
177 }
178 return expireNow;
179}
180
181MailCommon::ExpireCollectionAttribute *CollectionExpiryWidget::assignFolderAttribute(Akonadi::Collection &collection, bool &expireNow)
182{
183 const Akonadi::Collection expireToFolder = mFolderSelector->collection();
184 MailCommon::ExpireCollectionAttribute *attribute = nullptr;
185 if (expireToFolder.isValid() && mMoveToRB->isChecked()) {
186 if (expireToFolder.id() == collection.id()) {
188 i18n("Please select a different folder than the current folder to expire messages into.\nIf this is not done, expired messages "
189 "will be permanently deleted."),
190 i18nc("@title:window", "Wrong Folder Selected"));
191 mDeletePermanentlyRB->setChecked(true);
192 expireNow = false; // settings are not valid
193 } else {
194 attribute = collection.attribute<MailCommon::ExpireCollectionAttribute>(Akonadi::Collection::AddIfMissing);
195 attribute->setExpireToFolderId(expireToFolder.id());
196 }
197 }
198 if (!attribute) {
199 attribute = collection.attribute<MailCommon::ExpireCollectionAttribute>(Akonadi::Collection::AddIfMissing);
200 }
201 return attribute;
202}
203
204CollectionExpirySettings CollectionExpiryWidget::settings() const
205{
206 CollectionExpirySettings settings;
207 settings.expiryGloballyOn = mExpireReadMailSB->value() != 0 || mExpireUnreadMailSB->value() != 0;
208 settings.expiryMessagesWithInvalidDate = mExpireMailWithInvalidDateCB->isChecked();
209 // we always write out days now
210 settings.daysToExpireRead = mExpireReadMailSB->value();
211 settings.daysToExpireUnread = mExpireUnreadMailSB->value();
212 settings.mReadExpireUnits =
213 mExpireReadMailSB->value() != 0 ? MailCommon::ExpireCollectionAttribute::ExpireDays : MailCommon::ExpireCollectionAttribute::ExpireNever;
214 settings.mUnreadExpireUnits =
215 mExpireUnreadMailSB->value() != 0 ? MailCommon::ExpireCollectionAttribute::ExpireDays : MailCommon::ExpireCollectionAttribute::ExpireNever;
216
217 if (mDeletePermanentlyRB->isChecked()) {
218 settings.mExpireAction = ExpireCollectionAttribute::ExpireDelete;
219 } else {
220 settings.mExpireAction = ExpireCollectionAttribute::ExpireMove;
221 }
222 return settings;
223}
224
225void CollectionExpiryWidget::save(const CollectionExpirySettings &collectionExpirySettings, Akonadi::Collection &collection, bool saveSettings, bool expireNow)
226{
227 expireNow = validateExpireFolder(expireNow);
228 MailCommon::ExpireCollectionAttribute *attribute = assignFolderAttribute(collection, expireNow);
229 attribute->setAutoExpire(collectionExpirySettings.expiryGloballyOn);
230 // we always write out days now
231 attribute->setReadExpireAge(collectionExpirySettings.daysToExpireRead);
232 attribute->setUnreadExpireAge(collectionExpirySettings.daysToExpireUnread);
233 attribute->setReadExpireUnits(collectionExpirySettings.mReadExpireUnits);
234 attribute->setUnreadExpireUnits(collectionExpirySettings.mUnreadExpireUnits);
235 attribute->setExpireAction(collectionExpirySettings.mExpireAction);
236
237 if (saveSettings) {
238 auto job = new CollectionExpiryJob;
239 job->setExpireNow(expireNow);
240 job->setCollection(collection);
241 job->start();
242 } else {
243 if (expireNow) {
244 MailCommon::Util::expireOldMessages(collection, true /*immediate*/);
245 }
246 }
247 Q_EMIT configChanged(false);
248}
249
250void CollectionExpiryWidget::save(Akonadi::Collection &collection, bool saveSettings, bool expireNow)
251{
252 const CollectionExpirySettings collectionExpirySettings = settings();
253 save(collectionExpirySettings, collection, saveSettings, expireNow);
254}
255
256bool CollectionExpiryWidget::canHandle(const Akonadi::Collection &col)
257{
258 QSharedPointer<FolderSettings> fd = FolderSettings::forCollection(col, false);
259 return fd->canDeleteMessages() && !fd->isStructural() && !MailCommon::Util::isVirtualCollection(col);
260}
261
262bool CollectionExpirySettings::isValid() const
263{
264 const bool valid = daysToExpireRead != -1 || daysToExpireUnread != -1 || mUnreadExpireUnits != ExpireCollectionAttribute::ExpireNever
265 || mReadExpireUnits != ExpireCollectionAttribute::ExpireNever || mExpireAction != ExpireCollectionAttribute::ExpireDelete || mExpireToFolderId != -1;
266 return valid;
267}
268
269QDebug operator<<(QDebug d, const CollectionExpirySettings &t)
270{
271 d << " expiryGloballyOn " << t.expiryGloballyOn;
272 d << " expiryMessagesWithInvalidDate " << t.expiryMessagesWithInvalidDate;
273 d << " daysToExpireRead " << t.daysToExpireRead;
274 d << " daysToExpireUnread " << t.daysToExpireUnread;
275 d << " mUnreadExpireUnits " << t.mUnreadExpireUnits;
276 d << " mReadExpireUnits " << t.mReadExpireUnits;
277 d << " mExpireAction " << t.mExpireAction;
278 d << " mExpireToFolderId " << t.mExpireToFolderId;
279 return d;
280}
281
282#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 Nov 22 2024 12:12:19 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.