27 #include <Soprano/Statement>
28 #include <Soprano/StatementIterator>
29 #include <Soprano/NodeIterator>
30 #include <Soprano/Vocabulary/RDF>
32 #include <QtDBus/QDBusMessage>
36 #include <kdbusconnectionpool.h>
38 #include <QtCore/QStringList>
39 #include <QtCore/QSet>
42 using namespace Soprano::Vocabulary;
45 QVariant nodeToVariant(
const Soprano::Node& node) {
46 if(node.isResource()) {
47 return QVariant(node.uri().toString());
50 return QVariant(node.literal().variant());
54 template<
typename T> QVariantList nodeListToVariantList(
const T &nodes) {
56 list.reserve(nodes.size());
57 foreach(
const Soprano::Node &n, nodes ) {
58 list << nodeToVariant(n);
65 return KUrl(uri).url();
68 template<
typename T> QStringList convertUris(
const T& uris) {
70 foreach(
const QUrl& uri, uris)
79 QList<QUrl> convertUris(
const QStringList& uris) {
81 foreach(
const QString& uri, uris)
90 for(QSet<QUrl>::const_iterator it = candidates.constBegin();
91 it != candidates.constEnd(); ++it) {
92 if(hash.contains(*it, con)) {
104 m_mutex( QMutex::Recursive ),
107 QDBusConnection con = KDBusConnectionPool::threadConnection();
108 con.registerObject(
"/resourcewatcher",
this, QDBusConnection::ExportScriptableSlots|QDBusConnection::ExportScriptableSignals);
115 QMutexLocker locker( &m_mutex );
116 QSet<ResourceWatcherConnection*> allConnections
117 = QSet<ResourceWatcherConnection*>::fromList(m_resHash.values())
118 + QSet<ResourceWatcherConnection*>::fromList(m_propHash.values())
119 + QSet<ResourceWatcherConnection*>::fromList(m_typeHash.values())
120 + m_watchAllConnections;
121 qDeleteAll(allConnections);
127 QMutexLocker locker( &m_mutex );
134 if(!m_typeHash.isEmpty()) {
135 types = m_model->typeCache()->types( res );
142 if(property == RDF::type()) {
143 QSet<QUrl> addedTypes, removedTypes;
144 for(QList<Soprano::Node>::const_iterator it = addedValues.constBegin();
145 it != addedValues.constEnd(); ++it) {
146 addedTypes << it->uri();
148 for(QList<Soprano::Node>::const_iterator it = removedValues.constBegin();
149 it != removedValues.constEnd(); ++it) {
150 removedTypes << it->uri();
152 changeTypes(res, types.toSet(), addedTypes, removedTypes);
157 QSet<ResourceWatcherConnection*> connections(m_watchAllConnections);
163 if( m_propHash.contains(property, con) ||
164 !m_propHash.values().contains(con) ) {
179 bool conIsWatchingResType = !m_typeHash.values().contains(con);
180 foreach(
const QUrl& type, types) {
181 if(m_typeHash.contains(type, con)) {
182 conIsWatchingResType =
true;
187 if( !m_resHash.values().contains(con) && conIsWatchingResType ) {
198 foreach(
const QUrl& type, types) {
200 if(!m_propHash.values(property).contains(con)) {
212 QMetaObject::invokeMethod(con,
216 Q_ARG(QVariantList, nodeListToVariantList(addedValues)),
217 Q_ARG(QVariantList, nodeListToVariantList(removedValues)));
222 const QUrl& property,
223 const QList<Soprano::Node>& nodes)
225 QMutexLocker locker( &m_mutex );
226 QList<QUrl> uniqueKeys = oldValues.keys();
227 foreach(
const QUrl resUri, uniqueKeys ) {
228 const QList<Soprano::Node> old = oldValues.values( resUri );
229 changeProperty(resUri, property, old, nodes);
235 QMutexLocker locker( &m_mutex );
236 QSet<ResourceWatcherConnection*> connections(m_watchAllConnections);
237 foreach(
const QUrl& type, types) {
245 QMetaObject::invokeMethod(con,
248 Q_ARG(QStringList, convertUris(types)));
254 QMutexLocker locker( &m_mutex );
255 QList<QUrl> types(_types);
256 if(!m_typeHash.isEmpty()) {
257 types = m_model->typeCache()->types( res );
260 QSet<ResourceWatcherConnection*> connections(m_watchAllConnections);
261 foreach(
const QUrl& type, types) {
272 QMetaObject::invokeMethod(con,
275 Q_ARG(QStringList, convertUris(types)));
281 QMutexLocker locker( &m_mutex );
283 QMetaObject::invokeMethod(
this,
"somethingChanged");
287 const QList<QUrl> &properties,
288 const QList<QUrl> &types)
290 QMutexLocker locker( &m_mutex );
291 kDebug() << resources << properties << types;
294 foreach(
const QUrl& res, resources ) {
295 m_resHash.insert(res, con);
298 foreach(
const QUrl& prop, properties ) {
299 m_propHash.insert(prop, con);
302 foreach(
const QUrl& type, types ) {
303 m_typeHash.insert(type, con);
306 if(resources.isEmpty() && properties.isEmpty() && types.isEmpty()) {
307 m_watchAllConnections.insert(con);
314 const QStringList& properties,
315 const QStringList& types)
317 QMutexLocker locker( &m_mutex );
318 kDebug() << resources << properties << types;
320 if(
ResourceWatcherConnection* con = createConnection(convertUris(resources), convertUris(properties), convertUris(types))) {
324 QDBusConnection bus = KDBusConnectionPool::threadConnection();
325 bus.send(message().createErrorReply(QDBusError::InvalidArgs, QLatin1String(
"Failed to create watch for given arguments.")));
326 return QDBusObjectPath();
334 QMutableHashIterator<QUrl, Nepomuk2::ResourceWatcherConnection*> it( hash );
335 while( it.hasNext() ) {
336 if( it.next().value() == con )
344 QMutexLocker locker( &m_mutex );
345 removeConnectionFromHash( m_resHash, con );
346 removeConnectionFromHash( m_propHash, con );
347 removeConnectionFromHash( m_typeHash, con );
348 m_watchAllConnections.remove(con);
353 QMutexLocker locker( &m_mutex );
354 const QSet<QUrl> newRes = convertUris(resources).toSet();
355 const QSet<QUrl> oldRes = m_resHash.keys(conn).toSet();
357 foreach(
const QUrl& res, newRes - oldRes) {
358 m_resHash.insert(res, conn);
360 foreach(
const QUrl& res, oldRes - newRes) {
361 m_resHash.remove(res, conn);
364 if(resources.isEmpty()) {
365 if(!m_propHash.values().contains(conn) &&
366 !m_typeHash.values().contains(conn)) {
367 m_watchAllConnections << conn;
371 m_watchAllConnections.remove(conn);
377 QMutexLocker locker( &m_mutex );
379 m_watchAllConnections.remove(conn);
384 QMutexLocker locker( &m_mutex );
386 if(!m_resHash.values().contains(conn) &&
387 !m_propHash.values().contains(conn) &&
388 !m_typeHash.values().contains(conn)) {
389 m_watchAllConnections << conn;
395 QMutexLocker locker( &m_mutex );
396 const QSet<QUrl> newprop = convertUris(properties).toSet();
397 const QSet<QUrl> oldprop = m_propHash.keys(conn).toSet();
399 foreach(
const QUrl& prop, newprop - oldprop) {
400 m_propHash.insert(prop, conn);
402 foreach(
const QUrl& prop, oldprop - newprop) {
403 m_propHash.remove(prop, conn);
406 if(properties.isEmpty()) {
407 if(!m_resHash.values().contains(conn) &&
408 !m_typeHash.values().contains(conn)) {
409 m_watchAllConnections << conn;
413 m_watchAllConnections.remove(conn);
419 QMutexLocker locker( &m_mutex );
420 m_propHash.insert(
convertUri(property), conn);
421 m_watchAllConnections.remove(conn);
426 QMutexLocker locker( &m_mutex );
427 m_propHash.remove(
convertUri(property), conn);
428 if(!m_resHash.values().contains(conn) &&
429 !m_propHash.values().contains(conn) &&
430 !m_typeHash.values().contains(conn)) {
431 m_watchAllConnections << conn;
437 QMutexLocker locker( &m_mutex );
438 const QSet<QUrl> newtype = convertUris(types).toSet();
439 const QSet<QUrl> oldtype = m_typeHash.keys(conn).toSet();
441 foreach(
const QUrl& type, newtype - oldtype) {
442 m_typeHash.insert(type, conn);
444 foreach(
const QUrl& type, oldtype - newtype) {
445 m_typeHash.remove(type, conn);
448 if(types.isEmpty()) {
449 if(!m_resHash.values().contains(conn) &&
450 !m_propHash.values().contains(conn)) {
451 m_watchAllConnections << conn;
455 m_watchAllConnections.remove(conn);
461 QMutexLocker locker( &m_mutex );
463 m_watchAllConnections.remove(conn);
468 QMutexLocker locker( &m_mutex );
470 if(!m_resHash.values().contains(conn) &&
471 !m_propHash.values().contains(conn) &&
472 !m_typeHash.values().contains(conn)) {
473 m_watchAllConnections << conn;
478 void Nepomuk2::ResourceWatcherManager::changeTypes(
const QUrl &res,
const QSet<QUrl>& resTypes,
const QSet<QUrl> &addedTypes,
const QSet<QUrl> &removedTypes)
480 QMutexLocker locker( &m_mutex );
482 QSet<ResourceWatcherConnection*> addConnections(m_watchAllConnections), removeConnections(m_watchAllConnections);
486 foreach( ResourceWatcherConnection* con, m_resHash.values( res ) ) {
487 if( m_propHash.contains(RDF::type(), con) ||
488 !m_propHash.values().contains(con) ) {
489 if(!addedTypes.isEmpty() &&
490 connectionWatchesOneType(con, addedTypes)) {
491 addConnections << con;
493 if(!removedTypes.isEmpty() &&
494 connectionWatchesOneType(con, removedTypes)) {
495 removeConnections << con;
501 if(!addedTypes.isEmpty()) {
502 foreach(
const QUrl& type, addedTypes + resTypes) {
503 foreach(ResourceWatcherConnection* con, m_typeHash.values(type)) {
504 if(!m_resHash.values().contains(con) &&
505 !m_propHash.values().contains(con)) {
506 addConnections << con;
511 if(!removedTypes.isEmpty()) {
512 foreach(
const QUrl& type, removedTypes + resTypes) {
513 foreach(ResourceWatcherConnection* con, m_typeHash.values(type)) {
514 if(!m_resHash.values().contains(con) &&
515 !m_propHash.values().contains(con)) {
516 removeConnections << con;
523 foreach(ResourceWatcherConnection* con, m_propHash.values(RDF::type())) {
524 if(!m_resHash.values().contains(con) ) {
525 if(connectionWatchesOneType(con, addedTypes + resTypes)) {
526 addConnections << con;
528 if(connectionWatchesOneType(con, removedTypes + resTypes)) {
529 removeConnections << con;
535 if(!addedTypes.isEmpty()) {
536 foreach(ResourceWatcherConnection* con, addConnections) {
538 QMetaObject::invokeMethod(con,
539 "resourceTypesAdded",
541 Q_ARG(QStringList, convertUris(addedTypes)));
544 if(!removedTypes.isEmpty()) {
545 foreach(ResourceWatcherConnection* con, removeConnections) {
547 QMetaObject::invokeMethod(con,
548 "resourceTypesRemoved",
550 Q_ARG(QStringList, convertUris(removedTypes)));
557 QMutexLocker locker( &m_mutex );
558 return !m_typeHash.values().contains(con) || hashContainsAtLeastOneOf(con, types, m_typeHash);
561 #include "resourcewatchermanager.moc"
ResourceWatcherConnection * createConnection(const QList< QUrl > &resources, const QList< QUrl > &properties, const QList< QUrl > &types)
Used internally by watch() and by the unit tests to create watcher connections.
QDBusObjectPath registerDBusObject(const QString &dbusClient, int id)
~ResourceWatcherManager()
void changeSomething()
to be called whenever something changes (preferably after calling any of the above) ...
Q_SCRIPTABLE QDBusObjectPath watch(const QStringList &resources, const QStringList &properties, const QStringList &types)
The main DBus methods exposed by the ResourceWatcher.
void createResource(const QUrl &uri, const QSet< QUrl > &types)
void removeResource(const QUrl &uri, const QList< QUrl > &types)
QString convertUri(const QUrl &uri)
ResourceWatcherManager(DataManagementModel *parent=0)
void changeProperty(const QUrl &res, const QUrl &property, const QList< Soprano::Node > &addedValues, const QList< Soprano::Node > &removedValues)