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"