Mailcommon

collectionexpirywidget.cpp
1 /*
2  SPDX-FileCopyrightText: 2020-2022 Laurent Montel <[email protected]>
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 "mailcommon_debug.h"
14 #include "util/mailutil.h"
15 
16 #include <Akonadi/CollectionModifyJob>
17 
18 #include <KMessageBox>
19 #include <KPluralHandlingSpinBox>
20 #include <QCheckBox>
21 #include <QFormLayout>
22 #include <QGroupBox>
23 #include <QHBoxLayout>
24 #include <QPushButton>
25 #include <QRadioButton>
26 
27 using namespace MailCommon;
28 
29 class DaysSpinBox : public KPluralHandlingSpinBox
30 {
31 public:
32  DaysSpinBox(QWidget *parent)
33  : KPluralHandlingSpinBox(parent)
34  {
35  setMaximum(999999);
36  setSuffix(ki18ncp("Expire messages after %1", " day", " days"));
37  setSpecialValueText(i18n("Never"));
38  }
39 
40  Q_REQUIRED_RESULT QString textFromValue(int value) const override
41  {
42  if (value == 0) {
43  return i18n("Never");
44  }
46  }
47 
48  Q_REQUIRED_RESULT 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  }
58  return KPluralHandlingSpinBox::validate(text, pos);
59  }
60 };
61 
62 CollectionExpiryWidget::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(i18n("Save Settings and Expire Now"), this))
68  , mExpireMailWithInvalidDateCB(new QCheckBox(i18n("Expire messages with invalid date"), this))
69 {
70  auto formLayout = new QFormLayout(this);
71  formLayout->setContentsMargins({});
72 
73  connect(mExpireReadMailSB, &KPluralHandlingSpinBox::valueChanged, this, &CollectionExpiryWidget::slotChanged);
74  formLayout->addRow(i18n("Expire read messages after:"), mExpireReadMailSB);
75 
76  connect(mExpireUnreadMailSB, &KPluralHandlingSpinBox::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 
114 CollectionExpiryWidget::~CollectionExpiryWidget() = default;
115 
116 void CollectionExpiryWidget::hideExpireNowButton()
117 {
118  mExpireNowPB->setVisible(false);
119 }
120 
121 void 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 
132 void 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 
167 bool 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()) {
172  KMessageBox::error(this,
173  i18n("Please select a folder to expire messages into.\nIf this is not done, expired messages will be permanently deleted."),
174  i18n("No Folder Selected"));
175  mDeletePermanentlyRB->setChecked(true);
176  expireNow = false; // settings are not valid
177  }
178  return expireNow;
179 }
180 
181 MailCommon::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()) {
187  KMessageBox::error(this,
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  i18n("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 
204 CollectionExpirySettings 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 
225 void 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 
250 void CollectionExpiryWidget::save(Akonadi::Collection &collection, bool saveSettings, bool expireNow)
251 {
252  const CollectionExpirySettings collectionExpirySettings = settings();
253  save(collectionExpirySettings, collection, saveSettings, expireNow);
254 }
255 
256 bool 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 
262 bool 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 
269 QDebug 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 }
void clicked(bool checked)
QDataStream & operator<<(QDataStream &out, const KDateTime &dateTime)
virtual QString textFromValue(int value) const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void toggled(bool checked)
QString i18n(const char *text, const TYPE &arg...)
KLocalizedString KI18N_EXPORT ki18ncp(const char *context, const char *singular, const char *plural)
const T * attribute() const
virtual int valueFromText(const QString &text) const const
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
const QList< QKeySequence > & save()
bool isValid() const
virtual QValidator::State validate(QString &text, int &pos) const const override
void valueChanged(int i)
The filter dialog.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Sep 24 2022 03:58:14 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.