• Skip to content
  • Skip to link menu
KDE 4.2 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, SIGNAL( fileMoved( const QString&, const QString& ) ) );
00088     QDBusConnection::sessionBus().connect( QString(), QString(), "org.kde.KDirNotify", "FilesRemoved",
00089                                            this, SIGNAL( filesDeleted( const QStringList& ) ) );
00090 
00091     // async connection to the actual slots
00092     // FIXME: is the signal delivery order guranteed? If not, we need a queue!
00093     connect( this, SIGNAL( fileMoved( QString, QString ) ), this, SLOT( slotFileMoved( QString, QString ) ), Qt::QueuedConnection );
00094     connect( this, SIGNAL( filesDeleted( QStringList ) ), this, SLOT( slotFilesDeleted( QStringList ) ), Qt::QueuedConnection );
00095 }
00096 
00097 
00098 Nepomuk::FileWatch::~FileWatch()
00099 {
00100 }
00101 
00102 
00103 void Nepomuk::FileWatch::slotFileMoved( const QString& urlFrom, const QString& urlTo )
00104 {
00105     KUrl from( urlFrom );
00106     KUrl to( urlTo );
00107 
00108     kDebug() << from << to;
00109 
00110     if ( from.isEmpty() || to.isEmpty() ) {
00111         kDebug() << "empty path. Looks like a bug somewhere...";
00112         return;
00113     }
00114 
00115     if ( mainModel() ) {
00116         // We do NOT get deleted messages for overwritten files! Thus, we have to remove all metadata for overwritten files
00117         // first. We do that now.
00118         removeMetaData( to );
00119 
00120         // and finally update the old statements
00121         updateMetaData( from, to );
00122 
00123         // update children files in case from is a folder
00124         QString fromPath = from.path();
00125         QList<Soprano::BindingSet> children = queryChildren( mainModel(), fromPath ).allBindings();
00126         foreach( const Soprano::BindingSet& bs, children ) {
00127             QString path = to.path();
00128             if ( !path.endsWith( '/' ) )
00129                 path += '/';
00130             path += bs[1].toString().mid( fromPath.endsWith( '/' ) ? fromPath.length() : fromPath.length()+1 );
00131             updateMetaData( bs[1].toString(), path ); // FIXME: reuse the URI we already have
00132         }
00133 
00134         // TODO: optionally create a xesam:url property in case a file was moved from a remote URL to a local one
00135         // still disabled since we also need a new context and that is much easier with a proper NRLModel which
00136         // we will hopefully have in Soprano 2.2
00137 //         if ( to.isLocalFile() ) {
00138 //             if ( !mainModel()->containsAnyStatement( to, Soprano::Vocabulary::Xesam::url(), Soprano::Node() ) ) {
00139 //                 mainModel()->addStatement( to, Soprano::Vocabulary::Xesam::url(), Soprano::LiteralValue( to.path() ) );
00140 //             }
00141 //         }
00142     }
00143     else {
00144         kDebug() << "Could not contact Nepomuk server.";
00145     }
00146 }
00147 
00148 
00149 void Nepomuk::FileWatch::slotFilesDeleted( const QStringList& paths )
00150 {
00151     foreach( const QString& path, paths ) {
00152         slotFileDeleted( path );
00153     }
00154 }
00155 
00156 
00157 void Nepomuk::FileWatch::slotFileDeleted( const QString& urlString )
00158 {
00159     KUrl url( urlString );
00160 
00161     kDebug() << url;
00162 
00163     if ( mainModel() ) {
00164         removeMetaData( url );
00165 
00166         // remove child annotations in case it is a local folder
00167         foreach( Soprano::Node node, queryChildren( mainModel(), url.path() ).iterateBindings( 0 ).allNodes() ) {
00168             mainModel()->removeAllStatements( Statement( node, Node(), Node() ) );
00169         }
00170     }
00171     else {
00172         kDebug() << "Could not contact Nepomuk server.";
00173     }
00174 }
00175 
00176 
00177 void Nepomuk::FileWatch::removeMetaData( const KUrl& url )
00178 {
00179     kDebug() << url;
00180 
00181     if ( url.isEmpty() ) {
00182         kDebug() << "empty path. Looks like a bug somewhere...";
00183         return;
00184     }
00185 
00186     mainModel()->removeAllStatements( Statement( url, Node(), Node() ) );
00187 
00188     // FIXME: what about the triples that have our uri as object?
00189 }
00190 
00191 
00192 void Nepomuk::FileWatch::updateMetaData( const KUrl& from, const KUrl& to )
00193 {
00194     kDebug() << from << "->" << to;
00195 
00196     //
00197     // Nepomuk allows annotating of remote files. These files do not necessarily have a xesam:url property
00198     // since it would not be of much use in the classic sense: we cannot use it to locate the file on the hd
00199     //
00200     // Thus, when remote files are moved through KIO and we get the notification, we simply change all triples
00201     // referring to the original file to use the new URL
00202     //
00203 
00204     Soprano::Node oldResource = from;
00205     Soprano::Node newResource = to;
00206 
00207     // update the resource itself
00208     // -----------------------------------------------
00209     if ( mainModel()->containsAnyStatement( Soprano::Statement( oldResource, Soprano::Node(), Soprano::Node() ) ) ) {
00210 
00211         QList<Soprano::Statement> sl = mainModel()->listStatements( Soprano::Statement( oldResource,
00212                                                                                         Soprano::Node(),
00213                                                                                         Soprano::Node() ) ).allStatements();
00214         Q_FOREACH( Soprano::Statement s, sl ) {
00215             if ( s.predicate() == Soprano::Vocabulary::Xesam::url() ) {
00216                 mainModel()->addStatement( Soprano::Statement( newResource,
00217                                                                s.predicate(),
00218                                                                Soprano::LiteralValue( to.path() ),
00219                                                                s.context() ) );
00220             }
00221             else if ( s.predicate() == m_strigiParentUrlUri ) {
00222                 mainModel()->addStatement( Soprano::Statement( newResource,
00223                                                                s.predicate(),
00224                                                                Soprano::LiteralValue( to.directory( KUrl::IgnoreTrailingSlash ) ),
00225                                                                s.context() ) );
00226             }
00227             else {
00228                 mainModel()->addStatement( Soprano::Statement( newResource,
00229                                                                s.predicate(),
00230                                                                s.object(),
00231                                                                s.context() ) );
00232             }
00233         }
00234 
00235         mainModel()->removeStatements( sl );
00236         // -----------------------------------------------
00237 
00238 
00239         // update resources relating to it
00240         // -----------------------------------------------
00241         sl = mainModel()->listStatements( Statement( Node(),
00242                                                      Node(),
00243                                                      oldResource ) ).allStatements();
00244         Q_FOREACH( Soprano::Statement s, sl ) {
00245             mainModel()->addStatement( Soprano::Statement( s.subject(),
00246                                                            s.predicate(),
00247                                                            newResource,
00248                                                            s.context() ) );
00249         }
00250         mainModel()->removeStatements( sl );
00251         // -----------------------------------------------
00252     }
00253 }
00254 
00255 #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.7
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