File indexing completed on 2024-12-22 04:56:53
0001 /* 0002 SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "newmailnotifierselectcollectionwidget.h" 0008 0009 #include <Akonadi/AttributeFactory> 0010 #include <Akonadi/CollectionFilterProxyModel> 0011 #include <Akonadi/CollectionModifyJob> 0012 #include <Akonadi/NewMailNotifierAttribute> 0013 #include <QSortFilterProxyModel> 0014 0015 #include <Akonadi/ChangeRecorder> 0016 #include <Akonadi/EntityTreeModel> 0017 #include <KLineEditEventHandler> 0018 #include <KMime/Message> 0019 0020 #include "newmailnotifier_debug.h" 0021 #include <KLineEdit> 0022 #include <KLocalizedString> 0023 #include <QPushButton> 0024 0025 #include <QHBoxLayout> 0026 #include <QLabel> 0027 #include <QTreeView> 0028 #include <QVBoxLayout> 0029 0030 NewMailNotifierCollectionProxyModel::NewMailNotifierCollectionProxyModel(QObject *parent) 0031 : QIdentityProxyModel(parent) 0032 { 0033 } 0034 0035 QVariant NewMailNotifierCollectionProxyModel::data(const QModelIndex &index, int role) const 0036 { 0037 if (role == Qt::CheckStateRole) { 0038 if (index.isValid()) { 0039 const auto collection = data(index, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>(); 0040 // Make top-level collections uncheckable 0041 if (collection.parentCollection() == Akonadi::Collection::root()) { 0042 return {}; 0043 } 0044 if (mNotificationCollection.contains(collection)) { 0045 return mNotificationCollection.value(collection) ? Qt::Checked : Qt::Unchecked; 0046 } else { 0047 const auto attr = collection.attribute<Akonadi::NewMailNotifierAttribute>(); 0048 if (!attr || !attr->ignoreNewMail()) { 0049 return Qt::Checked; 0050 } 0051 return Qt::Unchecked; 0052 } 0053 } 0054 } 0055 return QIdentityProxyModel::data(index, role); 0056 } 0057 0058 bool NewMailNotifierCollectionProxyModel::setData(const QModelIndex &index, const QVariant &value, int role) 0059 { 0060 if (role == Qt::CheckStateRole) { 0061 if (index.isValid()) { 0062 const auto collection = data(index, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>(); 0063 mNotificationCollection[collection] = (value == Qt::Checked); 0064 Q_EMIT dataChanged(index, index); 0065 return true; 0066 } 0067 } 0068 0069 return QIdentityProxyModel::setData(index, value, role); 0070 } 0071 0072 Qt::ItemFlags NewMailNotifierCollectionProxyModel::flags(const QModelIndex &index) const 0073 { 0074 if (index.isValid()) { 0075 return QIdentityProxyModel::flags(index) | Qt::ItemIsUserCheckable; 0076 } else { 0077 return QIdentityProxyModel::flags(index); 0078 } 0079 } 0080 0081 QHash<Akonadi::Collection, bool> NewMailNotifierCollectionProxyModel::notificationCollection() const 0082 { 0083 return mNotificationCollection; 0084 } 0085 0086 NewMailNotifierSelectCollectionWidget::NewMailNotifierSelectCollectionWidget(QWidget *parent) 0087 : QWidget(parent) 0088 , mFolderView(new QTreeView(this)) 0089 , mChangeRecorder(new Akonadi::ChangeRecorder(this)) 0090 , mCollectionFilter(new QSortFilterProxyModel(this)) 0091 , mNewMailNotifierProxyModel(new NewMailNotifierCollectionProxyModel(this)) 0092 { 0093 Akonadi::AttributeFactory::registerAttribute<Akonadi::NewMailNotifierAttribute>(); 0094 auto vbox = new QVBoxLayout(this); 0095 0096 auto label = new QLabel(i18n("Select which folders to monitor for new message notifications:")); 0097 vbox->addWidget(label); 0098 0099 // Create a new change recorder. 0100 mChangeRecorder->setMimeTypeMonitored(KMime::Message::mimeType()); 0101 mChangeRecorder->fetchCollection(true); 0102 mChangeRecorder->setAllMonitored(true); 0103 0104 mModel = new Akonadi::EntityTreeModel(mChangeRecorder, this); 0105 // Set the model to show only collections, not items. 0106 mModel->setItemPopulationStrategy(Akonadi::EntityTreeModel::NoItemPopulation); 0107 connect(mModel, &Akonadi::EntityTreeModel::collectionTreeFetched, this, &NewMailNotifierSelectCollectionWidget::slotCollectionTreeFetched); 0108 0109 auto mimeTypeProxy = new Akonadi::CollectionFilterProxyModel(this); 0110 mimeTypeProxy->setExcludeVirtualCollections(true); 0111 mimeTypeProxy->setDynamicSortFilter(true); 0112 mimeTypeProxy->addMimeTypeFilters(QStringList() << KMime::Message::mimeType()); 0113 mimeTypeProxy->setSourceModel(mModel); 0114 0115 mNewMailNotifierProxyModel->setSourceModel(mimeTypeProxy); 0116 0117 mCollectionFilter->setRecursiveFilteringEnabled(true); 0118 mCollectionFilter->setSourceModel(mNewMailNotifierProxyModel); 0119 mCollectionFilter->setDynamicSortFilter(true); 0120 mCollectionFilter->setFilterCaseSensitivity(Qt::CaseInsensitive); 0121 mCollectionFilter->setSortRole(Qt::DisplayRole); 0122 mCollectionFilter->setSortCaseSensitivity(Qt::CaseSensitive); 0123 mCollectionFilter->setSortLocaleAware(true); 0124 0125 auto searchLine = new KLineEdit(this); 0126 KLineEditEventHandler::catchReturnKey(searchLine); 0127 searchLine->setPlaceholderText(i18n("Search...")); 0128 searchLine->setClearButtonEnabled(true); 0129 connect(searchLine, &QLineEdit::textChanged, this, &NewMailNotifierSelectCollectionWidget::slotSetCollectionFilter); 0130 0131 vbox->addWidget(searchLine); 0132 0133 mFolderView->setEditTriggers(QAbstractItemView::NoEditTriggers); 0134 mFolderView->setAlternatingRowColors(true); 0135 vbox->addWidget(mFolderView); 0136 0137 mFolderView->setModel(mCollectionFilter); 0138 0139 auto hbox = new QHBoxLayout; 0140 vbox->addLayout(hbox); 0141 0142 auto button = new QPushButton(i18n("&Select All"), this); 0143 connect(button, &QPushButton::clicked, this, &NewMailNotifierSelectCollectionWidget::slotSelectAllCollections); 0144 hbox->addWidget(button); 0145 0146 button = new QPushButton(i18n("&Unselect All"), this); 0147 connect(button, &QPushButton::clicked, this, &NewMailNotifierSelectCollectionWidget::slotUnselectAllCollections); 0148 hbox->addWidget(button); 0149 hbox->addStretch(1); 0150 } 0151 0152 NewMailNotifierSelectCollectionWidget::~NewMailNotifierSelectCollectionWidget() = default; 0153 0154 void NewMailNotifierSelectCollectionWidget::slotCollectionTreeFetched() 0155 { 0156 mCollectionFilter->sort(0, Qt::AscendingOrder); 0157 mFolderView->expandAll(); 0158 } 0159 0160 void NewMailNotifierSelectCollectionWidget::slotSetCollectionFilter(const QString &filter) 0161 { 0162 mCollectionFilter->setFilterWildcard(filter); 0163 mFolderView->expandAll(); 0164 } 0165 0166 void NewMailNotifierSelectCollectionWidget::slotSelectAllCollections() 0167 { 0168 forceStatus(QModelIndex(), true); 0169 } 0170 0171 void NewMailNotifierSelectCollectionWidget::slotUnselectAllCollections() 0172 { 0173 forceStatus(QModelIndex(), false); 0174 } 0175 0176 void NewMailNotifierSelectCollectionWidget::forceStatus(const QModelIndex &parent, bool status) 0177 { 0178 const int nbCol = mNewMailNotifierProxyModel->rowCount(parent); 0179 for (int i = 0; i < nbCol; ++i) { 0180 const QModelIndex child = mNewMailNotifierProxyModel->index(i, 0, parent); 0181 mNewMailNotifierProxyModel->setData(child, status ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole); 0182 forceStatus(child, status); 0183 } 0184 } 0185 0186 void NewMailNotifierSelectCollectionWidget::updateCollectionsRecursive() 0187 { 0188 QHashIterator<Akonadi::Collection, bool> i(mNewMailNotifierProxyModel->notificationCollection()); 0189 while (i.hasNext()) { 0190 i.next(); 0191 Akonadi::Collection collection = i.key(); 0192 auto attr = collection.attribute<Akonadi::NewMailNotifierAttribute>(); 0193 Akonadi::CollectionModifyJob *modifyJob = nullptr; 0194 const bool selected = i.value(); 0195 if (selected && attr && attr->ignoreNewMail()) { 0196 collection.removeAttribute<Akonadi::NewMailNotifierAttribute>(); 0197 modifyJob = new Akonadi::CollectionModifyJob(collection); 0198 modifyJob->setProperty("AttributeAdded", true); 0199 } else if (!selected && (!attr || !attr->ignoreNewMail())) { 0200 attr = collection.attribute<Akonadi::NewMailNotifierAttribute>(Akonadi::Collection::AddIfMissing); 0201 attr->setIgnoreNewMail(true); 0202 modifyJob = new Akonadi::CollectionModifyJob(collection); 0203 modifyJob->setProperty("AttributeAdded", false); 0204 } 0205 0206 if (modifyJob) { 0207 connect(modifyJob, &Akonadi::CollectionModifyJob::finished, this, &NewMailNotifierSelectCollectionWidget::slotModifyJobDone); 0208 } 0209 } 0210 } 0211 0212 void NewMailNotifierSelectCollectionWidget::slotModifyJobDone(KJob *job) 0213 { 0214 auto modifyJob = qobject_cast<Akonadi::CollectionModifyJob *>(job); 0215 if (modifyJob && job->error()) { 0216 if (job->property("AttributeAdded").toBool()) { 0217 qCWarning(NEWMAILNOTIFIER_LOG) << "Failed to append NewMailNotifierAttribute to collection" << modifyJob->collection().id() << ":" 0218 << job->errorString(); 0219 } else { 0220 qCWarning(NEWMAILNOTIFIER_LOG) << "Failed to remove NewMailNotifierAttribute from collection" << modifyJob->collection().id() << ":" 0221 << job->errorString(); 0222 } 0223 } 0224 } 0225 0226 #include "moc_newmailnotifierselectcollectionwidget.cpp"