File indexing completed on 2024-12-22 05:00:51

0001 /*
0002    SPDX-FileCopyrightText: 2015-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "archivemailwidget.h"
0008 #include "addarchivemaildialog.h"
0009 #include "archivemailagentutil.h"
0010 #include "archivemailkernel.h"
0011 
0012 #include <KIO/JobUiDelegateFactory>
0013 #include <KIO/OpenUrlJob>
0014 
0015 #include "kmail-version.h"
0016 
0017 #include <MailCommon/MailKernel>
0018 #include <MailCommon/MailUtil>
0019 
0020 #include <KAboutData>
0021 #include <KConfigGroup>
0022 #include <KLocalizedString>
0023 #include <KMessageBox>
0024 #include <KSharedConfig>
0025 #include <QLocale>
0026 #include <QMenu>
0027 
0028 namespace
0029 {
0030 inline QString archiveMailCollectionPattern()
0031 {
0032     return QStringLiteral("ArchiveMailCollection \\d+");
0033 }
0034 
0035 static const char myConfigGroupName[] = "ArchiveMailDialog";
0036 }
0037 
0038 ArchiveMailItem::ArchiveMailItem(QTreeWidget *parent)
0039     : QTreeWidgetItem(parent)
0040 {
0041 }
0042 
0043 ArchiveMailItem::~ArchiveMailItem()
0044 {
0045     delete mInfo;
0046 }
0047 
0048 void ArchiveMailItem::setInfo(ArchiveMailInfo *info)
0049 {
0050     mInfo = info;
0051 }
0052 
0053 ArchiveMailInfo *ArchiveMailItem::info() const
0054 {
0055     return mInfo;
0056 }
0057 
0058 ArchiveMailWidget::ArchiveMailWidget(const KSharedConfigPtr &config, QWidget *parent, const QVariantList &args)
0059     : Akonadi::AgentConfigurationBase(config, parent, args)
0060 {
0061     ArchiveMailKernel *archiveMailKernel = ArchiveMailKernel::self();
0062     CommonKernel->registerKernelIf(archiveMailKernel); // register KernelIf early, it is used by the Filter classes
0063     CommonKernel->registerSettingsIf(archiveMailKernel); // SettingsIf is used in FolderTreeWidget
0064 
0065     auto w = new QWidget(parent);
0066     mWidget.setupUi(w);
0067     parent->layout()->addWidget(w);
0068 
0069     const QStringList headers = QStringList{i18n("Name"), i18n("Last archive"), i18n("Next archive in"), i18n("Storage directory")};
0070     mWidget.treeWidget->setHeaderLabels(headers);
0071     mWidget.treeWidget->setObjectName(QLatin1StringView("treewidget"));
0072     mWidget.treeWidget->setSortingEnabled(true);
0073     mWidget.treeWidget->setRootIsDecorated(false);
0074     mWidget.treeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
0075     mWidget.treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
0076 
0077     connect(mWidget.treeWidget, &QWidget::customContextMenuRequested, this, &ArchiveMailWidget::slotCustomContextMenuRequested);
0078 
0079     connect(mWidget.deleteItem, &QAbstractButton::clicked, this, &ArchiveMailWidget::slotDeleteItem);
0080     connect(mWidget.modifyItem, &QAbstractButton::clicked, this, &ArchiveMailWidget::slotModifyItem);
0081     connect(mWidget.addItem, &QAbstractButton::clicked, this, &ArchiveMailWidget::slotAddItem);
0082     connect(mWidget.treeWidget, &QTreeWidget::itemChanged, this, &ArchiveMailWidget::slotItemChanged);
0083     connect(mWidget.treeWidget, &QTreeWidget::itemSelectionChanged, this, &ArchiveMailWidget::updateButtons);
0084     connect(mWidget.treeWidget, &QTreeWidget::itemDoubleClicked, this, &ArchiveMailWidget::slotModifyItem);
0085     updateButtons();
0086 
0087     KAboutData aboutData(QStringLiteral("archivemailagent"),
0088                          i18n("Archive Mail Agent"),
0089                          QStringLiteral(KDEPIM_VERSION),
0090                          i18n("Archive emails automatically."),
0091                          KAboutLicense::GPL_V2,
0092                          i18n("Copyright (C) 2014-%1 Laurent Montel", QStringLiteral("2023")));
0093     aboutData.addAuthor(i18n("Laurent Montel"), i18n("Maintainer"), QStringLiteral("montel@kde.org"));
0094 
0095     aboutData.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), i18nc("EMAIL OF TRANSLATORS", "Your emails"));
0096     aboutData.setProductName(QByteArrayLiteral("Akonadi/Archive Mail Agent"));
0097     setKAboutData(aboutData);
0098 }
0099 
0100 ArchiveMailWidget::~ArchiveMailWidget() = default;
0101 
0102 void ArchiveMailWidget::slotCustomContextMenuRequested(const QPoint &)
0103 {
0104     const QList<QTreeWidgetItem *> listItems = mWidget.treeWidget->selectedItems();
0105     QMenu menu(parentWidget());
0106     menu.addAction(QIcon::fromTheme(QStringLiteral("list-add")), i18n("Add..."), this, &ArchiveMailWidget::slotAddItem);
0107     if (!listItems.isEmpty()) {
0108         if (listItems.count() == 1) {
0109             menu.addSeparator();
0110             menu.addAction(mWidget.modifyItem->text(), this, &ArchiveMailWidget::slotModifyItem);
0111             menu.addSeparator();
0112             menu.addAction(i18n("Open Containing Folder..."), this, &ArchiveMailWidget::slotOpenFolder);
0113         }
0114         menu.addSeparator();
0115         menu.addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete"), this, &ArchiveMailWidget::slotDeleteItem);
0116     }
0117     menu.exec(QCursor::pos());
0118 }
0119 
0120 void ArchiveMailWidget::updateButtons()
0121 {
0122     const QList<QTreeWidgetItem *> listItems = mWidget.treeWidget->selectedItems();
0123     if (listItems.isEmpty()) {
0124         mWidget.deleteItem->setEnabled(false);
0125         mWidget.modifyItem->setEnabled(false);
0126     } else if (listItems.count() == 1) {
0127         mWidget.deleteItem->setEnabled(true);
0128         mWidget.modifyItem->setEnabled(true);
0129     } else {
0130         mWidget.deleteItem->setEnabled(true);
0131         mWidget.modifyItem->setEnabled(false);
0132     }
0133 }
0134 
0135 void ArchiveMailWidget::needReloadConfig()
0136 {
0137     // TODO add messagebox which informs that we save settings here.
0138     mWidget.treeWidget->clear();
0139     load();
0140 }
0141 
0142 void ArchiveMailWidget::load()
0143 {
0144     const auto group = config()->group(QLatin1StringView(myConfigGroupName));
0145     mWidget.treeWidget->header()->restoreState(group.readEntry("HeaderState", QByteArray()));
0146 
0147     const QStringList collectionList = config()->groupList().filter(QRegularExpression(archiveMailCollectionPattern()));
0148     const int numberOfCollection = collectionList.count();
0149     for (int i = 0; i < numberOfCollection; ++i) {
0150         KConfigGroup collectionGroup = config()->group(collectionList.at(i));
0151         auto info = new ArchiveMailInfo(collectionGroup);
0152         if (info->isValid()) {
0153             createOrUpdateItem(info);
0154         } else {
0155             delete info;
0156         }
0157     }
0158 }
0159 
0160 void ArchiveMailWidget::createOrUpdateItem(ArchiveMailInfo *info, ArchiveMailItem *item)
0161 {
0162     if (!item) {
0163         item = new ArchiveMailItem(mWidget.treeWidget);
0164     }
0165     const QString folderName = i18n("Folder: %1", MailCommon::Util::fullCollectionPath(Akonadi::Collection(info->saveCollectionId())));
0166     item->setText(ArchiveMailWidget::Name, folderName);
0167     item->setToolTip(ArchiveMailWidget::Name, folderName);
0168     item->setCheckState(ArchiveMailWidget::Name, info->isEnabled() ? Qt::Checked : Qt::Unchecked);
0169     const QString path{info->url().toLocalFile()};
0170     item->setText(ArchiveMailWidget::StorageDirectory, path);
0171     item->setToolTip(ArchiveMailWidget::StorageDirectory, path);
0172     if (info->lastDateSaved().isValid()) {
0173         const QString date{QLocale().toString(info->lastDateSaved(), QLocale::ShortFormat)};
0174         item->setText(ArchiveMailWidget::LastArchiveDate, date);
0175         item->setToolTip(ArchiveMailWidget::LastArchiveDate, date);
0176         updateDiffDate(item, info);
0177     } else {
0178         item->setBackground(ArchiveMailWidget::NextArchive, Qt::green);
0179     }
0180     item->setInfo(info);
0181 }
0182 
0183 void ArchiveMailWidget::updateDiffDate(ArchiveMailItem *item, ArchiveMailInfo *info)
0184 {
0185     const QDate diffDate = ArchiveMailAgentUtil::diffDate(info);
0186     const qint64 diff = QDate::currentDate().daysTo(diffDate);
0187     const QString dateStr{i18np("Tomorrow", "%1 days", diff)};
0188     item->setText(ArchiveMailWidget::NextArchive, dateStr);
0189     if (diff < 0) {
0190         if (info->isEnabled()) {
0191             item->setBackground(ArchiveMailWidget::NextArchive, Qt::red);
0192         } else {
0193             item->setBackground(ArchiveMailWidget::NextArchive, Qt::lightGray);
0194         }
0195     } else {
0196         item->setToolTip(ArchiveMailWidget::NextArchive, i18n("Archive will be done %1", QLocale().toString(diffDate, QLocale::ShortFormat)));
0197     }
0198 }
0199 
0200 bool ArchiveMailWidget::save() const
0201 {
0202     if (!mChanged) {
0203         return false;
0204     }
0205 
0206     // first, delete all filter groups:
0207     const QStringList filterGroups = config()->groupList().filter(QRegularExpression(archiveMailCollectionPattern()));
0208 
0209     for (const QString &group : filterGroups) {
0210         config()->deleteGroup(group);
0211     }
0212 
0213     const int numberOfItem(mWidget.treeWidget->topLevelItemCount());
0214     for (int i = 0; i < numberOfItem; ++i) {
0215         auto mailItem = static_cast<ArchiveMailItem *>(mWidget.treeWidget->topLevelItem(i));
0216         if (mailItem->info()) {
0217             KConfigGroup group = config()->group(ArchiveMailAgentUtil::archivePattern.arg(mailItem->info()->saveCollectionId()));
0218             mailItem->info()->writeConfig(group);
0219         }
0220     }
0221 
0222     auto group = config()->group(QLatin1StringView(myConfigGroupName));
0223     group.writeEntry("HeaderState", mWidget.treeWidget->header()->saveState());
0224 
0225     return true;
0226 }
0227 
0228 void ArchiveMailWidget::slotDeleteItem()
0229 {
0230     const QList<QTreeWidgetItem *> listItems = mWidget.treeWidget->selectedItems();
0231     const int answer = KMessageBox::warningTwoActions(parentWidget(),
0232                                                       i18n("Do you want to delete the selected items?"),
0233                                                       i18nc("@title:window", "Delete Items"),
0234                                                       KStandardGuiItem::del(),
0235                                                       KStandardGuiItem::cancel());
0236     if (answer == KMessageBox::ButtonCode::SecondaryAction) {
0237         return;
0238     }
0239 
0240     for (QTreeWidgetItem *item : listItems) {
0241         delete item;
0242     }
0243     mChanged = true;
0244     updateButtons();
0245 }
0246 
0247 void ArchiveMailWidget::slotModifyItem()
0248 {
0249     const QList<QTreeWidgetItem *> listItems = mWidget.treeWidget->selectedItems();
0250     if (listItems.count() == 1) {
0251         QTreeWidgetItem *item = listItems.at(0);
0252         if (!item) {
0253             return;
0254         }
0255         auto archiveItem = static_cast<ArchiveMailItem *>(item);
0256         QPointer<AddArchiveMailDialog> dialog = new AddArchiveMailDialog(archiveItem->info(), parentWidget());
0257         if (dialog->exec()) {
0258             ArchiveMailInfo *info = dialog->info();
0259             createOrUpdateItem(info, archiveItem);
0260             mChanged = true;
0261         }
0262         delete dialog;
0263     }
0264 }
0265 
0266 void ArchiveMailWidget::slotAddItem()
0267 {
0268     QPointer<AddArchiveMailDialog> dialog = new AddArchiveMailDialog(nullptr, parentWidget());
0269     if (dialog->exec()) {
0270         ArchiveMailInfo *info = dialog->info();
0271         if (verifyExistingArchive(info)) {
0272             KMessageBox::error(parentWidget(),
0273                                i18n("Cannot add a second archive for this folder. Modify the existing one instead."),
0274                                i18nc("@title:window", "Add Archive Mail"));
0275             delete info;
0276         } else {
0277             createOrUpdateItem(info);
0278             updateButtons();
0279             mChanged = true;
0280         }
0281     }
0282     delete dialog;
0283 }
0284 
0285 bool ArchiveMailWidget::verifyExistingArchive(ArchiveMailInfo *info) const
0286 {
0287     const int numberOfItem(mWidget.treeWidget->topLevelItemCount());
0288     for (int i = 0; i < numberOfItem; ++i) {
0289         auto mailItem = static_cast<ArchiveMailItem *>(mWidget.treeWidget->topLevelItem(i));
0290         ArchiveMailInfo *archiveItemInfo = mailItem->info();
0291         if (archiveItemInfo) {
0292             if (info->saveCollectionId() == archiveItemInfo->saveCollectionId()) {
0293                 return true;
0294             }
0295         }
0296     }
0297     return false;
0298 }
0299 
0300 void ArchiveMailWidget::slotOpenFolder()
0301 {
0302     const QList<QTreeWidgetItem *> listItems = mWidget.treeWidget->selectedItems();
0303     if (listItems.count() == 1) {
0304         QTreeWidgetItem *item = listItems.first();
0305         if (!item) {
0306             return;
0307         }
0308         auto archiveItem = static_cast<ArchiveMailItem *>(item);
0309         ArchiveMailInfo *archiveItemInfo = archiveItem->info();
0310         if (archiveItemInfo) {
0311             const QUrl url = archiveItemInfo->url();
0312             auto job = new KIO::OpenUrlJob(url);
0313             job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, parentWidget()));
0314             job->setRunExecutables(false);
0315             job->start();
0316         }
0317     }
0318 }
0319 
0320 void ArchiveMailWidget::slotItemChanged(QTreeWidgetItem *item, int col)
0321 {
0322     if (item) {
0323         auto archiveItem = static_cast<ArchiveMailItem *>(item);
0324         if (archiveItem->info()) {
0325             if (col == ArchiveMailWidget::Name) {
0326                 archiveItem->info()->setEnabled(archiveItem->checkState(ArchiveMailWidget::Name) == Qt::Checked);
0327                 mChanged = true;
0328             } else if (col == ArchiveMailWidget::NextArchive) {
0329                 updateDiffDate(archiveItem, archiveItem->info());
0330             }
0331         }
0332     }
0333 }
0334 
0335 QSize ArchiveMailWidget::restoreDialogSize() const
0336 {
0337     auto group = config()->group(QLatin1StringView(myConfigGroupName));
0338     const QSize size = group.readEntry("Size", QSize(500, 300));
0339     return size;
0340 }
0341 
0342 void ArchiveMailWidget::saveDialogSize(const QSize &size)
0343 {
0344     auto group = config()->group(QLatin1StringView(myConfigGroupName));
0345     group.writeEntry("Size", size);
0346 }
0347 
0348 #include "moc_archivemailwidget.cpp"