File indexing completed on 2024-05-12 05:20:46
0001 /* 0002 SPDX-FileCopyrightText: 2018-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "unityservicemanager.h" 0008 #include "kmail_debug.h" 0009 #include "kmkernel.h" 0010 #include "kmsystemtray.h" 0011 #include "settings/kmailsettings.h" 0012 #include <MailCommon/MailKernel> 0013 #include <MailCommon/MailUtil> 0014 0015 #include <QApplication> 0016 #include <QDBusConnection> 0017 #include <QDBusConnectionInterface> 0018 #include <QDBusMessage> 0019 #include <QDBusPendingCallWatcher> 0020 #include <QDBusPendingReply> 0021 #include <QDBusServiceWatcher> 0022 #include <QTimer> 0023 0024 #include <Akonadi/ChangeRecorder> 0025 #include <Akonadi/CollectionStatistics> 0026 #include <Akonadi/EntityMimeTypeFilterModel> 0027 #include <Akonadi/EntityTreeModel> 0028 #include <Akonadi/NewMailNotifierAttribute> 0029 #include <chrono> 0030 0031 using namespace std::chrono_literals; 0032 0033 using namespace KMail; 0034 0035 UnityServiceManager::UnityServiceManager(QObject *parent) 0036 : QObject(parent) 0037 , mUnityServiceWatcher(new QDBusServiceWatcher(this)) 0038 { 0039 connect(kmkernel->folderCollectionMonitor(), &Akonadi::Monitor::collectionStatisticsChanged, this, &UnityServiceManager::slotCollectionStatisticsChanged); 0040 0041 connect(kmkernel->folderCollectionMonitor(), &Akonadi::Monitor::collectionAdded, this, &UnityServiceManager::initListOfCollection); 0042 connect(kmkernel->folderCollectionMonitor(), &Akonadi::Monitor::collectionRemoved, this, &UnityServiceManager::initListOfCollection); 0043 connect(kmkernel->folderCollectionMonitor(), &Akonadi::Monitor::collectionSubscribed, this, &UnityServiceManager::initListOfCollection); 0044 connect(kmkernel->folderCollectionMonitor(), &Akonadi::Monitor::collectionUnsubscribed, this, &UnityServiceManager::initListOfCollection); 0045 initListOfCollection(); 0046 initUnity(); 0047 } 0048 0049 UnityServiceManager::~UnityServiceManager() 0050 { 0051 mSystemTray = nullptr; 0052 } 0053 0054 bool UnityServiceManager::excludeFolder(const Akonadi::Collection &collection) const 0055 { 0056 if (!collection.isValid() || !collection.contentMimeTypes().contains(KMime::Message::mimeType())) { 0057 return true; 0058 } 0059 if (CommonKernel->outboxCollectionFolder() == collection || CommonKernel->sentCollectionFolder() == collection 0060 || CommonKernel->templatesCollectionFolder() == collection || CommonKernel->trashCollectionFolder() == collection 0061 || CommonKernel->draftsCollectionFolder() == collection) { 0062 return true; 0063 } 0064 0065 if (MailCommon::Util::isVirtualCollection(collection)) { 0066 return true; 0067 } 0068 return false; 0069 } 0070 0071 void UnityServiceManager::unreadMail(const QAbstractItemModel *model, const QModelIndex &parentIndex) 0072 { 0073 const int rowCount = model->rowCount(parentIndex); 0074 for (int row = 0; row < rowCount; ++row) { 0075 const QModelIndex index = model->index(row, 0, parentIndex); 0076 const auto collection = model->data(index, Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>(); 0077 0078 if (!excludeFolder(collection)) { 0079 const Akonadi::CollectionStatistics statistics = collection.statistics(); 0080 const qint64 count = qMax(0LL, statistics.unreadCount()); 0081 0082 if (count > 0) { 0083 if (!ignoreNewMailInFolder(collection)) { 0084 mCount += count; 0085 } 0086 } 0087 } 0088 if (model->hasChildren(index)) { 0089 unreadMail(model, index); 0090 } 0091 } 0092 if (mSystemTray) { 0093 // Update tooltip to reflect count of unread messages 0094 mSystemTray->updateToolTip(mCount); 0095 } 0096 } 0097 0098 void UnityServiceManager::updateSystemTray() 0099 { 0100 initListOfCollection(); 0101 } 0102 0103 void UnityServiceManager::initListOfCollection() 0104 { 0105 mCount = 0; 0106 const QAbstractItemModel *model = kmkernel->collectionModel(); 0107 if (model->rowCount() == 0) { 0108 QTimer::singleShot(1s, this, &UnityServiceManager::initListOfCollection); 0109 return; 0110 } 0111 unreadMail(model); 0112 if (mSystemTray) { 0113 mSystemTray->updateStatus(mCount); 0114 } 0115 0116 // qCDebug(KMAIL_LOG)<<" mCount :"<<mCount; 0117 updateCount(); 0118 } 0119 0120 void UnityServiceManager::slotCollectionStatisticsChanged(Akonadi::Collection::Id id, const Akonadi::CollectionStatistics &) 0121 { 0122 // Exclude sent mail folder 0123 0124 if (CommonKernel->outboxCollectionFolder().id() == id || CommonKernel->sentCollectionFolder().id() == id 0125 || CommonKernel->templatesCollectionFolder().id() == id || CommonKernel->trashCollectionFolder().id() == id 0126 || CommonKernel->draftsCollectionFolder().id() == id) { 0127 return; 0128 } 0129 initListOfCollection(); 0130 } 0131 0132 void UnityServiceManager::updateCount() 0133 { 0134 if (mSystemTray) { 0135 mSystemTray->updateCount(mCount); 0136 } 0137 0138 if (mUnityServiceAvailable) { 0139 const QString launcherId = qApp->desktopFileName() + QLatin1StringView(".desktop"); 0140 const int unreadEmail = KMailSettings::self()->showUnreadInTaskbar() ? mCount : 0; 0141 const QVariantMap properties{{QStringLiteral("count-visible"), unreadEmail > 0}, {QStringLiteral("count"), unreadEmail}}; 0142 0143 QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/org/kmail2/UnityLauncher"), 0144 QStringLiteral("com.canonical.Unity.LauncherEntry"), 0145 QStringLiteral("Update")); 0146 message.setArguments({launcherId, properties}); 0147 QDBusConnection::sessionBus().send(message); 0148 } 0149 } 0150 0151 void UnityServiceManager::setSystemTryAssociatedWindow(QWindow *window) 0152 { 0153 if (!mSystemTray) { 0154 return; 0155 } 0156 mSystemTray->setAssociatedWindow(window); 0157 } 0158 0159 void UnityServiceManager::initUnity() 0160 { 0161 mUnityServiceWatcher->setConnection(QDBusConnection::sessionBus()); 0162 mUnityServiceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration | QDBusServiceWatcher::WatchForRegistration); 0163 mUnityServiceWatcher->addWatchedService(QStringLiteral("com.canonical.Unity")); 0164 connect(mUnityServiceWatcher, &QDBusServiceWatcher::serviceRegistered, this, [this](const QString &service) { 0165 Q_UNUSED(service) 0166 mUnityServiceAvailable = true; 0167 updateCount(); 0168 }); 0169 0170 connect(mUnityServiceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, [this](const QString &service) { 0171 Q_UNUSED(service) 0172 mUnityServiceAvailable = false; 0173 }); 0174 0175 // QDBusConnectionInterface::isServiceRegistered blocks 0176 QDBusPendingCall listNamesCall = QDBusConnection::sessionBus().interface()->asyncCall(QStringLiteral("ListNames")); 0177 auto callWatcher = new QDBusPendingCallWatcher(listNamesCall, this); 0178 connect(callWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { 0179 QDBusPendingReply<QStringList> reply = *watcher; 0180 watcher->deleteLater(); 0181 0182 if (reply.isError()) { 0183 qCWarning(KMAIL_LOG) << "DBus reported an error " << reply.error().message(); 0184 return; 0185 } 0186 0187 const QStringList &services = reply.value(); 0188 0189 mUnityServiceAvailable = services.contains(QLatin1StringView("com.canonical.Unity")); 0190 if (mUnityServiceAvailable) { 0191 updateCount(); 0192 } 0193 }); 0194 } 0195 0196 bool UnityServiceManager::ignoreNewMailInFolder(const Akonadi::Collection &collection) 0197 { 0198 if (collection.hasAttribute<Akonadi::NewMailNotifierAttribute>()) { 0199 if (collection.attribute<Akonadi::NewMailNotifierAttribute>()->ignoreNewMail()) { 0200 return true; 0201 } 0202 } 0203 return false; 0204 } 0205 0206 bool UnityServiceManager::haveSystemTrayApplet() const 0207 { 0208 return mSystemTray != nullptr; 0209 } 0210 0211 bool UnityServiceManager::hasUnreadMail() const 0212 { 0213 return mCount != 0; 0214 } 0215 0216 bool UnityServiceManager::canQueryClose() 0217 { 0218 if (!mSystemTray) { 0219 return true; 0220 } 0221 if (hasUnreadMail()) { 0222 mSystemTray->setStatus(KStatusNotifierItem::Active); 0223 } 0224 mSystemTray->hideKMail(); 0225 return false; 0226 } 0227 0228 void UnityServiceManager::toggleSystemTray(QWidget *widget) 0229 { 0230 if (widget) { 0231 if (!mSystemTray && KMailSettings::self()->systemTrayEnabled()) { 0232 mSystemTray = new KMail::KMSystemTray(widget); 0233 mSystemTray->setUnityServiceManager(this); 0234 mSystemTray->initialize(mCount); 0235 } else if (mSystemTray && !KMailSettings::self()->systemTrayEnabled()) { 0236 // Get rid of system tray on user's request 0237 qCDebug(KMAIL_LOG) << "deleting systray"; 0238 delete mSystemTray; 0239 mSystemTray = nullptr; 0240 } 0241 } 0242 } 0243 0244 #include "moc_unityservicemanager.cpp"