diff --git a/nepomuk/core/resourcedata.cpp b/nepomuk/core/resourcedata.cpp index 0fd6d03a74..ca151319c3 100644 --- a/nepomuk/core/resourcedata.cpp +++ b/nepomuk/core/resourcedata.cpp @@ -1,816 +1,816 @@ /* * This file is part of the Nepomuk KDE project. * Copyright (C) 2006-2010 Sebastian Trueg * Copyright (C) 2010-2012 Vishesh Handa * * 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 "resourcedata.h" #include "resourcemanager.h" #include "resourcemanager_p.h" #include "resource.h" #include "tools.h" #include "nie.h" #include "nfo.h" #include "pimo.h" #include "nepomukmainmodel.h" #include "dbusconnectionpool.h" #include "class.h" #include "dbustypes.h" #include "resourcewatcher.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Soprano; #define MAINMODEL (m_rm->m_manager->mainModel()) Nepomuk::ResourceData::ResourceData( const QUrl& uri, const QUrl& kickOffUri, const QUrl& type, ResourceManagerPrivate* rm ) : m_uri(uri), m_mainType( type ), m_modificationMutex(QMutex::Recursive), m_cacheDirty(true), m_pimoThing(0), m_groundingOccurence(0), m_rm(rm) { if( m_mainType.isEmpty() ) { m_mainType = Soprano::Vocabulary::RDFS::Resource(); } m_types << m_mainType; if( m_rm->dataCacheFull() ) m_rm->cleanupCache(); m_rm->dataCnt.ref(); if( !uri.isEmpty() ) { m_kickoffUris.insert( uri ); } if( !kickOffUri.isEmpty() ) { m_kickoffUris.insert( kickOffUri ); } m_rm->addToKickOffList( this, m_kickoffUris ); } Nepomuk::ResourceData::~ResourceData() { resetAll(true); m_rm->dataCnt.deref(); } bool Nepomuk::ResourceData::isFile() { return( m_uri.scheme() == QLatin1String("file") || m_nieUrl.scheme() == QLatin1String("file") || (!m_kickoffUris.isEmpty() && (*m_kickoffUris.begin()).scheme() == QLatin1String("file")) || constHasType( Soprano::Vocabulary::Xesam::File() ) || constHasType( Nepomuk::Vocabulary::NFO::FileDataObject() ) ); } QUrl Nepomuk::ResourceData::uri() const { return m_uri; } QUrl Nepomuk::ResourceData::type() { load(); return m_mainType; } QList Nepomuk::ResourceData::allTypes() { load(); return m_types; } void Nepomuk::ResourceData::setTypes( const QList& types ) { store(); QMutexLocker lock(&m_modificationMutex); // reset types m_types.clear(); m_mainType = Soprano::Vocabulary::RDFS::Resource(); QList nodes; // load types (and set maintype) foreach( const QUrl& url, types ) { loadType( url ); nodes << Node( url ); } // update the data store setProperty(Soprano::Vocabulary::RDF::type(), Nepomuk::Variant(types) ); } void Nepomuk::ResourceData::resetAll( bool isDelete ) { // remove us from all caches (store() will re-insert us later if necessary) m_rm->mutex.lock(); if( !m_uri.isEmpty() ) { m_rm->m_initializedData.remove( m_uri ); if( m_rm->m_watcher ) { - m_rm->m_watcher->removeResource(Resource::fromResourceUri(m_uri)); + m_rm->m_watcher->removeResource(m_uri); } } Q_FOREACH( const KUrl& uri, m_kickoffUris ) m_rm->m_uriKickoffData.remove( uri ); m_rm->mutex.unlock(); // reset all variables m_uri = QUrl(); m_nieUrl = KUrl(); m_kickoffUris.clear(); m_cache.clear(); m_cacheDirty = false; m_types.clear(); delete m_pimoThing; m_pimoThing = 0; m_groundingOccurence = 0; // when we are being deleted the value of m_mainType is not important // anymore. Also since ResourceManager is a global static it might be // deleted after the global static behind Soprano::Vocabulary::RDFS // which results in a crash. if( !isDelete ) m_mainType = Soprano::Vocabulary::RDFS::Resource(); } QHash Nepomuk::ResourceData::allProperties() { load(); return m_cache; } bool Nepomuk::ResourceData::hasProperty( const QUrl& uri ) { load(); QHash::const_iterator it = m_cache.constFind( uri ); if( it == m_cache.constEnd() ) return false; return true; } bool Nepomuk::ResourceData::hasProperty( const QUrl& p, const Variant& v ) { QHash::const_iterator it = m_cache.constFind( p ); if( it == m_cache.constEnd() ) return false; QList thisVals = it.value().toVariantList(); QList vals = v.toVariantList(); Q_FOREACH( const Variant& val, vals ) { if( !thisVals.contains(val) ) return false; } return true; } bool Nepomuk::ResourceData::hasType( const QUrl& uri ) { load(); return constHasType( uri ); } bool Nepomuk::ResourceData::constHasType( const QUrl& uri ) const { // we need to protect the reading, too. setTypes may be triggered from another thread QMutexLocker lock(&m_modificationMutex); Types::Class requestedType( uri ); for ( QList::const_iterator it = m_types.constBegin(); it != m_types.constEnd(); ++it ) { Types::Class availType( *it ); if ( availType == requestedType || availType.isSubClassOf( requestedType ) ) { return true; } } return false; } Nepomuk::Variant Nepomuk::ResourceData::property( const QUrl& uri ) { load(); // we need to protect the reading, too. load my be triggered from another thread's // connection to a Soprano statement signal QMutexLocker lock(&m_modificationMutex); QHash::const_iterator it = m_cache.constFind( uri ); if ( it == m_cache.constEnd() ) { return Variant(); } else { return *it; } } bool Nepomuk::ResourceData::store() { QMutexLocker lock(&m_modificationMutex); if ( m_uri.isEmpty() ) { QMutexLocker rmlock(&m_rm->mutex); if ( m_nieUrl.isValid() && m_nieUrl.isLocalFile() && m_mainType == Soprano::Vocabulary::RDFS::Resource() ) { m_mainType = Nepomuk::Vocabulary::NFO::FileDataObject(); m_types << m_mainType; } QDBusConnection bus = QDBusConnection::sessionBus(); QDBusMessage msg = QDBusMessage::createMethodCall( QLatin1String("org.kde.nepomuk.DataManagement"), QLatin1String("/datamanagement"), QLatin1String("org.kde.nepomuk.DataManagement"), QLatin1String("createResource") ); QString app = KGlobal::mainComponent().componentName(); QVariantList arguments; //FIXME: Maybe we should be setting the 'label' over here. arguments << DBus::convertUriList(m_types) << QString() << QString() << app; msg.setArguments( arguments ); QDBusMessage reply = bus.call( msg ); if( reply.type() == QDBusMessage::ErrorMessage ) { //TODO: Set the error somehow kWarning() << reply.errorMessage(); return false; } else if( reply.type() == QDBusMessage::ReplyMessage ) { m_uri = reply.arguments().at(0).toUrl(); } // Add us to the initialized data, i.e. make us "valid" m_rm->m_initializedData.insert( m_uri, this ); // each initialized resource has to be in a kickoff list // thus, we make sure that is the case. if( m_kickoffUris.isEmpty() ) { m_kickoffUris.insert( m_uri ); m_rm->addToKickOffList( this, m_kickoffUris ); } // store our grounding occurrence in case we are a thing created by the pimoThing() method if( m_groundingOccurence ) { if( m_groundingOccurence != this ) m_groundingOccurence->store(); setProperty(Vocabulary::PIMO::groundingOccurrence(), Variant(m_groundingOccurence->uri()) ); } foreach( const KUrl& url, m_kickoffUris ) { if( url.scheme().isEmpty() ) setProperty( Soprano::Vocabulary::NAO::identifier(), Variant(url.url()) ); else setProperty( Nepomuk::Vocabulary::NIE::url(), Variant(url.url()) ); } } return true; } void Nepomuk::ResourceData::loadType( const QUrl& storedType ) { if ( !m_types.contains( storedType ) ) { m_types << storedType; } if ( m_mainType == Soprano::Vocabulary::RDFS::Resource() ) { Q_ASSERT( !storedType.isEmpty() ); m_mainType = storedType; } else { Types::Class currentTypeClass = m_mainType; Types::Class storedTypeClass = storedType; // Keep the type that is further down the hierarchy if ( storedTypeClass.isSubClassOf( currentTypeClass ) ) { m_mainType = storedTypeClass.uri(); } else { // This is a little convenience hack since the user is most likely // more interested in the file content than the actual file Types::Class xesamContentClass( Soprano::Vocabulary::Xesam::Content() ); if ( m_mainType == Soprano::Vocabulary::Xesam::File() && ( storedTypeClass == xesamContentClass || storedTypeClass.isSubClassOf( xesamContentClass ) ) ) { m_mainType = storedTypeClass.uri(); } else { // the same is true for nie:DataObject vs. nie:InformationElement Types::Class nieInformationElementClass( Vocabulary::NIE::InformationElement() ); Types::Class nieDataObjectClass( Vocabulary::NIE::DataObject() ); if( ( currentTypeClass == nieDataObjectClass || currentTypeClass.isSubClassOf( nieDataObjectClass ) ) && ( storedTypeClass == nieInformationElementClass || storedTypeClass.isSubClassOf( nieInformationElementClass ) ) ) { m_mainType = storedTypeClass.uri(); } } } } } bool Nepomuk::ResourceData::load() { QMutexLocker lock(&m_modificationMutex); if ( m_cacheDirty ) { m_cache.clear(); if ( m_uri.isValid() ) { // // We exclude properties that are part of the inference graph // It would only pollute the user interface // Soprano::QueryResultIterator it = MAINMODEL->executeQuery(QString("select distinct ?p ?o where { " "graph ?g { %1 ?p ?o . } . FILTER(?g!=) . " "}").arg(Soprano::Node::resourceToN3(m_uri)), Soprano::Query::QueryLanguageSparql); while ( it.next() ) { QUrl p = it["p"].uri(); Soprano::Node o = it["o"]; if ( p == Soprano::Vocabulary::RDF::type() ) { if ( o.isResource() ) { loadType( o.uri() ); } } else { Nepomuk::Variant var = Variant::fromNode( o ); updateKickOffLists( p, var ); m_cache[p].append( var ); } } m_cacheDirty = false; delete m_pimoThing; m_pimoThing = 0; if( hasType( Vocabulary::PIMO::Thing() ) ) { m_pimoThing = new Thing( m_uri ); } else { // TODO: somehow handle pimo:referencingOccurrence and pimo:occurrence QueryResultIterator pimoIt = MAINMODEL->executeQuery( QString( "select ?r where { ?r <%1> <%2> . }") .arg( Vocabulary::PIMO::groundingOccurrence().toString() ) .arg( QString::fromAscii( m_uri.toEncoded() ) ), Soprano::Query::QueryLanguageSparql ); if( pimoIt.next() ) { m_pimoThing = new Thing( pimoIt.binding("r").uri() ); } } return true; } else { return false; } } else { return true; } } void Nepomuk::ResourceData::setProperty( const QUrl& uri, const Nepomuk::Variant& value ) { Q_ASSERT( uri.isValid() ); if( store() ) { // step 0: make sure this resource is in the store QMutexLocker lock(&m_modificationMutex); // update the store QDBusConnection bus = QDBusConnection::sessionBus(); QDBusMessage msg = QDBusMessage::createMethodCall( QLatin1String("org.kde.nepomuk.DataManagement"), QLatin1String("/datamanagement"), QLatin1String("org.kde.nepomuk.DataManagement"), QLatin1String("setProperty") ); QString app = KGlobal::mainComponent().componentName(); QVariantList arguments; QVariantList varList; foreach( const Nepomuk::Variant var, value.toVariantList() ) { // make sure resource values are in the store if( var.simpleType() == qMetaTypeId() ) { var.toResource().m_data->store(); varList << var.toUrl(); } else { varList << var.variant(); } } arguments << DBus::convertUriList(QList() << m_uri) << DBus::convertUri(uri) << QVariant(DBus::normalizeVariantList(varList)) << app; msg.setArguments( arguments ); QDBusMessage reply = bus.call( msg ); if( reply.type() == QDBusMessage::ErrorMessage ) { //TODO: Set the error somehow kWarning() << reply.errorMessage(); return; } // update the cache for now if( value.isValid() ) m_cache[uri] = value; else m_cache.remove(uri); // update the kickofflists updateKickOffLists( uri, value ); } } void Nepomuk::ResourceData::addProperty( const QUrl& uri, const Nepomuk::Variant& value ) { Q_ASSERT( uri.isValid() ); if( value.isValid() && store() ) { // step 0: make sure this resource is in the store QMutexLocker lock(&m_modificationMutex); // update the store QDBusConnection bus = QDBusConnection::sessionBus(); QDBusMessage msg = QDBusMessage::createMethodCall( QLatin1String("org.kde.nepomuk.DataManagement"), QLatin1String("/datamanagement"), QLatin1String("org.kde.nepomuk.DataManagement"), QLatin1String("addProperty") ); QString app = KGlobal::mainComponent().componentName(); QVariantList arguments; QVariantList varList; foreach( const Nepomuk::Variant var, value.toVariantList() ) { // make sure resource values are in the store if( var.simpleType() == qMetaTypeId() ) { var.toResource().m_data->store(); varList << var.toUrl(); } else { varList << var.variant(); } } arguments << DBus::convertUriList(QList() << m_uri) << DBus::convertUri(uri) << QVariant(DBus::normalizeVariantList(varList)) << app; msg.setArguments( arguments ); QDBusMessage reply = bus.call( msg ); if( reply.type() == QDBusMessage::ErrorMessage ) { //TODO: Set the error somehow kWarning() << reply.errorMessage(); return; } // update the cache for now if( value.isValid() ) m_cache[uri].append(value); // update the kickofflists updateKickOffLists( uri, value ); } } void Nepomuk::ResourceData::removeProperty( const QUrl& uri ) { Q_ASSERT( uri.isValid() ); if( !m_uri.isEmpty() ) { QMutexLocker lock(&m_modificationMutex); QDBusConnection bus = QDBusConnection::sessionBus(); QDBusMessage msg = QDBusMessage::createMethodCall( QLatin1String("org.kde.nepomuk.DataManagement"), QLatin1String("/datamanagement"), QLatin1String("org.kde.nepomuk.DataManagement"), QLatin1String("removeProperties") ); QString app = KGlobal::mainComponent().componentName(); QVariantList arguments; arguments << DBus::convertUri(m_uri) << DBus::convertUri(uri) << app; msg.setArguments( arguments ); QDBusMessage reply = bus.call( msg ); if( reply.type() == QDBusMessage::ErrorMessage ) { //TODO: Set the error somehow kWarning() << reply.errorMessage(); return; } // Update the cache m_cache.remove( uri ); // update the kickofflists updateKickOffLists( uri, Variant() ); } } void Nepomuk::ResourceData::remove( bool recursive ) { Q_UNUSED(recursive) QMutexLocker lock(&m_modificationMutex); if( !m_uri.isEmpty() ) { QDBusConnection bus = QDBusConnection::sessionBus(); QDBusMessage msg = QDBusMessage::createMethodCall( QLatin1String("org.kde.nepomuk.DataManagement"), QLatin1String("/datamanagement"), QLatin1String("org.kde.nepomuk.DataManagement"), QLatin1String("removeResources") ); QString app = KGlobal::mainComponent().componentName(); QVariantList arguments; // TODO: Set the flag over here arguments << DBus::convertUri(m_uri) << 0 << app; msg.setArguments( arguments ); QDBusMessage reply = bus.call( msg ); if( reply.type() == QDBusMessage::ErrorMessage ) { //TODO: Set the error somehow kWarning() << reply.errorMessage(); return; } } resetAll(); } bool Nepomuk::ResourceData::exists() { if( m_uri.isValid() ) { const QString query = QString::fromLatin1("ask { %1 ?p ?o . }") .arg( Soprano::Node::resourceToN3(m_uri) ); return MAINMODEL->executeQuery( query, Soprano::Query::QueryLanguageSparql ).boolValue(); } else { return false; } } bool Nepomuk::ResourceData::isValid() const { return( !m_mainType.isEmpty() && ( !m_uri.isEmpty() || !m_kickoffUris.isEmpty() ) ); } Nepomuk::ResourceData* Nepomuk::ResourceData::determineUri() { // We have the following possible situations: // 1. m_uri is already valid // -> simple, nothing to do // // 2. m_uri is not valid // -> we need to determine the URI // // 2.1. m_kickoffUri is valid // 2.1.1. it is a file URL // 2.1.1.1. it is nie:url for r // -> use r as m_uri // 2.1.1.2. it points to a file on a removable device for which we have a filex:/ URL // -> use the r in r nie:url filex:/... // 2.1.1.3. it is a file which is not an object in some nie:url relation // -> create new random m_uri and use kickoffUriOrId() as m_nieUrl // 2.1.2. it is a resource URI // -> use it as m_uri // // 2.2. m_kickOffUri is not valid // 2.2.1. m_kickOffUri is a nao:identifier for r // -> use r as m_uri // if( m_uri.isEmpty() ) { Soprano::Model* model = MAINMODEL; if( !m_kickoffUris.isEmpty() ) { KUrl kickOffUri = *m_kickoffUris.begin(); if( kickOffUri.scheme().isEmpty() ) { // // Not valid. Checking for nao:identifier // QString query = QString::fromLatin1("select distinct ?r where { ?r %1 %2. } LIMIT 1") .arg( Soprano::Node::resourceToN3(Soprano::Vocabulary::NAO::identifier()) ) .arg( Soprano::Node::literalToN3( kickOffUri.url() ) ); Soprano::QueryResultIterator it = model->executeQuery( query, Soprano::Query::QueryLanguageSparql ); if( it.next() ) { m_uri = it["r"].uri(); it.close(); } } else { // // In one query determine if the URI is already used as resource URI or as // nie:url // QString query = QString::fromLatin1("select distinct ?r ?o where { " "{ ?r %1 %2 . FILTER(?r!=%2) . } " "UNION " "{ %2 ?p ?o . } " "} LIMIT 1") .arg( Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::url() ) ) .arg( Soprano::Node::resourceToN3( kickOffUri ) ); Soprano::QueryResultIterator it = model->executeQuery( query, Soprano::Query::QueryLanguageSparql ); if( it.next() ) { QUrl uri = it["r"].uri(); if( uri.isEmpty() ) { m_uri = kickOffUri; } else { m_uri = uri; m_nieUrl = kickOffUri; } it.close(); } else if( kickOffUri.scheme() == QLatin1String("nepomuk") ) { // for nepomuk URIs we simply use the kickoff URI as resource URI m_uri = kickOffUri; } else { // for everything else we use m_kickoffUri as nie:url with a new random m_uri m_nieUrl = kickOffUri; } } } } // // Move us to the final data hash now that the URI is known // if( !m_uri.isEmpty() ) { //vHanda: Is there some way to avoid this hash lookup every time? // It sure would speed things up. ResourceDataHash::iterator it = m_rm->m_initializedData.find(m_uri); if( it == m_rm->m_initializedData.end() ) { m_rm->m_initializedData.insert( m_uri, this ); if(!m_rm->m_watcher) { m_rm->m_watcher = new ResourceWatcher(m_rm->m_manager); - QObject::connect( m_rm->m_watcher, SIGNAL(propertyAdded(Nepomuk::Resource, Nepomuk::Types::Property, QVariant)), - m_rm->m_manager, SLOT(slotPropertyAdded(Nepomuk::Resource, Nepomuk::Types::Property, QVariant)) ); - QObject::connect( m_rm->m_watcher, SIGNAL(propertyRemoved(Nepomuk::Resource, Nepomuk::Types::Property, QVariant)), - m_rm->m_manager, SLOT(slotPropertyRemoved(Nepomuk::Resource, Nepomuk::Types::Property, QVariant)) ); - m_rm->m_watcher->addResource( Nepomuk::Resource::fromResourceUri(m_uri) ); + QObject::connect( m_rm->m_watcher, SIGNAL(propertyAdded(QUrl, Nepomuk::Types::Property, QVariant)), + m_rm->m_manager, SLOT(slotPropertyAdded(QUrl, Nepomuk::Types::Property, QVariant)) ); + QObject::connect( m_rm->m_watcher, SIGNAL(propertyRemoved(QUrl, Nepomuk::Types::Property, QVariant)), + m_rm->m_manager, SLOT(slotPropertyRemoved(QUrl, Nepomuk::Types::Property, QVariant)) ); + m_rm->m_watcher->addResource( m_uri ); m_rm->m_watcher->start(); } else { - m_rm->m_watcher->addResource( Nepomuk::Resource::fromResourceUri(m_uri) ); + m_rm->m_watcher->addResource( m_uri ); } } else { return it.value(); } } return this; } void Nepomuk::ResourceData::invalidateCache() { m_cacheDirty = true; } Nepomuk::Thing Nepomuk::ResourceData::pimoThing() { load(); if( !m_pimoThing ) { // // We only create a new thing if we are a nie:InformationElement. // All other resources will simply be converted into a pimo:Thing // // Files, however, are a special case in every aspect. this includes pimo things. // Files are their own grounding occurrence. This makes a lot of things // much simpler. // if( hasType( Vocabulary::PIMO::Thing() ) || isFile() || !hasType( Vocabulary::NIE::InformationElement() ) ) { m_pimoThing = new Thing(this); } else { m_pimoThing = new Thing(); } m_pimoThing->m_data->m_groundingOccurence = this; } return *m_pimoThing; } bool Nepomuk::ResourceData::operator==( const ResourceData& other ) const { if( this == &other ) return true; return( m_uri == other.m_uri && m_mainType == other.m_mainType && m_kickoffUris == other.m_kickoffUris ); } QDebug Nepomuk::ResourceData::operator<<( QDebug dbg ) const { KUrl::List list = m_kickoffUris.toList(); dbg << QString::fromLatin1("[kickoffuri: %1; uri: %2; type: %3; ref: %4]") .arg( list.toStringList().join(QLatin1String(",")), m_uri.url(), m_mainType.toString() ) .arg( m_ref ); return dbg; } QDebug operator<<( QDebug dbg, const Nepomuk::ResourceData& data ) { return data.operator<<( dbg ); } void Nepomuk::ResourceData::updateKickOffLists(const QUrl& prop, const Nepomuk::Variant& v) { KUrl oldUrl; KUrl newUrl; if( prop == Nepomuk::Vocabulary::NIE::url() ) { oldUrl = m_nieUrl; newUrl = v.toUrl(); m_nieUrl = newUrl; } else if( prop == Soprano::Vocabulary::NAO::identifier() ) { Q_FOREACH( const KUrl& url, m_kickoffUris ) { if( url.scheme().isEmpty() ) { oldUrl = url; break; } } newUrl = KUrl( v.toString() ); } else { return; } if( oldUrl != newUrl ) { QMutexLocker rmlock(&m_rm->mutex); m_kickoffUris.remove( oldUrl ); m_rm->m_uriKickoffData.remove( oldUrl ); if( !newUrl.isEmpty() ) { m_kickoffUris.insert( newUrl ); m_rm->m_uriKickoffData.insert( newUrl, this ); } } } diff --git a/nepomuk/core/resourcemanager.cpp b/nepomuk/core/resourcemanager.cpp index 1e0b5ff1c4..f800c443a4 100644 --- a/nepomuk/core/resourcemanager.cpp +++ b/nepomuk/core/resourcemanager.cpp @@ -1,569 +1,569 @@ /* * This file is part of the Nepomuk KDE project. * Copyright (C) 2006-2012 Sebastian Trueg * Copyright (C) 2010 Vishesh Handa * * 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 "resourcemanager.h" #include "resourcemanager_p.h" #include "resourcedata.h" #include "tools.h" #include "nepomukmainmodel.h" #include "resource.h" #include "class.h" #include "nie.h" #include "dbustypes.h" #include "resourcewatcher.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Soprano; Nepomuk::ResourceManager* Nepomuk::ResourceManager::s_instance = 0; Nepomuk::ResourceManagerPrivate::ResourceManagerPrivate( ResourceManager* manager ) : mainModel( 0 ), overrideModel( 0 ), mutex(QMutex::Recursive), dataCnt( 0 ), m_manager( manager ), m_watcher( 0 ) { Nepomuk::DBus::registerDBusTypes(); } Nepomuk::ResourceData* Nepomuk::ResourceManagerPrivate::data( const QUrl& uri, const QUrl& type ) { if ( uri.isEmpty() ) { // return an invalid resource which may be activated by calling setProperty return new ResourceData( QUrl(), QUrl(), type, this ); } if( ResourceData* data = findData( uri ) ) { return data; } else { return new ResourceData( QUrl(), uri, type, this ); } } Nepomuk::ResourceData* Nepomuk::ResourceManagerPrivate::data( const QString& uriOrId, const QUrl& type ) { if ( !uriOrId.isEmpty() ) { KUrl url(uriOrId); return data( url, type ); } return new ResourceData( QUrl(), QUrl(), type, this ); } Nepomuk::ResourceData* Nepomuk::ResourceManagerPrivate::dataForResourceUri( const QUrl& uri, const QUrl& type ) { if ( uri.isEmpty() ) { // return an invalid resource which may be activated by calling setProperty return new ResourceData( QUrl(), QUrl(), type, this ); } if( ResourceData* data = findData( uri ) ) { return data; } else { return new ResourceData( uri, QUrl(), type, this ); } } QList Nepomuk::ResourceManagerPrivate::allResourceDataOfType( const QUrl& type ) { QList l; if( !type.isEmpty() ) { mutex.lock(); QSet rdl = m_uriKickoffData.values().toSet(); mutex.unlock(); for( QSet::iterator rdIt = rdl.begin(); rdIt != rdl.end(); ++rdIt ) { ResourceData* rd = *rdIt; // // make sure we do not trigger a load here since // 1. that could result in the deletion of values from the iterated list (m_cache.clear() in ResourceData::load) // 2. We only need to check non-existing resources anyway, since the rest is queried from the db below // if( rd->constHasType( type ) ) { l.append( rd ); } } } return l; } QList Nepomuk::ResourceManagerPrivate::allResourceDataWithProperty( const QUrl& uri, const Variant& v ) { QList l; // // We need to cache m_uriKickoffData since it might be changed // in the loop by ResourceData::load() // mutex.lock(); QSet rdl = m_uriKickoffData.values().toSet(); mutex.unlock(); // // make sure none of the ResourceData objects are deleted by ResourceData::load below // which would result in a crash since we have them cached. // QList tmp; foreach( ResourceData* rd, rdl ) { tmp << Resource( rd ); } for( QSet::iterator rdIt = rdl.begin(); rdIt != rdl.end(); ++rdIt ) { ResourceData* rd = *rdIt; if( rd->hasProperty( uri ) && rd->property( uri ) == v ) { l.append( rd ); } } return l; } QList Nepomuk::ResourceManagerPrivate::allResourceData() { return m_uriKickoffData.values().toSet().toList(); } bool Nepomuk::ResourceManagerPrivate::dataCacheFull() const { return dataCnt >= 1000; } void Nepomuk::ResourceManagerPrivate::cleanupCache( int num ) { QMutexLocker lock( &mutex ); QSet rdl = m_uriKickoffData.values().toSet() + m_initializedData.values().toSet(); for( QSet::iterator rdIt = rdl.begin(); rdIt != rdl.end(); ++rdIt ) { ResourceData* data = *rdIt; if ( !data->cnt() ) { delete data; if( num > 0 && --num == 0 ) break; } } } bool Nepomuk::ResourceManagerPrivate::shouldBeDeleted( ResourceData * rd ) const { // // We delete data objects in one of two cases: // 1. They are not valid and as such not in one of the ResourceManagerPrivate kickoff lists // 2. The cache is already full and we need to clean up // return( !rd->cnt() && ( !rd->isValid() || dataCacheFull() )); } void Nepomuk::ResourceManagerPrivate::addToKickOffList( ResourceData* rd, const QSet & uris ) { Q_FOREACH( const KUrl& uri, uris ) m_uriKickoffData.insert( uri, rd ); } void Nepomuk::ResourceManagerPrivate::_k_storageServiceInitialized( bool success ) { if( success ) { kDebug() << "Nepomuk Storage service up and initialized."; cleanupCache(-1); m_manager->init(); emit m_manager->nepomukSystemStarted(); } } void Nepomuk::ResourceManagerPrivate::_k_dbusServiceUnregistered( const QString& serviceName ) { if( serviceName == QLatin1String("org.kde.NepomukStorage") ) { kDebug() << "Nepomuk Storage service went down."; cleanupCache(-1); emit m_manager->nepomukSystemStopped(); } } Nepomuk::ResourceData* Nepomuk::ResourceManagerPrivate::findData( const QUrl& uri ) { if ( !uri.isEmpty() ) { QMutexLocker lock( &mutex ); // look for the URI in the initialized and in the URI kickoff data ResourceDataHash::iterator end = m_initializedData.end(); ResourceDataHash::iterator it = m_initializedData.find( uri ); if( it == end ) { end = m_uriKickoffData.end(); it = m_uriKickoffData.find( uri ); } if( it != end ) { return it.value(); } } return 0; } Nepomuk::ResourceManager::ResourceManager() : QObject(), d( new ResourceManagerPrivate( this ) ) { // connect to the storage service's initialized signal to be able to emit // the nepomukSystemStarted signal QDBusConnection::sessionBus().connect( QLatin1String("org.kde.NepomukStorage"), QLatin1String("/servicecontrol"), QLatin1String("org.kde.nepomuk.ServiceControl"), QLatin1String("serviceInitialized"), this, SLOT(_k_storageServiceInitialized(bool)) ); // connect to the serviceUnregistered signal to be able to connect the nepomukSystemStopped // signal once the storage service goes away QDBusServiceWatcher *watcher = new QDBusServiceWatcher( QLatin1String("org.kde.NepomukStorage"), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForUnregistration, this ); connect( watcher, SIGNAL(serviceUnregistered(QString)), this, SLOT(_k_dbusServiceUnregistered(QString)) ); init(); } Nepomuk::ResourceManager::~ResourceManager() { clearCache(); delete d->mainModel; delete d; if(s_instance == this) { s_instance = 0; } } void Nepomuk::ResourceManager::deleteInstance() { delete this; } Nepomuk::ResourceManager* Nepomuk::ResourceManager::instance() { if(!s_instance) { s_instance = new ResourceManager(); s_instance->setParent(QCoreApplication::instance()); } return s_instance; } int Nepomuk::ResourceManager::init() { QMutexLocker lock( &d->initMutex ); if( !d->mainModel ) { d->mainModel = new MainModel( this ); } d->mainModel->init(); return d->mainModel->isValid() ? 0 : -1; } bool Nepomuk::ResourceManager::initialized() const { QMutexLocker lock( &d->initMutex ); return d->mainModel && d->mainModel->isValid(); } #ifndef KDE_NO_DEPRECATED Nepomuk::Resource Nepomuk::ResourceManager::createResourceFromUri( const QString& uri ) { return Resource( uri, QUrl() ); } #endif void Nepomuk::ResourceManager::removeResource( const QString& uri ) { Resource res( uri ); res.remove(); } void Nepomuk::ResourceManager::notifyError( const QString& uri, int errorCode ) { kDebug() << "(Nepomuk::ResourceManager) error: " << uri << " " << errorCode; emit error( uri, errorCode ); } #ifndef KDE_NO_DEPRECATED QList Nepomuk::ResourceManager::allResourcesOfType( const QString& type ) { return allResourcesOfType( QUrl(type) ); } #endif QList Nepomuk::ResourceManager::allResourcesOfType( const QUrl& type ) { QSet set; if( !type.isEmpty() ) { // check local data QList localData = d->allResourceDataOfType( type ); for( QList::iterator rdIt = localData.begin(); rdIt != localData.end(); ++rdIt ) { Resource res( *rdIt ); set.insert(res); } // kDebug() << " added local resources: " << l.count(); Soprano::Model* model = mainModel(); Soprano::StatementIterator it = model->listStatements( Soprano::Statement( Soprano::Node(), Soprano::Vocabulary::RDF::type(), type ) ); while( it.next() ) { Statement s = *it; Resource res( s.subject().uri() ); set.insert(res); } // kDebug() << " added remote resources: " << l.count(); } return set.toList(); } QList Nepomuk::ResourceManager::allResources() { QList l; Q_FOREACH( ResourceData* data, d->allResourceData()) { l << Resource( data ); } Soprano::QueryResultIterator it = mainModel()->executeQuery( QLatin1String("select distinct ?r where { ?r a ?t . FILTER(?t != rdf:Property && ?t != rdfs:Class) . }"), Soprano::Query::QueryLanguageSparql ); while( it.next() ) { Resource r( it[0].uri() ); l << r; } return l; } #ifndef KDE_NO_DEPRECATED QList Nepomuk::ResourceManager::allResourcesWithProperty( const QString& uri, const Variant& v ) { return allResourcesWithProperty( QUrl(uri), v ); } #endif QList Nepomuk::ResourceManager::allResourcesWithProperty( const QUrl& uri, const Variant& v ) { QSet set; if( v.isList() ) { kDebug() << "(ResourceManager::allResourcesWithProperty) list values not supported."; } else { // check local data QList localData = d->allResourceDataWithProperty( uri, v ); for( QList::iterator rdIt = localData.begin(); rdIt != localData.end(); ++rdIt ) { set.insert( Resource( *rdIt ) ); } // check remote data Soprano::Model* model = mainModel(); Soprano::StatementIterator it = model->listStatements( Soprano::Statement( Soprano::Node(), uri, v.toNode() ) ); while( it.next() ) { Statement s = *it; Resource res( s.subject().uri() ); set.insert( res ); } } return set.toList(); } void Nepomuk::ResourceManager::clearCache() { d->cleanupCache( -1 ); } #ifndef KDE_NO_DEPRECATED QString Nepomuk::ResourceManager::generateUniqueUri() { return generateUniqueUri( QString() ).toString(); } #endif QUrl Nepomuk::ResourceManager::generateUniqueUri( const QString& name ) { // default to res URIs QString type = QLatin1String("res"); // ctx is the only used value for name if(name == QLatin1String("ctx")) { type = name; } Soprano::Model* model = mainModel(); while( 1 ) { QString uuid = QUuid::createUuid().toString(); uuid = uuid.mid(1, uuid.length()-2); QUrl uri = QUrl( QLatin1String("nepomuk:/") + type + QLatin1String("/") + uuid ); if ( !model->executeQuery( QString::fromLatin1("ask where { " "{ <%1> ?p1 ?o1 . } " "UNION " "{ ?s2 <%1> ?o2 . } " "UNION " "{ ?s3 ?p3 <%1> . } " "UNION " "{ graph <%1> { ?s4 ?4 ?o4 . } . } " "}") .arg( QString::fromAscii( uri.toEncoded() ) ), Soprano::Query::QueryLanguageSparql ).boolValue() ) { return uri; } } } Soprano::Model* Nepomuk::ResourceManager::mainModel() { // make sure we are initialized if ( !d->overrideModel && !initialized() ) { init(); } return d->mainModel; } -void Nepomuk::ResourceManager::slotPropertyAdded(const Resource &res, const Types::Property &prop, const QVariant &value) +void Nepomuk::ResourceManager::slotPropertyAdded(const QUrl &res, const Types::Property &prop, const QVariant &value) { - ResourceDataHash::iterator it = d->m_initializedData.find(res.resourceUri()); + ResourceDataHash::iterator it = d->m_initializedData.find(res); if(it != d->m_initializedData.end()) { ResourceData* data = *it; data->m_cache[prop.uri()].append(Variant(value)); data->updateKickOffLists(prop.uri(), Variant(value)); } } -void Nepomuk::ResourceManager::slotPropertyRemoved(const Resource &res, const Types::Property &prop, const QVariant &value_) +void Nepomuk::ResourceManager::slotPropertyRemoved(const QUrl& res, const Nepomuk::Types::Property& prop, const QVariant& value_) { - ResourceDataHash::iterator it = d->m_initializedData.find(res.resourceUri()); + ResourceDataHash::iterator it = d->m_initializedData.find(res); if(it != d->m_initializedData.end()) { ResourceData* data = *it; QHash::iterator cacheIt = data->m_cache.find(prop.uri()); if(cacheIt != data->m_cache.end()) { Variant v = *cacheIt; const Variant value(value_); QList vl = v.toVariantList(); if(vl.contains(value)) { vl.removeAll(value); data->updateKickOffLists(prop.uri(), Variant()); if(vl.isEmpty()) { data->m_cache.erase(cacheIt); } else { cacheIt.value() = vl; } } } } } void Nepomuk::ResourceManager::setOverrideMainModel( Soprano::Model* model ) { QMutexLocker lock( &d->mutex ); if( model != d->mainModel ) { d->overrideModel = model; // clear cache to make sure we do not mix data Q_FOREACH( ResourceData* data, d->allResourceData()) { data->invalidateCache(); } } } Nepomuk::ResourceManager* Nepomuk::ResourceManager::createManagerForModel( Soprano::Model* model ) { ResourceManager* manager = new ResourceManager(); manager->setOverrideMainModel( model ); return manager; } #include "resourcemanager.moc" diff --git a/nepomuk/core/resourcemanager.h b/nepomuk/core/resourcemanager.h index 6b23b8f455..c87a803227 100644 --- a/nepomuk/core/resourcemanager.h +++ b/nepomuk/core/resourcemanager.h @@ -1,289 +1,289 @@ /* * This file is part of the Nepomuk KDE project. * Copyright (C) 2006-2009 Sebastian Trueg * * 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 _NEPOMUK_RESOURCE_MANAGER_H_ #define _NEPOMUK_RESOURCE_MANAGER_H_ #include "nepomuk_export.h" #include #include namespace Soprano { class Model; } namespace Nepomuk { class Resource; class Variant; class ResourceManagerHelper; class ResourceManagerPrivate; namespace Types { class Class; class Property; } /** * \class ResourceManager resourcemanager.h Nepomuk/ResourceManager * * \brief The ResourceManager is the central \a %Nepomuk configuration point. * * Use the initialized() method to check the availabity of the %Nepomuk system. * Signals nepomukSystemStarted() and nepomukSystemStopped() can be used to * enable or disable Nepomuk-specific GUI elements. * * \author Sebastian Trueg */ class NEPOMUK_EXPORT ResourceManager : public QObject { Q_OBJECT public: static ResourceManager* instance(); /** * In KDE 4.3 support for multiple ResourceManager instances * has been introduced. To keep binary compatibility both the constructor's * and destructor's access visibility could not be changed. Thus, instead of deleting * a custom ResourceManager instance the standard way, one has to call this * method or use QObject::deleteLater. * * \since 4.3 */ void deleteInstance(); /** * Initialize the Nepomuk framework. This method will initialize the communication with * the local Nepomuk-KDE services, ie. the data repository. It will trigger a reconnect * to the %Nepomuk database. * * There is normally no reason to call this method manually except when using multiple * threads. In that case it is highly recommended to call this method in the main thread * before doing anything else. * * \return 0 if all necessary components could be found and -1 otherwise. */ int init(); /** * \return true if init() has been called successfully, ie. the KMetaData system is connected * to the local RDF repository service and ready to work. */ bool initialized() const; /** * Retrieve the main data storage model. */ Soprano::Model* mainModel(); /** * Override the main model used for all storage. By default the main model * used is the Nepomuk server main model. * * \param model The model to use instead of the Nepomuk server or 0 to reset. * * \since 4.1 */ void setOverrideMainModel( Soprano::Model* model ); /** * \deprecated Use the Resource constructor directly. * * Creates a Resource object representing the data referenced by \a uri. * The result is the same as from using the Resource::Resource( const QString&, const QString& ) * constructor with an empty type. * * \return The Resource representing the data at \a uri or an invalid Resource object if the local * NEPOMUK RDF store does not contain an object with URI \a uri. */ #ifndef KDE_NO_DEPRECATED KDE_DEPRECATED Resource createResourceFromUri( const QString& uri ); #endif /** * Remove the resource denoted by \a uri completely. * * This method is just a wrapper around Resource::remove. The result * is the same. */ void removeResource( const QString& uri ); /** * Retrieve a list of all resource managed by this manager. * * \warning This list will be very big. Usage of this method is * discouraged. Use Query::QueryServiceClient in combination with an * empty Query::Query instead. * * \since 4.3 */ QList allResources(); /** * Retrieve a list of all resources of the specified \a type. * * This includes Resources that are not synced yet so it might * not represent exactly the state as in the RDF store. * * \warning This list can be very big. Usage of this method is * discouraged. Use Query::QueryServiceClient in combination with * a Query::Query containing one Query::ResourceTypeTerm instead. */ QList allResourcesOfType( const QUrl& type ); /** * \deprecated Use allResourcesOfType( const QString& type ) */ #ifndef KDE_NO_DEPRECATED KDE_DEPRECATED QList allResourcesOfType( const QString& type ); #endif /** * Retrieve a list of all resources that have property \a uri defined with a value of \a v. * * This includes Resources that are not synced yet so it might * not represent exactly the state as in the RDF store. * * \param uri The URI identifying the property. If this URI does * not include a namespace the default namespace is * prepended. * \param v The value all returned resources should have set as properts \a uri. * * \warning This list can be very big. Usage of this method is * discouraged. Use Query::QueryServiceClient in combination with * a Query::Query containing one Query::ComparisonTerm instead. */ QList allResourcesWithProperty( const QUrl& uri, const Variant& v ); /** * \deprecated Use allResourcesWithProperty( const QString& type ) */ #ifndef KDE_NO_DEPRECATED KDE_DEPRECATED QList allResourcesWithProperty( const QString& uri, const Variant& v ); #endif /** * %ResourceManager caches resource locally so subsequent access is faster. * This method clears this cache, deleting any Resource that is not used. * * \since 4.4 */ void clearCache(); /** * \deprecated Use generateUniqueUri(const QString&) * * Generates a unique URI that is not used in the store yet. This method ca be used to * generate URIs for virtual types such as Tag. */ #ifndef KDE_NO_DEPRECATED KDE_DEPRECATED QString generateUniqueUri(); #endif /** * Generates a unique URI that is not used in the store yet. This method can be used to * generate URIs for virtual types such as Tag. * * \param label A label that the algorithm should use to try to create a more readable URI. * * \return A new unique URI which can be used to define a new resource. * * \since 4.2 */ QUrl generateUniqueUri( const QString& label ); /** * \internal Non-public API. Used by Resource to signalize errors. */ void notifyError( const QString& uri, int errorCode ); /** * Create a new ResourceManager instance which uses model as its * override model. This allows to use multiple instances of ResourceManager * at the same time. Normally one does not need this method as the singleton * accessed via instance() should be enough. * * \param model The model to read and write data from and to. * * \since 4.3 */ static ResourceManager* createManagerForModel( Soprano::Model* model ); Q_SIGNALS: /** * This signal gets emitted whenever a Resource changes due to a sync procedure. * Be aware that modifying resources locally via the Resource::setProperty method * does not result in a resourceModified signal being emitted. * * \param uri The URI of the modified resource. * * NOT IMPLEMENTED YET */ void resourceModified( const QString& uri ); /** * Whenever a problem occurs (like for example failed resource syncing) this * signal is emitted. * * \param uri The resource related to the error. * \param errorCode The type of the error (Resource::ErrorCode) */ void error( const QString& uri, int errorCode ); /** * Emitted once the Nepomuk system is up and can be used. * * \warning This signal will not be emitted if the Nepomuk * system is running when the ResourceManager is created. * Use initialized() to check the status. * * \since 4.4 */ void nepomukSystemStarted(); /** * Emitted once the Nepomuk system goes down. * * \since 4.4 */ void nepomukSystemStopped(); private Q_SLOTS: - void slotPropertyAdded(const Nepomuk::Resource &res, const Nepomuk::Types::Property &prop, const QVariant &value); - void slotPropertyRemoved(const Nepomuk::Resource &res, const Nepomuk::Types::Property &prop, const QVariant &value); + void slotPropertyAdded(const QUrl &res, const Nepomuk::Types::Property &prop, const QVariant &value); + void slotPropertyRemoved(const QUrl &res, const Nepomuk::Types::Property &prop, const QVariant &value); private: friend class Nepomuk::Resource; friend class Nepomuk::ResourceManagerPrivate; ResourceManager(); ~ResourceManager(); static ResourceManager* s_instance; ResourceManagerPrivate* const d; Q_PRIVATE_SLOT( d, void _k_storageServiceInitialized(bool) ) Q_PRIVATE_SLOT( d, void _k_dbusServiceUnregistered(QString) ) }; } #endif diff --git a/nepomuk/core/resourcewatcher.cpp b/nepomuk/core/resourcewatcher.cpp index 617950320a..d507e1e4ba 100644 --- a/nepomuk/core/resourcewatcher.cpp +++ b/nepomuk/core/resourcewatcher.cpp @@ -1,280 +1,274 @@ /* This file is part of the Nepomuk KDE project. Copyright (C) 2011 Vishesh Handa Copyright (C) 2011 Sebastian Trueg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "resourcewatcher.h" #include "resourcewatcherconnectioninterface.h" #include "resourcewatchermanagerinterface.h" #include #include "resource.h" #include "kurl.h" #include "kdebug.h" namespace { QString convertUri(const QUrl& uri) { return KUrl(uri).url(); } QStringList convertUris(const QList& uris) { QStringList cs; foreach(const QUrl& uri, uris) { cs << convertUri(uri); } return cs; } QList convertUris(const QStringList& uris) { QList us; foreach(const QString& uri, uris) { us << KUrl(uri); } return us; } } class Nepomuk::ResourceWatcher::Private { public: QList m_types; QList m_resources; QList m_properties; org::kde::nepomuk::ResourceWatcherConnection * m_connectionInterface; org::kde::nepomuk::ResourceWatcher * m_watchManagerInterface; }; Nepomuk::ResourceWatcher::ResourceWatcher(QObject* parent) : QObject(parent), d(new Private) { d->m_watchManagerInterface = new org::kde::nepomuk::ResourceWatcher( "org.kde.nepomuk.DataManagement", "/resourcewatcher", QDBusConnection::sessionBus() ); d->m_connectionInterface = 0; } Nepomuk::ResourceWatcher::~ResourceWatcher() { stop(); delete d; } bool Nepomuk::ResourceWatcher::start() { // // Convert to list of strings // QList uris = convertUris(d->m_resources); QList props = convertUris(d->m_properties); QList types_ = convertUris(d->m_types); // // Create the dbus object to watch // QDBusPendingReply reply = d->m_watchManagerInterface->watch( uris, props, types_ ); QDBusObjectPath path = reply.value(); if(!path.path().isEmpty()) { d->m_connectionInterface = new org::kde::nepomuk::ResourceWatcherConnection( "org.kde.nepomuk.DataManagement", path.path(), QDBusConnection::sessionBus() ); connect( d->m_connectionInterface, SIGNAL(propertyAdded(QString,QString,QVariantList)), this, SLOT(slotPropertyAdded(QString,QString,QVariantList)) ); connect( d->m_connectionInterface, SIGNAL(propertyRemoved(QString,QString,QVariantList)), this, SLOT(slotPropertyRemoved(QString,QString,QVariantList)) ); connect( d->m_connectionInterface, SIGNAL(resourceCreated(QString,QStringList)), this, SLOT(slotResourceCreated(QString,QStringList)) ); connect( d->m_connectionInterface, SIGNAL(propertyChanged(QString,QString,QVariantList,QVariantList)), this, SLOT(slotPropertyChanged(QString,QString,QVariantList,QVariantList)) ); connect( d->m_connectionInterface, SIGNAL(resourceRemoved(QString,QStringList)), this, SLOT(slotResourceRemoved(QString,QStringList)) ); connect( d->m_connectionInterface, SIGNAL(resourceTypeAdded(QString,QString)), this, SLOT(slotResourceTypeAdded(QString,QString)) ); connect( d->m_connectionInterface, SIGNAL(resourceTypeRemoved(QString,QString)), this, SLOT(slotResourceTypeRemoved(QString,QString)) ); return true; } else { return false; } } void Nepomuk::ResourceWatcher::stop() { if (d->m_connectionInterface) { d->m_connectionInterface->close(); delete d->m_connectionInterface; d->m_connectionInterface = 0; } } void Nepomuk::ResourceWatcher::addProperty(const Nepomuk::Types::Property& property) { d->m_properties << property.uri(); if(d->m_connectionInterface) { d->m_connectionInterface->addProperty(convertUri(property.uri())); } } -void Nepomuk::ResourceWatcher::addResource(const Nepomuk::Resource& res) +void Nepomuk::ResourceWatcher::addResource(const QUrl& res) { - d->m_resources << res.resourceUri(); + d->m_resources << res; if(d->m_connectionInterface) { - d->m_connectionInterface->addResource(convertUri(res.resourceUri())); + d->m_connectionInterface->addResource(convertUri(res)); } } void Nepomuk::ResourceWatcher::addType(const Nepomuk::Types::Class& type) { d->m_types << type.uri(); if(d->m_connectionInterface) { d->m_connectionInterface->addType(convertUri(type.uri())); } } void Nepomuk::ResourceWatcher::removeProperty(const Nepomuk::Types::Property& property) { d->m_properties.removeAll(property.uri()); if(d->m_connectionInterface) { d->m_connectionInterface->removeProperty(convertUri(property.uri())); } } -void Nepomuk::ResourceWatcher::removeResource(const Nepomuk::Resource& res) +void Nepomuk::ResourceWatcher::removeResource(const QUrl& res) { - d->m_resources.removeAll(res.resourceUri()); + d->m_resources.removeAll(res); if(d->m_connectionInterface) { - d->m_connectionInterface->removeResource(convertUri(res.resourceUri())); + d->m_connectionInterface->removeResource(convertUri(res)); } } void Nepomuk::ResourceWatcher::removeType(const Nepomuk::Types::Class& type) { d->m_types.removeAll(type.uri()); if(d->m_connectionInterface) { d->m_connectionInterface->removeType(convertUri(type.uri())); } } QList< Nepomuk::Types::Property > Nepomuk::ResourceWatcher::properties() const { QList< Nepomuk::Types::Property > props; foreach(const QUrl& uri, d->m_properties) props << Types::Property(uri); return props; } -QList Nepomuk::ResourceWatcher::resources() const +QList Nepomuk::ResourceWatcher::resources() const { - QList resources; - foreach(const QUrl& uri, d->m_resources) - resources << Resource::fromResourceUri(uri); - return resources; + return d->m_resources; } QList< Nepomuk::Types::Class > Nepomuk::ResourceWatcher::types() const { QList types; foreach(const QUrl& uri, d->m_types) types << Types::Class(uri); return types; } void Nepomuk::ResourceWatcher::setProperties(const QList< Nepomuk::Types::Property >& properties_) { d->m_properties.clear(); foreach(const Nepomuk::Types::Property& p, properties_) { d->m_properties << p.uri(); } if(d->m_connectionInterface) { d->m_connectionInterface->setProperties(convertUris(d->m_properties)); } } -void Nepomuk::ResourceWatcher::setResources(const QList< Nepomuk::Resource >& resources_) +void Nepomuk::ResourceWatcher::setResources(const QList& resources_) { - d->m_resources.clear(); - foreach(const Nepomuk::Resource& res, resources_) { - d->m_resources << res.resourceUri(); - } + d->m_resources = resources_; if(d->m_connectionInterface) { d->m_connectionInterface->setResources(convertUris(d->m_resources)); } } void Nepomuk::ResourceWatcher::setTypes(const QList< Nepomuk::Types::Class >& types_) { d->m_types.clear(); foreach(const Nepomuk::Types::Class& t, types_) { d->m_types << t.uri(); } if(d->m_connectionInterface) { d->m_connectionInterface->setTypes(convertUris(d->m_types)); } } void Nepomuk::ResourceWatcher::slotResourceCreated(const QString &res, const QStringList &types) { - emit resourceCreated(Nepomuk::Resource::fromResourceUri(KUrl(res)), convertUris(types)); + emit resourceCreated((KUrl(res)), convertUris(types)); } void Nepomuk::ResourceWatcher::slotResourceRemoved(const QString &res, const QStringList &types) { emit resourceRemoved(KUrl(res), convertUris(types)); } void Nepomuk::ResourceWatcher::slotResourceTypeAdded(const QString &res, const QString &type) { emit resourceTypeAdded(KUrl(res), KUrl(type)); } void Nepomuk::ResourceWatcher::slotResourceTypeRemoved(const QString &res, const QString &type) { emit resourceTypeRemoved(KUrl(res), KUrl(type)); } void Nepomuk::ResourceWatcher::slotPropertyAdded(const QString& res, const QString& prop, const QVariantList &objects) { foreach(const QVariant& v, objects) { - emit propertyAdded( Resource::fromResourceUri(KUrl(res)), Types::Property( KUrl(prop) ), v ); + emit propertyAdded( KUrl(res), Types::Property( KUrl(prop) ), v ); } } void Nepomuk::ResourceWatcher::slotPropertyRemoved(const QString& res, const QString& prop, const QVariantList &objects) { foreach(const QVariant& v, objects) { - emit propertyRemoved( Resource::fromResourceUri(KUrl(res)), Types::Property( KUrl(prop) ), v ); + emit propertyRemoved( KUrl(res), Types::Property( KUrl(prop) ), v ); } } void Nepomuk::ResourceWatcher::slotPropertyChanged(const QString& res, const QString& prop, const QVariantList& oldObjs, const QVariantList& newObjs) { - emit propertyChanged( Resource::fromResourceUri(KUrl(res)), Types::Property( KUrl(prop) ), + emit propertyChanged( KUrl(res), Types::Property( KUrl(prop) ), oldObjs, newObjs ); } #include "resourcewatcher.moc" diff --git a/nepomuk/core/resourcewatcher.h b/nepomuk/core/resourcewatcher.h index 06b96229cd..1392920a64 100644 --- a/nepomuk/core/resourcewatcher.h +++ b/nepomuk/core/resourcewatcher.h @@ -1,315 +1,315 @@ /* This file is part of the Nepomuk KDE project. Copyright (C) 2011 Vishesh Handa Copyright (C) 2011 Sebastian Trueg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef RESOURCEWATCHER_H #define RESOURCEWATCHER_H #include "../types/class.h" #include "../types/property.h" #include "resource.h" #include #include namespace Nepomuk { /** * \class ResourceWatcher resourcewatcher.h * * \brief Selectively monitor the nepomuk repository for changes. * * Resources may be monitored on the basis of types, properties, and uris. * * Changes may be monitored in one of the following ways: * -# By resources - * Specify the exact resources that should be watched. Any changes made to the specified resources * (Excluding \ref nepomuk_dms_metadata) will be notified through the propertyAdded() and propertyRemoved() * signals. Notifications will also be sent if any of the watched resources is deleted. * -# By resources and properties - * Specify the exact resources and their properties. Any changes made to the specified resources * which touch one of the specified properties will be notified through the propertyAdded() and propertyRemoved() * signals. * -# By types - * Specific types may be specified via add/setType. If types are set, then notifications will be * sent for all new resources of that type. This includes property changes and resource creation and removal. * TODO: add flags that allow to only watch for resource creation and removal. * -# By types and properties - * Both the types and properties may be specified. Notifications will be sent for property changes * in resource with the specified types. * * \section nepomuk_rw_examples Resource Watcher Usage Example * * The following code creates a new ResourceWatcher, configures it to listen to changes on the \c nmm:performer * property on one specific resource \c res. * * \code * Nepomuk::ResourceWatcher* watcher = new Nepomuk::ResourceWatcher(this); * watcher->addResource(res); * watcher->addProperty(NMM:performer()); * connect(watcher, SIGNAL(propertyAdded(Nepomuk::Resource, Nepomuk::Types::Property, QVariant)), * this, SLOT(slotPropertyChanged())); * connect(watcher, SIGNAL(propertyRemoved(Nepomuk::Resource, Nepomuk::Types::Property, QVariant)), * this, SLOT(slotPropertyChanged())); * rwatcher->start(); * \endcode * * \author Vishesh Handa , Sebastian Trueg * * \ingroup nepomuk_datamanagement */ class ResourceWatcher : public QObject { Q_OBJECT public: /** * \brief Create a new %ResourceWatcher instance. * * This instance will not emit any signals before it has been configured * and started. */ ResourceWatcher( QObject* parent = 0 ); /** * \brief Destructor. */ virtual ~ResourceWatcher(); /** * \brief Add a type to be watched. * * Every resource of this type will be watched for changes. * * \sa setTypes() */ void addType( const Types::Class & type ); /** * \brief Add a resource to be watched. * * Every change to this resource will be * signalled, depending on the configured properties(). * * \sa setResources() */ - void addResource( const Nepomuk::Resource & res ); + void addResource( const QUrl & res ); /** * \brief Add a property to be watched. * * Every change to a value of this property * will be signalled, depending on the configured resources() or types(). * * \sa setProperties() */ void addProperty( const Types::Property & property ); /** * \brief Remove a type to be watched. * * Every resource of this type will be watched for changes. * * \sa setTypes() */ void removeType( const Types::Class & type ); /** * \brief Remove a resource to be watched. * * Every change to this resource will be * signalled, depending on the configured properties(). * * \sa setResources() */ - void removeResource( const Nepomuk::Resource & res ); + void removeResource( const QUrl & res ); /** * \brief Remove a property to be watched. * * Every change to a value of this property * will be signalled, depending on the configured resources() or types(). * * \sa setProperties() */ void removeProperty( const Types::Property & property ); /** * \brief Set the types to be watched. * * Every resource having one of these types will be watched for changes. * * \sa addType() */ void setTypes( const QList & types_ ); /** * \brief Set the resources to be watched. * * Every change to one of these resources will be * signalled, depending on the configured properties(). * * \sa addResource() */ - void setResources( const QList & resources_ ); + void setResources( const QList & resources_ ); /** * \brief Set the properties to be watched. * * Every change to a value of any of these properties * will be signalled, depending on the configured resources() or types(). * * \sa addProperty() */ void setProperties( const QList & properties_ ); /** * \brief The types that have been configured via addType() and setTypes(). * * Every resource having one of these types will be watched * for changes. */ QList types() const; /** * \brief The resources that have been configured via addResource() and setResources(). * * Every change to one of these resources will be * signalled, depending on the configured properties(). */ - QList resources() const; + QList resources() const; /** * \brief The properties that have been configured via addProperty() and setProperties(). * * Every change to a value of any of these properties * will be signalled, depending on the configured resources() or types(). */ QList properties() const; public Q_SLOTS: /** * \brief Start the signalling of changes. * * Before calling this method no signal will be emitted. In * combination with stop() this allows to suspend the watching. * Calling start() multiple times has no effect. */ bool start(); /** * \brief Stop the signalling of changes. * * Allows to stop the watcher which has been started * via start(). Calling stop() multiple times has no effect. */ void stop(); Q_SIGNALS: /** * \brief This signal is emitted when a new resource is created. * \param resource The newly created resource. * \param types The types the new resource has. If types() have been configured this list will always * contain one of the configured types. */ - void resourceCreated( const Nepomuk::Resource & resource, const QList& types ); //FIXME: Use either Resource or uri, not a mix + void resourceCreated( const QUrl & resource, const QList& types ); //FIXME: Use either Resource or uri, not a mix /** * \brief This signal is emitted when a resource is deleted. * \param uri The resource URI of the removed resource. * \param types The types the removed resource had. If types() have been configured this list will always * contain one of the configured types. */ void resourceRemoved( const QUrl & uri, const QList& types ); /** * \brief This signal is emitted when a type has been added to a resource. This does not include creation which * is signalled via resourceCreated(). It only applies to changes in a resource's types. * \param res The changed resource. * \param type The newly added type. If types() have been configured it will be one of them. */ - void resourceTypeAdded( const Nepomuk::Resource & res, const Types::Class & type ); + void resourceTypeAdded( const QUrl & res, const Types::Class & type ); /** * \brief This signal is emitted when a type has been removed from a resource. * * This does not include removal of entire resources which is signalled via resourceRemoved(). * It only applies to changes in a resource's types. * \param res The changed resource. * \param type The removed type. If types() have been configured it will be one of them. */ - void resourceTypeRemoved( const Nepomuk::Resource & res, const Types::Class & type ); + void resourceTypeRemoved( const QUrl & res, const Types::Class & type ); /** * \brief This signal is emitted when a property value is added. * \param resource The changed resource. * \param property The property which has a new value. * \param value The newly added property value. */ - void propertyAdded( const Nepomuk::Resource & resource, + void propertyAdded( const QUrl & resource, const Nepomuk::Types::Property & property, const QVariant & value ); /** * \brief This signal is emitted when a property value is removed. * \param resource The changed resource. * \param property The property which was changed. * \param value The removed property value. */ - void propertyRemoved( const Nepomuk::Resource & resource, + void propertyRemoved( const QUrl & resource, const Nepomuk::Types::Property & property, const QVariant & value ); /** * \brief This signal is emitted when a property value is changed. * * This signal cannot be emitted for all changes. It doesn't work if a property is first * removed and then set, cause the Data Mangement Service does not maintain an internal * cache for the purpose of emitting the propertyChanged signal. * * Specially, since one could theoretically take forever between the removal and the * setting of the property. * * \param resource The changed resource. * \param property The property which was changed. * \param oldValue The removed property value. */ - void propertyChanged( const Nepomuk::Resource & resource, + void propertyChanged( const QUrl & resource, const Nepomuk::Types::Property & property, const QVariantList & oldValue, const QVariantList & newValue ); private Q_SLOTS: void slotResourceCreated(const QString& res, const QStringList& types); void slotResourceRemoved(const QString& res, const QStringList& types); void slotResourceTypeAdded(const QString& res, const QString& type); void slotResourceTypeRemoved(const QString& res, const QString& type); void slotPropertyAdded(const QString& res, const QString& prop, const QVariantList& objects); void slotPropertyRemoved(const QString& res, const QString& prop, const QVariantList& objects); void slotPropertyChanged(const QString& res, const QString& prop, const QVariantList & oldObjs, const QVariantList & newObjs); private: class Private; Private * d; }; } #endif // RESOURCEWATCHER_H