• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

NepomukDaemons

nepomukfilewatch.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE Project
00002    Copyright (c) 2007-2008 Sebastian Trueg <trueg@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #include "nepomukfilewatch.h"
00020 
00021 #include <QtCore/QTimer>
00022 #include <QtCore/QDir>
00023 #include <QtCore/QRegExp>
00024 #include <QtCore/QFileInfo>
00025 #include <QtDBus/QDBusConnection>
00026 
00027 #include <kdebug.h>
00028 #include <KUrl>
00029 #include <kmessagebox.h>
00030 #include <klocale.h>
00031 #include <KPluginFactory>
00032 #include <kio/netaccess.h>
00033 
00034 #include <Soprano/Model>
00035 #include <Soprano/StatementIterator>
00036 #include <Soprano/Statement>
00037 #include <Soprano/Node>
00038 #include <Soprano/NodeIterator>
00039 #include <Soprano/QueryResultIterator>
00040 #include <Soprano/Vocabulary/Xesam>
00041 
00042 // Restrictions and TODO:
00043 // ----------------------
00044 //
00045 // * KIO slaves that do change the local file system may emit stuff like
00046 //   file:///foo/bar -> xyz://foobar while the file actually ends up in
00047 //   the local file system again. This is not handled here. It is maybe
00048 //   necessary to use KFileItem::mostLocalUrl to determine local paths
00049 //   before deciding to call updateMetaDataForResource.
00050 //
00051 // * Only operations done through KIO are caught
00052 //
00053 
00054 using namespace Soprano;
00055 
00056 
00057 NEPOMUK_EXPORT_SERVICE( Nepomuk::FileWatch, "nepomukfilewatch")
00058 
00059 
00060 namespace {
00061     Soprano::QueryResultIterator queryChildren( Model* model, const QString& path )
00062     {
00063         // escape special chars
00064         QString regexpPath( path );
00065         if ( regexpPath[regexpPath.length()-1] != '/' ) {
00066             regexpPath += '/';
00067         }
00068         regexpPath.replace( QRegExp( "([\\.\\?\\*\\\\+\\(\\)\\\\\\|\\[\\]{}])" ), "\\\\\\1" );
00069 
00070 //        kDebug() << "query:" << QString( "select ?r ?p where { ?r <http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#fileUrl> ?p FILTER(REGEX(STR(?p), '^%1')) . }" ).arg( regexpPath );
00071 
00072         // query for all files that
00073         return model->executeQuery( QString( "prefix xesam: <http://freedesktop.org/standards/xesam/1.0/core#> "
00074                                              "select ?r ?p where { ?r xesam:url ?p . FILTER(REGEX(STR(?p), '^%1')) . }" ).arg( regexpPath ),
00075                                     Soprano::Query::QueryLanguageSparql );
00076     }
00077 }
00078 
00079 
00080 
00081 Nepomuk::FileWatch::FileWatch( QObject* parent, const QList<QVariant>& )
00082     : Service( parent ),
00083       m_strigiParentUrlUri( "http://strigi.sf.net/ontologies/0.9#parentUrl" )
00084 {
00085     // monitor KIO for changes
00086     QDBusConnection::sessionBus().connect( QString(), QString(), "org.kde.KDirNotify", "FileMoved",
00087                                            this, SLOT( slotFileMoved( const QString&, const QString& ) ) );
00088     QDBusConnection::sessionBus().connect( QString(), QString(), "org.kde.KDirNotify", "FilesRemoved",
00089                                            this, SLOT( slotFilesDeleted( const QStringList& ) ) );
00090 }
00091 
00092 
00093 Nepomuk::FileWatch::~FileWatch()
00094 {
00095 }
00096 
00097 
00098 void Nepomuk::FileWatch::slotFileMoved( const QString& urlFrom, const QString& urlTo )
00099 {
00100     KUrl from( urlFrom );
00101     KUrl to( urlTo );
00102 
00103     kDebug() << from << to;
00104 
00105     if ( from.isEmpty() || to.isEmpty() ) {
00106         kDebug() << "empty path. Looks like a bug somewhere...";
00107         return;
00108     }
00109 
00110     if ( mainModel() ) {
00111         // We do NOT get deleted messages for overwritten files! Thus, we have to remove all metadata for overwritten files
00112         // first. We do that now.
00113         removeMetaData( to );
00114 
00115         // and finally update the old statements
00116         updateMetaData( from, to );
00117 
00118         // update children files in case from is a folder
00119         QString fromPath = from.path();
00120         QList<Soprano::BindingSet> children = queryChildren( mainModel(), fromPath ).allBindings();
00121         foreach( const Soprano::BindingSet& bs, children ) {
00122             QString path = to.path();
00123             if ( !path.endsWith( '/' ) )
00124                 path += '/';
00125             path += bs[1].toString().mid( fromPath.endsWith( '/' ) ? fromPath.length() : fromPath.length()+1 );
00126             updateMetaData( bs[1].toString(), path ); // FIXME: reuse the URI we already have
00127         }
00128 
00129         // TODO: optionally create a xesam:url property in case a file was moved from a remote URL to a local one
00130         // still disabled since we also need a new context and that is much easier with a proper NRLModel which
00131         // we will hopefully have in Soprano 2.2
00132 //         if ( to.isLocalFile() ) {
00133 //             if ( !mainModel()->containsAnyStatement( to, Soprano::Vocabulary::Xesam::url(), Soprano::Node() ) ) {
00134 //                 mainModel()->addStatement( to, Soprano::Vocabulary::Xesam::url(), Soprano::LiteralValue( to.path() ) );
00135 //             }
00136 //         }
00137     }
00138     else {
00139         kDebug() << "Could not contact Nepomuk server.";
00140     }
00141 }
00142 
00143 
00144 void Nepomuk::FileWatch::slotFilesDeleted( const QStringList& paths )
00145 {
00146     foreach( const QString& path, paths ) {
00147         slotFileDeleted( path );
00148     }
00149 }
00150 
00151 
00152 void Nepomuk::FileWatch::slotFileDeleted( const QString& urlString )
00153 {
00154     KUrl url( urlString );
00155 
00156     kDebug() << url;
00157 
00158     if ( mainModel() ) {
00159         removeMetaData( url );
00160 
00161         // remove child annotations in case it is a local folder
00162         foreach( Soprano::Node node, queryChildren( mainModel(), url.path() ).iterateBindings( 0 ).allNodes() ) {
00163             mainModel()->removeAllStatements( Statement( node, Node(), Node() ) );
00164         }
00165     }
00166     else {
00167         kDebug() << "Could not contact Nepomuk server.";
00168     }
00169 }
00170 
00171 
00172 void Nepomuk::FileWatch::removeMetaData( const KUrl& url )
00173 {
00174     kDebug() << url;
00175 
00176     if ( url.isEmpty() ) {
00177         kDebug() << "empty path. Looks like a bug somewhere...";
00178         return;
00179     }
00180 
00181     mainModel()->removeAllStatements( Statement( url, Node(), Node() ) );
00182 
00183     // FIXME: what about the triples that have our uri as object?
00184 }
00185 
00186 
00187 void Nepomuk::FileWatch::updateMetaData( const KUrl& from, const KUrl& to )
00188 {
00189     kDebug() << from << "->" << to;
00190 
00191     //
00192     // Nepomuk allows annotating of remote files. These files do not necessarily have a xesam:url property
00193     // since it would not be of much use in the classic sense: we cannot use it to locate the file on the hd
00194     //
00195     // Thus, when remote files are moved through KIO and we get the notification, we simply change all triples
00196     // referring to the original file to use the new URL
00197     //
00198 
00199     Soprano::Node oldResource = from;
00200     Soprano::Node newResource = to;
00201 
00202     // update the resource itself
00203     // -----------------------------------------------
00204     if ( mainModel()->containsAnyStatement( Soprano::Statement( oldResource, Soprano::Node(), Soprano::Node() ) ) ) {
00205 
00206         QList<Soprano::Statement> sl = mainModel()->listStatements( Soprano::Statement( oldResource,
00207                                                                                         Soprano::Node(),
00208                                                                                         Soprano::Node() ) ).allStatements();
00209         Q_FOREACH( Soprano::Statement s, sl ) {
00210             if ( s.predicate() == Soprano::Vocabulary::Xesam::url() ) {
00211                 mainModel()->addStatement( Soprano::Statement( newResource,
00212                                                                s.predicate(),
00213                                                                Soprano::LiteralValue( to.path() ),
00214                                                                s.context() ) );
00215             }
00216             else if ( s.predicate() == m_strigiParentUrlUri ) {
00217                 mainModel()->addStatement( Soprano::Statement( newResource,
00218                                                                s.predicate(),
00219                                                                Soprano::LiteralValue( to.directory( KUrl::IgnoreTrailingSlash ) ),
00220                                                                s.context() ) );
00221             }
00222             else {
00223                 mainModel()->addStatement( Soprano::Statement( newResource,
00224                                                                s.predicate(),
00225                                                                s.object(),
00226                                                                s.context() ) );
00227             }
00228         }
00229 
00230         mainModel()->removeStatements( sl );
00231         // -----------------------------------------------
00232 
00233 
00234         // update resources relating to it
00235         // -----------------------------------------------
00236         sl = mainModel()->listStatements( Statement( Node(),
00237                                                      Node(),
00238                                                      oldResource ) ).allStatements();
00239         Q_FOREACH( Soprano::Statement s, sl ) {
00240             mainModel()->addStatement( Soprano::Statement( s.subject(),
00241                                                            s.predicate(),
00242                                                            newResource,
00243                                                            s.context() ) );
00244         }
00245         mainModel()->removeStatements( sl );
00246         // -----------------------------------------------
00247     }
00248 }
00249 
00250 #include "nepomukfilewatch.moc"

NepomukDaemons

Skip menu "NepomukDaemons"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KCMShell
  • KNotify
  • KStyles
  • Nepomuk Daemons
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal