diff --git a/interfaces/org.freedesktop.Akonadi.NotificationManager.xml b/interfaces/org.freedesktop.Akonadi.NotificationManager.xml index 84855b35..183befe1 100644 --- a/interfaces/org.freedesktop.Akonadi.NotificationManager.xml +++ b/interfaces/org.freedesktop.Akonadi.NotificationManager.xml @@ -1,34 +1,50 @@ + + + + + + + + + + + + + + + + diff --git a/server/src/notificationmanager.cpp b/server/src/notificationmanager.cpp index ba222bbf..f876ed73 100644 --- a/server/src/notificationmanager.cpp +++ b/server/src/notificationmanager.cpp @@ -1,234 +1,262 @@ /* Copyright (c) 2006 - 2007 Volker Krause Copyright (c) 2010 Michael Jansen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "notificationmanager.h" #include #include "notificationmanageradaptor.h" #include "notificationsource.h" #include "tracer.h" #include "storage/datastore.h" #include "clientcapabilityaggregator.h" #include #include #include #include #include using namespace Akonadi; using namespace Akonadi::Server; NotificationManager *NotificationManager::mSelf = 0; NotificationManager::NotificationManager() - : QObject( 0 ) + : QObject( 0 ), + mNotificationCounter( 0 ) { NotificationMessage::registerDBusTypes(); NotificationMessageV2::registerDBusTypes(); NotificationMessageV3::registerDBusTypes(); new NotificationManagerAdaptor( this ); QDBusConnection::sessionBus().registerObject( QLatin1String( "/notifications" ), this, QDBusConnection::ExportAdaptors ); QDBusConnection::sessionBus().registerObject( QLatin1String( "/notifications/debug" ), this, QDBusConnection::ExportScriptableSlots ); const QString serverConfigFile = AkStandardDirs::serverConfigFile( XdgBaseDirs::ReadWrite ); QSettings settings( serverConfigFile, QSettings::IniFormat ); mTimer.setInterval( settings.value( QLatin1String( "NotificationManager/Interval" ), 50 ).toInt() ); mTimer.setSingleShot( true ); connect( &mTimer, SIGNAL(timeout()), SLOT(emitPendingNotifications()) ); } NotificationManager::~NotificationManager() { } NotificationManager *NotificationManager::self() { if ( !mSelf ) { mSelf = new NotificationManager(); } return mSelf; } void NotificationManager::connectNotificationCollector( NotificationCollector *collector ) { connect( collector, SIGNAL(notify(Akonadi::NotificationMessageV3::List)), SLOT(slotNotify(Akonadi::NotificationMessageV3::List)) ); } void NotificationManager::slotNotify( const Akonadi::NotificationMessageV3::List &msgs ) { //akDebug() << Q_FUNC_INFO << "Appending" << msgs.count() << "notifications to current list of " << mNotifications.count() << "notifications"; + mNotificationCounter += msgs.count(); + Q_FOREACH ( const NotificationMessageV3 &msg, msgs ) NotificationMessageV3::appendAndCompress( mNotifications, msg ); //akDebug() << Q_FUNC_INFO << "We have" << mNotifications.count() << "notifications queued in total after appendAndCompress()"; if ( !mTimer.isActive() ) { mTimer.start(); } } void NotificationManager::emitPendingNotifications() { if ( mNotifications.isEmpty() ) { return; } NotificationMessage::List legacyNotifications; Q_FOREACH ( const NotificationMessageV3 ¬ification, mNotifications ) { Tracer::self()->signal( "NotificationManager::notify", notification.toString() ); if ( ClientCapabilityAggregator::minimumNotificationMessageVersion() < 2 ) { const NotificationMessage::List tmp = notification.toNotificationV1().toList(); Q_FOREACH ( const NotificationMessage &legacyNotification, tmp ) { bool appended = false; NotificationMessage::appendAndCompress( legacyNotifications, legacyNotification, &appended ); if ( !appended ) { legacyNotifications << legacyNotification; } } } } if ( !legacyNotifications.isEmpty() ) { Q_FOREACH ( NotificationSource *src, mNotificationSources ) { src->emitNotification( legacyNotifications ); } } NotificationMessageV2::List v2List; if ( ClientCapabilityAggregator::maximumNotificationMessageVersion() == 2 ) { v2List = NotificationMessageV3::toV2List( mNotifications ); } if ( ClientCapabilityAggregator::maximumNotificationMessageVersion() > 1 ) { Q_FOREACH ( NotificationSource *source, mNotificationSources ) { if ( !source->isServerSideMonitorEnabled() ) { if ( ClientCapabilityAggregator::maximumNotificationMessageVersion() == 2 ) { source->emitNotification( v2List ); } else { source->emitNotification( mNotifications ); } continue; } NotificationMessageV3::List acceptedNotifications; Q_FOREACH ( const NotificationMessageV3 ¬ification, mNotifications ) { if ( source->acceptsNotification( notification ) ) { acceptedNotifications << notification; } } if ( !acceptedNotifications.isEmpty() ) { if ( ClientCapabilityAggregator::maximumNotificationMessageVersion() == 2 ) { source->emitNotification( NotificationMessageV3::toV2List( acceptedNotifications ) ); } else { source->emitNotification( acceptedNotifications ); } } } } // backward compatibility with the old non-subcription interface // FIXME: Can we drop this already? if ( !legacyNotifications.isEmpty() ) { Q_EMIT notify( legacyNotifications ); } mNotifications.clear(); } QDBusObjectPath NotificationManager::subscribeV2( const QString &identifier, bool serverSideMonitor ) { akDebug() << Q_FUNC_INFO << this << identifier << serverSideMonitor; return subscribeV3( identifier, serverSideMonitor, false ); } QDBusObjectPath NotificationManager::subscribeV3( const QString &identifier, bool serverSideMonitor, bool exclusive ) { akDebug() << Q_FUNC_INFO << this << identifier << serverSideMonitor << exclusive; NotificationSource *source = mNotificationSources.value( identifier ); if ( source ) { akDebug() << "Known subscriber" << identifier << "subscribes again"; source->addClientServiceName( message().service() ); } else { source = new NotificationSource( identifier, message().service(), this ); } registerSource( source ); source->setServerSideMonitorEnabled( serverSideMonitor ); source->setExclusive( exclusive ); // The path is /subscriber/escaped_identifier. We want to extract // the escaped_identifier and emit it in subscribed() instead of the original // identifier const QStringList paths = source->dbusPath().path().split( QLatin1Char( '/' ), QString::SkipEmptyParts ); // FIXME KF5: Emit the QDBusObjectPath instead of the identifier Q_EMIT subscribed( paths.at( 1 ) ); - + mDebugMessages.append(QDateTime::currentDateTime().toString() + QLatin1String(" SUBSCRIBE ") + identifier); return source->dbusPath(); } void NotificationManager::registerSource( NotificationSource *source ) { mNotificationSources.insert( source->identifier(), source ); } QDBusObjectPath NotificationManager::subscribe( const QString &identifier ) { akDebug() << Q_FUNC_INFO << this << identifier; return subscribeV2( identifier, false ); } void NotificationManager::unsubscribe( const QString &identifier ) { + mDebugMessages.append(QDateTime::currentDateTime().toString() + QLatin1String(" UNSUBSCRIBE ") + identifier); NotificationSource *source = mNotificationSources.value( identifier ); if ( source ) { unregisterSource( source ); const QStringList paths = source->dbusPath().path().split( QLatin1Char( '/' ), QString::SkipEmptyParts ); source->deleteLater(); Q_EMIT unsubscribed( paths.at( 1 ) ); } else { akDebug() << "Attempt to unsubscribe unknown subscriber" << identifier; } } void NotificationManager::unregisterSource( NotificationSource *source ) { mNotificationSources.remove( source->identifier() ); } QStringList NotificationManager::subscribers() const { QStringList identifiers; Q_FOREACH ( NotificationSource *source, mNotificationSources ) { identifiers << source->identifier(); } return identifiers; } + +int NotificationManager::notificationCounter() const +{ + return mNotificationCounter; +} + +int NotificationManager::notificationCount() const +{ + return mNotifications.size(); +} + +QStringList NotificationManager::listNotifications() const +{ + QStringList list; + Q_FOREACH ( const NotificationMessageV3 &n, mNotifications ) { + list << n.toString(); + } + return list; +} + +QStringList NotificationManager::debugMessages() const +{ + return mDebugMessages; +} diff --git a/server/src/notificationmanager.h b/server/src/notificationmanager.h index 3143cb06..617e6861 100644 --- a/server/src/notificationmanager.h +++ b/server/src/notificationmanager.h @@ -1,130 +1,137 @@ /* Copyright (c) 2006 - 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_NOTIFICATIONMANAGER_H #define AKONADI_NOTIFICATIONMANAGER_H #include "../libs/notificationmessage_p.h" #include "../libs/notificationmessagev3_p.h" #include "storage/entity.h" #include #include #include #include class NotificationManagerTest; namespace Akonadi { namespace Server { class NotificationCollector; class NotificationSource; /** Notification manager D-Bus interface. */ class NotificationManager : public QObject, protected QDBusContext { Q_OBJECT Q_CLASSINFO( "D-Bus Interface", "org.freedesktop.Akonadi.NotificationManager" ) public: static NotificationManager *self(); virtual ~NotificationManager(); void connectNotificationCollector( NotificationCollector *collector ); public Q_SLOTS: Q_SCRIPTABLE void emitPendingNotifications(); /** * Subscribe to notifications emitted by this manager. * * @param identifier Identifier to use of our subscription. * @return The path we got assigned. Contains identifier. */ Q_SCRIPTABLE QDBusObjectPath subscribe( const QString &identifier ); /** * Subscribe to notifications emitted by this manager. * * @param identifier Identifier to use for our subscription. * @param serverSideMonitor Whether client supports server-side monitoring * @return The path we got assigned. Contains identifier. */ Q_SCRIPTABLE QDBusObjectPath subscribeV2( const QString &identifier, bool serverSideMonitor ); /** * Subscribe to notifications emitted by this manager. * * @param identifier Identifier to use for our subscription. * @param serverSideMonitor Whether client supports server-side monitoring * @param exclusive Exclusive subscribers also receive notifications on referenced collections * @return The path we got assigned. Contains identifier. */ Q_SCRIPTABLE QDBusObjectPath subscribeV3( const QString &identifier, bool serverSideMonitor, bool exclusive ); /** * Unsubscribe from this manager. * * This method is for your inconvenience only. It's advisable to use the unsubscribe method * provided by the NotificationSource. * * @param identifier The identifier used for subscription. */ Q_SCRIPTABLE void unsubscribe( const QString &identifier ); /** * Returns identifiers of currently subscribed sources */ Q_SCRIPTABLE QStringList subscribers() const; + Q_SCRIPTABLE int notificationCounter() const; + Q_SCRIPTABLE int notificationCount() const; + Q_SCRIPTABLE QStringList debugMessages() const; + Q_SCRIPTABLE QStringList listNotifications() const; + Q_SIGNALS: Q_SCRIPTABLE void notify( const Akonadi::NotificationMessage::List &msgs ); Q_SCRIPTABLE void subscribed( const QString &identifier ); Q_SCRIPTABLE void unsubscribed( const QString &identifier ); private Q_SLOTS: void slotNotify( const Akonadi::NotificationMessageV3::List &msgs ); private: NotificationManager(); private: void registerSource( NotificationSource *source ); void unregisterSource( NotificationSource *source ); static NotificationManager *mSelf; NotificationMessageV3::List mNotifications; QTimer mTimer; //! One message source for each subscribed process QHash mNotificationSources; + QList mDebugMessages; + int mNotificationCounter; friend class NotificationSource; friend class ::NotificationManagerTest; }; } // namespace Server } // namespace Akonadi #endif