00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
00043
00044
00045
00046
00047
00048
00049
00050
00051
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
00064 QString regexpPath( path );
00065 if ( regexpPath[regexpPath.length()-1] != '/' ) {
00066 regexpPath += '/';
00067 }
00068 regexpPath.replace( QRegExp( "([\\.\\?\\*\\\\+\\(\\)\\\\\\|\\[\\]{}])" ), "\\\\\\1" );
00069
00070
00071
00072
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
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
00112
00113 removeMetaData( to );
00114
00115
00116 updateMetaData( from, to );
00117
00118
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 );
00127 }
00128
00129
00130
00131
00132
00133
00134
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
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
00184 }
00185
00186
00187 void Nepomuk::FileWatch::updateMetaData( const KUrl& from, const KUrl& to )
00188 {
00189 kDebug() << from << "->" << to;
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199 Soprano::Node oldResource = from;
00200 Soprano::Node newResource = to;
00201
00202
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
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"