Sophie

Sophie

distrib > Mandriva > 2010.1 > i586 > media > main-testing-src > by-pkgid > 357e0466909645e33fa8bfa6e2222a8a > files > 17

kdebase4-runtime-4.4.5-0.1mdv2010.2.src.rpm

From 48fc3e119087a427f88525117e429c5d9e6d0de4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicolas=20L=C3=A9cureuil?= <nlecureuil@mandriva.com>
Date: Fri, 17 Dec 2010 20:39:15 +0100
Subject: [PATCH] Update nepomuk to kde 4.5

---
 nepomuk/interfaces/org.kde.nepomuk.FileWatch.xml   |    9 +
 nepomuk/interfaces/org.kde.nepomuk.Query.xml       |    6 +
 .../org.kde.nepomuk.RemovableStorage.xml           |    3 +
 nepomuk/interfaces/org.kde.nepomuk.Strigi.xml      |    6 +
 nepomuk/kcm/CMakeLists.txt                         |    1 +
 nepomuk/kcm/kcm_nepomuk.desktop                    |    6 +-
 nepomuk/kcm/nepomukconfigwidget.ui                 |    6 +-
 nepomuk/kcm/nepomukserverkcm.cpp                   |   21 +-
 nepomuk/kioslaves/common/nepomuksearchurltools.h   |   21 -
 nepomuk/kioslaves/common/resourcestat.cpp          |  382 ++++++++++++++++++
 nepomuk/kioslaves/common/resourcestat.h            |  109 +++++
 nepomuk/kioslaves/common/timelinetools.cpp         |  173 ++++++++
 nepomuk/kioslaves/common/timelinetools.h           |   50 +++
 nepomuk/kioslaves/nepomuk/CMakeLists.txt           |    3 +-
 nepomuk/kioslaves/nepomuk/kio_nepomuk.cpp          |  403 +------------------
 nepomuk/kioslaves/nepomuk/kio_nepomuk.h            |    8 -
 nepomuk/kioslaves/search/CMakeLists.txt            |    2 +
 nepomuk/kioslaves/search/kdedmodule/CMakeLists.txt |   11 +
 .../search/kdedmodule/nepomuksearchmodule.cpp      |   64 ++-
 .../search/kdedmodule/nepomuksearchmodule.desktop  |   25 +-
 .../search/kdedmodule/nepomuksearchmodule.h        |    8 +-
 .../search/kdedmodule/searchurllistener.cpp        |   16 +-
 .../search/kdedmodule/searchurllistener.h          |    3 +-
 nepomuk/kioslaves/search/kio_nepomuksearch.cpp     |  148 ++------
 nepomuk/kioslaves/search/kio_nepomuksearch.h       |   10 -
 nepomuk/kioslaves/search/nepomuksearch.protocol    |    1 +
 nepomuk/kioslaves/search/searchfolder.cpp          |  110 ++++--
 nepomuk/kioslaves/search/searchfolder.h            |   27 ++-
 nepomuk/kioslaves/timeline/CMakeLists.txt          |   21 +-
 nepomuk/kioslaves/timeline/kio_timeline.cpp        |  273 ++++----------
 nepomuk/kioslaves/timeline/kio_timeline.h          |   17 -
 nepomuk/server/CMakeLists.txt                      |    1 -
 nepomuk/server/nepomukserver.cpp                   |   18 +-
 nepomuk/server/nepomukserver.desktop               |   12 +-
 nepomuk/server/nepomukserver.h                     |    3 -
 nepomuk/server/nepomukservice.desktop              |    1 +
 nepomuk/server/processcontrol.cpp                  |   17 +-
 nepomuk/server/processcontrol.h                    |    2 +
 nepomuk/server/servicecontroller.cpp               |   89 +++--
 nepomuk/server/servicecontroller.h                 |    5 +-
 nepomuk/server/servicemanager.cpp                  |   55 +--
 nepomuk/services/CMakeLists.txt                    |    2 +
 nepomuk/services/activities/CMakeLists.txt         |   48 +++
 .../activities/nepomukactivitiesservice.cpp        |  321 +++++++++++++++
 .../activities/nepomukactivitiesservice.desktop    |   57 +++
 .../services/activities/nepomukactivitiesservice.h |  162 ++++++++
 .../org.kde.nepomuk.ActivitiesService.xml          |   70 ++++
 nepomuk/services/filewatch/CMakeLists.txt          |   11 +
 .../filewatch/invalidfileresourcecleaner.cpp       |   86 ++++
 .../filewatch/invalidfileresourcecleaner.h         |   64 +++
 nepomuk/services/filewatch/kinotify.cpp            |  420 ++++++++++++++++++++
 nepomuk/services/filewatch/kinotify.h              |  176 ++++++++
 nepomuk/services/filewatch/metadatamover.cpp       |  201 ++++++++--
 nepomuk/services/filewatch/metadatamover.h         |   12 +-
 nepomuk/services/filewatch/nepomukfilewatch.cpp    |  142 ++++++-
 .../services/filewatch/nepomukfilewatch.desktop    |    6 +-
 nepomuk/services/filewatch/nepomukfilewatch.h      |   27 +-
 .../services/migration1/nepomukmigration1.desktop  |    2 +
 .../ontologyloader/nepomukontologyloader.desktop   |    2 +
 nepomuk/services/ontologyloader/ontologyloader.cpp |   10 +-
 nepomuk/services/queryservice/folder.h             |    2 +
 nepomuk/services/queryservice/folderconnection.cpp |   12 +
 nepomuk/services/queryservice/folderconnection.h   |    7 +
 .../queryservice/nepomukqueryservice.desktop       |   11 +-
 nepomuk/services/queryservice/queryservice.cpp     |   31 +-
 nepomuk/services/queryservice/queryservice.h       |    6 +-
 nepomuk/services/queryservice/searchthread.cpp     |   38 ++-
 nepomuk/services/queryservice/searchthread.h       |    2 +-
 nepomuk/services/removablestorage/CMakeLists.txt   |    1 +
 .../nepomukremovablestorageservice.desktop         |   22 +-
 .../removablestorage/removablestorageservice.cpp   |   57 +++-
 .../removablestorage/removablestorageservice.h     |    3 +
 nepomuk/services/storage/nepomukcore.cpp           |    2 +-
 nepomuk/services/storage/nepomukstorage.desktop    |    8 +-
 nepomuk/services/storage/nepomukstorage.notifyrc   |  270 ++++++-------
 nepomuk/services/storage/repository.cpp            |    5 +-
 nepomuk/services/strigi/CMakeLists.txt             |    8 +-
 nepomuk/services/strigi/eventmonitor.cpp           |   69 +++-
 nepomuk/services/strigi/eventmonitor.h             |   13 +-
 nepomuk/services/strigi/indexscheduler.cpp         |  101 ++++-
 nepomuk/services/strigi/indexscheduler.h           |    9 +-
 .../services/strigi/nepomukstrigiservice.desktop   |    6 +-
 .../services/strigi/nepomukstrigiservice.notifyrc  |  145 ++++---
 nepomuk/services/strigi/statuswidget.cpp           |    2 +-
 nepomuk/services/strigi/strigiservice.cpp          |  116 +++---
 nepomuk/services/strigi/strigiservice.h            |   15 +-
 nepomuk/services/strigi/strigiserviceadaptor.cpp   |   37 ++-
 nepomuk/services/strigi/strigiserviceadaptor.h     |   12 +
 nepomuk/services/strigi/strigiserviceconfig.cpp    |    8 +-
 nepomuk/services/strigi/systray.cpp                |    2 +-
 nepomuk/servicestub/CMakeLists.txt                 |    1 +
 nepomuk/servicestub/main.cpp                       |   23 +-
 nepomuk/servicestub/priority.cpp                   |  105 +++++
 nepomuk/servicestub/priority.h                     |   26 ++
 nepomuk/strigibackend/CMakeLists.txt               |    5 +
 nepomuk/strigibackend/nepomukindexwriter.cpp       |   75 ++--
 96 files changed, 3766 insertions(+), 1454 deletions(-)
 create mode 100644 nepomuk/interfaces/org.kde.nepomuk.FileWatch.xml
 create mode 100644 nepomuk/kioslaves/common/resourcestat.cpp
 create mode 100644 nepomuk/kioslaves/common/resourcestat.h
 create mode 100644 nepomuk/kioslaves/common/timelinetools.cpp
 create mode 100644 nepomuk/kioslaves/common/timelinetools.h
 create mode 100644 nepomuk/services/activities/CMakeLists.txt
 create mode 100644 nepomuk/services/activities/nepomukactivitiesservice.cpp
 create mode 100644 nepomuk/services/activities/nepomukactivitiesservice.desktop
 create mode 100644 nepomuk/services/activities/nepomukactivitiesservice.h
 create mode 100644 nepomuk/services/activities/org.kde.nepomuk.ActivitiesService.xml
 create mode 100644 nepomuk/services/filewatch/invalidfileresourcecleaner.cpp
 create mode 100644 nepomuk/services/filewatch/invalidfileresourcecleaner.h
 create mode 100644 nepomuk/services/filewatch/kinotify.cpp
 create mode 100644 nepomuk/services/filewatch/kinotify.h
 create mode 100644 nepomuk/servicestub/priority.cpp
 create mode 100644 nepomuk/servicestub/priority.h

diff --git a/nepomuk/interfaces/org.kde.nepomuk.FileWatch.xml b/nepomuk/interfaces/org.kde.nepomuk.FileWatch.xml
new file mode 100644
index 0000000..e2784a2
--- /dev/null
+++ b/nepomuk/interfaces/org.kde.nepomuk.FileWatch.xml
@@ -0,0 +1,9 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+          "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+  <interface name="org.kde.nepomuk.FileWatch">
+    <method name="watchFolder">
+      <arg name="path" type="s" direction="in"/>
+    </method>
+  </interface>
+</node>
diff --git a/nepomuk/interfaces/org.kde.nepomuk.Query.xml b/nepomuk/interfaces/org.kde.nepomuk.Query.xml
index ed43ef9..4be3707 100644
--- a/nepomuk/interfaces/org.kde.nepomuk.Query.xml
+++ b/nepomuk/interfaces/org.kde.nepomuk.Query.xml
@@ -5,6 +5,12 @@
     <method name="list" />
     <method name="listen" />
     <method name="close" />
+    <method name="isListingFinished">
+      <arg type="b" direction="out" />
+    </method>
+    <method name="queryString">
+      <arg type="s" direction="out" />
+    </method>
     <signal name="newEntries">
       <arg name="entries" type="a(sda{s(isss)})" />
       <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="QList&lt;Nepomuk::Query::Result&gt;" />
diff --git a/nepomuk/interfaces/org.kde.nepomuk.RemovableStorage.xml b/nepomuk/interfaces/org.kde.nepomuk.RemovableStorage.xml
index 452ad07..38a29ea 100644
--- a/nepomuk/interfaces/org.kde.nepomuk.RemovableStorage.xml
+++ b/nepomuk/interfaces/org.kde.nepomuk.RemovableStorage.xml
@@ -6,5 +6,8 @@
       <arg type="s" direction="out"/>
       <arg name="url" type="s" direction="in"/>
     </method>
+    <method name="currentlyMountedAndIndexed">
+      <arg type="as" direction="out"/>
+    </method>
   </interface>
 </node>
diff --git a/nepomuk/interfaces/org.kde.nepomuk.Strigi.xml b/nepomuk/interfaces/org.kde.nepomuk.Strigi.xml
index ff28976..df0b109 100644
--- a/nepomuk/interfaces/org.kde.nepomuk.Strigi.xml
+++ b/nepomuk/interfaces/org.kde.nepomuk.Strigi.xml
@@ -11,6 +11,9 @@
     <method name="currentFolder">
       <arg type="s" direction="out" />
     </method>
+    <method name="currentFile">
+      <arg type="s" direction="out" />
+    </method>
     <method name="suspend" />
     <method name="resume" />
     <method name="updateFolder">
@@ -24,6 +27,9 @@
       <arg name="path" type="s" direction="in" />
       <arg name="forced" type="b" direction="in" />
     </method>
+    <method name="indexFile">
+      <arg name="path" type="s" direction="in" />
+    </method>
     <method name="analyzeResource" >
       <arg name="uri" direction="in" type="s" />
       <arg name="lastModificationDate" direction="in" type="u" />
diff --git a/nepomuk/kcm/CMakeLists.txt b/nepomuk/kcm/CMakeLists.txt
index 6803a80..874d848 100644
--- a/nepomuk/kcm/CMakeLists.txt
+++ b/nepomuk/kcm/CMakeLists.txt
@@ -15,6 +15,7 @@ set(kcmnepomuk_SRCS
 
 qt4_add_dbus_interface(kcmnepomuk_SRCS ../interfaces/org.kde.NepomukServer.xml nepomukserverinterface)
 qt4_add_dbus_interface(kcmnepomuk_SRCS ../interfaces/org.kde.nepomuk.ServiceManager.xml nepomukservicemanagerinterface)
+qt4_add_dbus_interface(kcmnepomuk_SRCS ../interfaces/org.kde.nepomuk.ServiceControl.xml nepomukservicecontrolinterface)
 qt4_add_dbus_interface(kcmnepomuk_SRCS ../interfaces/org.kde.nepomuk.Strigi.xml strigiserviceinterface)
 
 kde4_add_ui_files(kcmnepomuk_SRCS
diff --git a/nepomuk/kcm/kcm_nepomuk.desktop b/nepomuk/kcm/kcm_nepomuk.desktop
index 85b0454..6795fb9 100644
--- a/nepomuk/kcm/kcm_nepomuk.desktop
+++ b/nepomuk/kcm/kcm_nepomuk.desktop
@@ -8,7 +8,7 @@ X-DocPath=kcontrol/nepomuk/index.html
 X-KDE-ServiceTypes=KCModule
 X-KDE-Library=kcm_nepomuk
 X-KDE-ParentApp=kcontrol
-X-KDE-System-Settings-Parent-Category=advanced-user-settings
+X-KDE-System-Settings-Parent-Category=workspace-appearance-and-behavior
 
 Name=Desktop Search
 Name[ar]=بحث سطح المكتب
@@ -40,6 +40,7 @@ Name[hne]=डेस्कटाप खोज
 Name[hr]=Pretraživanje računala
 Name[hsb]=Pytanje za dźěłowy powjerch
 Name[hu]=Asztali keresés
+Name[ia]=Cerca de Scriptorio
 Name[id]=Pencarian Desktop
 Name[is]=Skjáborðsleit
 Name[it]=Ricerca desktop
@@ -65,7 +66,7 @@ Name[pl]=Wyszukiwanie na pulpicie
 Name[pt]=Pesquisa no Ambiente de Trabalho
 Name[pt_BR]=Pesquisa na área de trabalho
 Name[ro]=Căutare de birou
-Name[ru]=Поиск в рабочей среде
+Name[ru]=Поиск по меткам и содержимому
 Name[si]=වැඩතල සෙවුම
 Name[sk]=Hľadanie na ploche
 Name[sl]=Namizno iskanje
@@ -115,6 +116,7 @@ Comment[hne]=नेपोमक/स्ट्रिगि सेवा कान
 Comment[hr]=Konfiguracija Nepomuk/Strigi poslužitelja
 Comment[hsb]=Připrawjenje Nepomuk/Strigi-Serwera
 Comment[hu]=A Nepomuk/Strigi szolgáltatás beállítása
+Comment[ia]=Configuration de servitor Nepomuk/Strigi
 Comment[id]=Konfigurasi Server Nepomuk/Strigi
 Comment[is]=Nepomuk/Strigi miðlarastillingar
 Comment[it]=Configurazione dei server di Nepomuk/Strigi
diff --git a/nepomuk/kcm/nepomukconfigwidget.ui b/nepomuk/kcm/nepomukconfigwidget.ui
index 57f2aa2..3267a87 100644
--- a/nepomuk/kcm/nepomukconfigwidget.ui
+++ b/nepomuk/kcm/nepomukconfigwidget.ui
@@ -158,7 +158,7 @@
              <string>Index the files on removable media like USB sticks when they are mounted</string>
             </property>
             <property name="text">
-             <string>Index Files on Removable Media</string>
+             <string>Index files on removable media</string>
             </property>
            </widget>
           </item>
@@ -194,7 +194,7 @@
           <item>
            <widget class="QLabel" name="label_4">
             <property name="text">
-             <string>The maximum amount of memory the Nepomuk database should use. The more memory Nepomuk has the more performant it will be.</string>
+             <string>&lt;p&gt;The maximum amount of main memory the Nepomuk system should use for its database process. The more memory is available to Nepomuk the better will be its performance. (The Nepomuk database process shows up as &lt;command&gt;virtuoso-t&lt;/command&gt; in the process manager.)</string>
             </property>
             <property name="wordWrap">
              <bool>true</bool>
@@ -222,7 +222,7 @@
             <item>
              <widget class="QSpinBox" name="m_editMemoryUsage">
               <property name="suffix">
-               <string> MB</string>
+               <string> MiB</string>
               </property>
               <property name="minimum">
                <number>50</number>
diff --git a/nepomuk/kcm/nepomukserverkcm.cpp b/nepomuk/kcm/nepomukserverkcm.cpp
index f47ec58..46e6287 100644
--- a/nepomuk/kcm/nepomukserverkcm.cpp
+++ b/nepomuk/kcm/nepomukserverkcm.cpp
@@ -19,6 +19,7 @@
 #include "nepomukserverkcm.h"
 #include "nepomukserverinterface.h"
 #include "folderselectionmodel.h"
+#include "nepomukservicecontrolinterface.h"
 #include "../services/strigi/strigiservicedefaults.h"
 
 #include <KPluginFactory>
@@ -28,6 +29,7 @@
 #include <KMessageBox>
 
 #include <QtGui/QTreeView>
+#include <QtDBus/QDBusServiceWatcher>
 
 #include <Soprano/PluginManager>
 
@@ -117,10 +119,15 @@ Nepomuk::ServerConfigModule::ServerConfigModule( QWidget* parent, const QVariant
     connect( m_checkShowHiddenFolders, SIGNAL( toggled( bool ) ),
              m_folderModel, SLOT( setHiddenFoldersShown( bool ) ) );
 
-    connect( QDBusConnection::sessionBus().interface(),
-             SIGNAL( serviceOwnerChanged( const QString&, const QString&, const QString& ) ),
-             this,
-             SLOT( slotUpdateStrigiStatus() ) );
+    QDBusServiceWatcher * watcher = new QDBusServiceWatcher( this );
+    watcher->addWatchedService( QLatin1String("org.kde.nepomuk.services.nepomukstrigiservice") );
+    watcher->setConnection( QDBusConnection::sessionBus() );
+    watcher->setWatchMode( QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration );
+
+    connect( watcher, SIGNAL( serviceRegistered(const QString&) ),
+             this, SLOT( slotUpdateStrigiStatus() ) );
+    connect( watcher, SIGNAL( serviceUnregistered(const QString&) ),
+             this, SLOT( slotUpdateStrigiStatus() ) );
 
     recreateStrigiInterface();
 }
@@ -250,8 +257,10 @@ void Nepomuk::ServerConfigModule::defaults()
 
 void Nepomuk::ServerConfigModule::slotUpdateStrigiStatus()
 {
-    if ( m_serviceManagerInterface.isServiceRunning( "nepomukstrigiservice") ) {
-        if ( m_serviceManagerInterface.isServiceInitialized( "nepomukstrigiservice") ) {
+    if ( QDBusConnection::sessionBus().interface()->isServiceRegistered( "org.kde.nepomuk.services.nepomukstrigiservice" ) ) {
+        if ( org::kde::nepomuk::ServiceControl( "org.kde.nepomuk.services.nepomukstrigiservice",
+                                                "/servicecontrol",
+                                                QDBusConnection::sessionBus() ).isInitialized() ) {
             QString status = m_strigiInterface->userStatusString();
             if ( status.isEmpty() ) {
                 m_labelStrigiStatus->setText( i18nc( "@info:status %1 is an error message returned by a dbus interface.",
diff --git a/nepomuk/kioslaves/common/nepomuksearchurltools.h b/nepomuk/kioslaves/common/nepomuksearchurltools.h
index 7f16070..ee5fd94 100644
--- a/nepomuk/kioslaves/common/nepomuksearchurltools.h
+++ b/nepomuk/kioslaves/common/nepomuksearchurltools.h
@@ -47,27 +47,6 @@ namespace Nepomuk {
     {
         return QUrl::fromEncoded( QByteArray::fromPercentEncoding( name.toAscii(), '_' ) );
     }
-
-    /**
-     * Extract SPARQL query from a nepomuksearch query URL.
-     */
-    inline QString queryFromUrl( const KUrl& url ) {
-        if(url.queryItems().contains( "sparql" ) ) {
-            return url.queryItem( "sparql" );
-        }
-        else {
-            QString plainQuery;
-            if(url.queryItems().contains( "query" ) ) {
-                plainQuery = url.queryItem( "query" );
-            }
-            else {
-                plainQuery = url.path().section( '/', 0, 0, QString::SectionSkipEmpty );
-            }
-            Query::Query query = Query::QueryParser::parseQuery( plainQuery );
-            query.addRequestProperty( Query::Query::RequestProperty( Nepomuk::Vocabulary::NIE::url(), true ) );
-            return query.toSparqlQuery();
-        }
-    }
 }
 
 #endif
diff --git a/nepomuk/kioslaves/common/resourcestat.cpp b/nepomuk/kioslaves/common/resourcestat.cpp
new file mode 100644
index 0000000..cf527a4
--- /dev/null
+++ b/nepomuk/kioslaves/common/resourcestat.cpp
@@ -0,0 +1,382 @@
+/*
+   Copyright 2008-2010 Sebastian Trueg <trueg@kde.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License or (at your option) version 3 or any later version
+   accepted by the membership of KDE e.V. (or its successor approved
+   by the membership of KDE e.V.), which shall act as a proxy
+   defined in Section 14 of version 3 of the license.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "resourcestat.h"
+#include "nepomuksearchurltools.h"
+#include "nie.h"
+#include "nfo.h"
+#include "pimo.h"
+
+#include <QtCore/QEventLoop>
+#include <QtCore/QTimer>
+#include <QtCore/QFile>
+
+#include <KUrl>
+#include <KMimeType>
+#include <KUser>
+#include <kio/udsentry.h>
+#include <KDebug>
+
+#include <Nepomuk/Thing>
+#include <Nepomuk/Variant>
+#include <Nepomuk/Types/Class>
+#include <Nepomuk/ResourceManager>
+#include <Nepomuk/Query/Query>
+#include <Nepomuk/Query/ComparisonTerm>
+#include <Nepomuk/Query/ResourceTerm>
+
+#include <Soprano/Vocabulary/RDF>
+#include <Soprano/Vocabulary/NAO>
+#include <Soprano/QueryResultIterator>
+#include <Soprano/NodeIterator>
+#include <Soprano/Node>
+#include <Soprano/Model>
+
+#include <Solid/Device>
+#include <Solid/StorageAccess>
+
+
+KUrl Nepomuk::stripQuery( const KUrl& url )
+{
+    KUrl newUrl( url );
+    newUrl.setEncodedQuery( QByteArray() );
+    return newUrl;
+}
+
+
+Nepomuk::Resource Nepomuk::splitNepomukUrl( const KUrl& url, QString* filename )
+{
+    //
+    // let's try to extract the resource from the url in case we listed a tag or
+    // filesystem and need to stat the entries in those virtual folders
+    //
+    // pre KDE 4.4 resources had just a single section, in KDE 4.4 we have "/res/<UUID>"
+    //
+    QString urlStr = stripQuery( url ).url();
+    int pos = urlStr.indexOf( '/', urlStr.startsWith( QLatin1String( "nepomuk:/res/" ) ) ? 13 : 9 );
+    if ( pos > 0 ) {
+        KUrl resourceUri = urlStr.left(pos);
+        if ( filename )
+            *filename = urlStr.mid( pos+1 );
+        return resourceUri;
+    }
+    else {
+        return stripQuery( url );
+    }
+}
+
+
+bool Nepomuk::isRemovableMediaFile( const Nepomuk::Resource& res )
+{
+    if ( res.hasProperty( Nepomuk::Vocabulary::NIE::url() ) ) {
+        KUrl url = res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl();
+        return ( url.protocol() == QLatin1String( "filex" ) );
+    }
+    else {
+        return false;
+    }
+}
+
+
+Solid::StorageAccess* Nepomuk::storageFromUUID( const QString& uuid )
+{
+    QString solidQuery = QString::fromLatin1( "[ StorageVolume.usage=='FileSystem' AND StorageVolume.uuid=='%1' ]" ).arg( uuid.toLower() );
+    QList<Solid::Device> devices = Solid::Device::listFromQuery( solidQuery );
+    kDebug() << uuid << solidQuery << devices.count();
+    if ( !devices.isEmpty() )
+        return devices.first().as<Solid::StorageAccess>();
+    else
+        return 0;
+}
+
+
+bool Nepomuk::mountAndWait( Solid::StorageAccess* storage )
+{
+    kDebug() << storage;
+    QEventLoop loop;
+    loop.connect( storage,
+                  SIGNAL(accessibilityChanged(bool, QString)),
+                  SLOT(quit()) );
+    // timeout 20 second
+    QTimer::singleShot( 20000, &loop, SLOT(quit()) );
+
+    storage->setup();
+    loop.exec();
+
+    kDebug() << storage << storage->isAccessible();
+
+    return storage->isAccessible();
+}
+
+
+KUrl Nepomuk::determineFilesystemPath( const Nepomuk::Resource& fsRes )
+{
+    QString uuidQuery = QString::fromLatin1( "select ?uuid where { %1 %2 ?uuid . }" )
+                        .arg( Soprano::Node::resourceToN3( fsRes.resourceUri() ),
+                              Soprano::Node::resourceToN3( Soprano::Vocabulary::NAO::identifier() ) );
+    Soprano::QueryResultIterator it = Nepomuk::ResourceManager::instance()->mainModel()->executeQuery( uuidQuery, Soprano::Query::QueryLanguageSparql );
+    if ( it.next() ) {
+        Solid::StorageAccess* storage = storageFromUUID( it["uuid"].toString() );
+        it.close();
+        if ( storage &&
+             ( storage->isAccessible() ||
+               mountAndWait( storage ) ) ) {
+            return storage->filePath();
+        }
+    }
+    return KUrl();
+}
+
+
+QString Nepomuk::getFileSystemLabelForRemovableMediaFileUrl( const Nepomuk::Resource& res )
+{
+    QList<Soprano::Node> labelNodes
+        = Nepomuk::ResourceManager::instance()->mainModel()->executeQuery( QString::fromLatin1( "select ?label where { "
+                                                                                                "%1 nie:isPartOf ?fs . "
+                                                                                                "?fs a nfo:Filesystem . "
+                                                                                                "?fs nao:prefLabel ?label . "
+                                                                                                "} LIMIT 1" )
+                                                                           .arg( Soprano::Node::resourceToN3( res.resourceUri() ) ),
+                                                                           Soprano::Query::QueryLanguageSparql ).iterateBindings( "label" ).allNodes();
+
+    if ( !labelNodes.isEmpty() )
+        return labelNodes.first().toString();
+    else
+        return res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl().host(); // Solid UUID
+}
+
+
+KUrl Nepomuk::convertRemovableMediaFileUrl( const KUrl& url, bool evenMountIfNecessary )
+{
+    Solid::StorageAccess* storage = Nepomuk::storageFromUUID( url.host() );
+    kDebug() << url << storage;
+    if ( storage &&
+         ( storage->isAccessible() ||
+           ( evenMountIfNecessary && Nepomuk::mountAndWait( storage ) ) ) ) {
+        kDebug() << "converted:" << KUrl( storage->filePath() + QLatin1String( "/" ) + url.path() );
+        return storage->filePath() + QLatin1String( "/" ) + url.path();
+    }
+    else {
+        return KUrl();
+    }
+}
+
+
+KIO::UDSEntry Nepomuk::statNepomukResource( const Nepomuk::Resource& res )
+{
+    //
+    // We do not have a local file
+    // This is where the magic starts to happen.
+    // This is where we only use Nepomuk properties
+    //
+    KIO::UDSEntry uds;
+
+    // we handle files on removable media which are not mounted
+    // as a special case
+    bool isFileOnRemovableMedium = isRemovableMediaFile( res );
+
+    // The display name can be anything
+    QString displayName;
+    if ( isFileOnRemovableMedium ) {
+        displayName = i18nc( "%1 is a filename of a file on a removable device, "
+                             "%2 is the name of the removable medium which often is something like "
+                             "'X GiB Removable Media.",
+                             "%1 (on unmounted medium <resource>%2</resource>)",
+                             res.genericLabel(),
+                             getFileSystemLabelForRemovableMediaFileUrl( res ) );
+    }
+    else {
+        displayName = res.genericLabel();
+    }
+    uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, displayName );
+
+    // UDS_NAME needs to be unique but can be ugly
+    uds.insert( KIO::UDSEntry::UDS_NAME, resourceUriToUdsName( res.resourceUri() ) );
+
+    //
+    // There can still be file resources that have a mimetype but are
+    // stored remotely, thus they do not have a local nie:url
+    //
+    // Sadly Strigi's mimetype is not very useful (yet)
+    /* QStringList mimeTypes = res.property( Vocabulary::NIE::mimeType() ).toStringList();
+    if ( !mimeTypes.isEmpty() ) {
+        uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, mimeTypes.first() );
+    }
+    else */
+    if ( isFileOnRemovableMedium ) {
+        KMimeType::Ptr mt = KMimeType::findByUrl( res.property( Vocabulary::NIE::url() ).toUrl(),
+                                                  0,
+                                                  false, /* no local file as it is not accessible at the moment */
+                                                  true   /* fast mode */ );
+        if ( mt ) {
+            uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, mt->name() );
+        }
+    }
+    else {
+        // Use nice display types like "Person", "Project" and so on
+        Nepomuk::Types::Class type( res.resourceType() );
+        if (!type.label().isEmpty())
+            uds.insert( KIO::UDSEntry::UDS_DISPLAY_TYPE, type.label() );
+
+        QString icon = res.genericIcon();
+        if ( !icon.isEmpty() ) {
+            uds.insert( KIO::UDSEntry::UDS_ICON_NAME, icon );
+        }
+        else {
+            // a fallback icon for nepomuk resources
+            uds.insert( KIO::UDSEntry::UDS_ICON_NAME, QLatin1String( "nepomuk" ) );
+        }
+
+        if ( uds.stringValue( KIO::UDSEntry::UDS_ICON_NAME ) != QLatin1String( "nepomuk" ) )
+            uds.insert( KIO::UDSEntry::UDS_ICON_OVERLAY_NAMES, QLatin1String( "nepomuk" ) );
+    }
+
+    //
+    // Add some random values
+    //
+    uds.insert( KIO::UDSEntry::UDS_ACCESS, 0700 );
+    uds.insert( KIO::UDSEntry::UDS_USER, KUser().loginName() );
+    if ( res.hasProperty( Vocabulary::NIE::lastModified() ) ) {
+        // remotely stored files
+        uds.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, res.property( Vocabulary::NIE::lastModified() ).toDateTime().toTime_t() );
+    }
+    else {
+        // all nepomuk resources
+        uds.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, res.property( Soprano::Vocabulary::NAO::lastModified() ).toDateTime().toTime_t() );
+        uds.insert( KIO::UDSEntry::UDS_CREATION_TIME, res.property( Soprano::Vocabulary::NAO::created() ).toDateTime().toTime_t() );
+    }
+
+    if ( res.hasProperty( Vocabulary::NIE::contentSize() ) ) {
+        // remotely stored files
+        uds.insert( KIO::UDSEntry::UDS_SIZE, res.property( Vocabulary::NIE::contentSize() ).toInt() );
+    }
+
+
+    //
+    // Starting with KDE 4.4 we have the pretty UDS_NEPOMUK_URI which makes
+    // everything much cleaner since kio slaves can decide if the resources can be
+    // annotated or not.
+    //
+    uds.insert( KIO::UDSEntry::UDS_NEPOMUK_URI, KUrl( res.resourceUri() ).url() );
+
+    KUrl reUrl = Nepomuk::redirectionUrl( res );
+    if ( !reUrl.isEmpty() ) {
+        uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, QLatin1String( "inode/directory" ) );
+        uds.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
+
+        // FIXME: not sure this is necessary if we already do the redirect in listDir()
+        uds.insert( KIO::UDSEntry::UDS_URL, reUrl.url() );
+    }
+
+    return uds;
+}
+
+
+bool Nepomuk::willBeRedirected( const Nepomuk::Resource& res )
+{
+    return( res.hasType( Nepomuk::Vocabulary::NFO::Folder() ) ||
+            res.hasType( Soprano::Vocabulary::NAO::Tag() ) ||
+            res.hasType( Nepomuk::Vocabulary::NFO::Filesystem() ) );
+}
+
+
+KUrl Nepomuk::redirectionUrl( const Nepomuk::Resource& res )
+{
+    if ( res.hasType( Nepomuk::Vocabulary::NFO::Folder() ) ) {
+        return res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl();
+    }
+    else if ( res.hasType( Nepomuk::Vocabulary::NFO::Filesystem() ) ) {
+        KUrl fsUrl = determineFilesystemPath( res );
+        if ( fsUrl.isValid() ) {
+            return fsUrl;
+        }
+    }
+    else if ( res.hasType( Soprano::Vocabulary::NAO::Tag() ) ) {
+        Query::ComparisonTerm term( Soprano::Vocabulary::NAO::hasTag(), Query::ResourceTerm( res ), Query::ComparisonTerm::Equal );
+        KUrl queryUrl( Query::Query( term ).toSearchUrl() );
+        queryUrl.addQueryItem( QLatin1String( "title" ), i18n( "Things tagged '%1'", res.genericLabel() ) );
+        return queryUrl.url();
+    }
+
+#if 0 // disabled as long as the strigi service does create a dedicated album resource for each track
+    else if ( res.hasType( Nepomuk::Vocabulary::NMM::MusicAlbum() ) ) {
+        Query::ComparisonTerm term( Nepomuk::Vocabulary::NMM::musicAlbum(), Query::ResourceTerm( res ) );
+        KUrl queryUrl( Query::Query( term ).toSearchUrl() );
+        queryUrl.addQueryItem( QLatin1String( "title" ), res.genericLabel() );
+        return queryUrl.url();
+    }
+#endif
+
+    return KUrl();
+}
+
+
+namespace {
+    /**
+     * Check if the resource represents a local file with an existing nie:url property.
+     */
+    bool isLocalFile( const Nepomuk::Resource& res )
+    {
+        if ( res.hasProperty( Nepomuk::Vocabulary::NIE::url() ) ) {
+            KUrl url = res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl();
+            return ( !url.isEmpty() &&
+                     QFile::exists( url.toLocalFile() ) );
+        }
+        else {
+            return false;
+        }
+    }
+}
+
+KUrl Nepomuk::nepomukToFileUrl( const KUrl& url, bool evenMountIfNecessary )
+{
+    QString filename;
+    Nepomuk::Resource res = splitNepomukUrl( url, &filename );
+
+    if ( !res.exists() )
+        return KUrl();
+
+    KUrl newURL;
+
+    //
+    // let's see if it is a pimo thing which refers to a file
+    //
+    if ( res.hasType( Nepomuk::Vocabulary::PIMO::Thing() ) ) {
+        if ( !res.pimoThing().groundingOccurrences().isEmpty() ) {
+            res = res.pimoThing().groundingOccurrences().first();
+        }
+    }
+
+    if ( isLocalFile( res ) ) {
+        newURL = res.property( Vocabulary::NIE::url() ).toUrl();
+    }
+    else if ( isRemovableMediaFile( res ) ) {
+        const KUrl removableMediaUrl = res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl();
+        newURL = convertRemovableMediaFileUrl( removableMediaUrl, evenMountIfNecessary );
+    }
+
+    if ( newURL.isValid() && !filename.isEmpty() ) {
+        newURL.addPath( filename );
+    }
+
+    kDebug() << url << newURL;
+
+    return newURL;
+}
diff --git a/nepomuk/kioslaves/common/resourcestat.h b/nepomuk/kioslaves/common/resourcestat.h
new file mode 100644
index 0000000..76a9bac
--- /dev/null
+++ b/nepomuk/kioslaves/common/resourcestat.h
@@ -0,0 +1,109 @@
+/*
+   Copyright 2008-2010 Sebastian Trueg <trueg@kde.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License or (at your option) version 3 or any later version
+   accepted by the membership of KDE e.V. (or its successor approved
+   by the membership of KDE e.V.), which shall act as a proxy
+   defined in Section 14 of version 3 of the license.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NEPOMUK_RESOURCE_STAT_H_
+#define _NEPOMUK_RESOURCE_STAT_H_
+
+class QString;
+class KUrl;
+namespace KIO {
+    class UDSEntry;
+}
+namespace Solid {
+    class StorageAccess;
+}
+
+namespace Nepomuk {
+
+    class Resource;
+
+    /**
+     * Remove all query parts from a KUrl.
+     */
+    KUrl stripQuery( const KUrl& url );
+
+    /**
+     * Split the filename part off a nepomuk:/ URI. This is used in many methods for identifying
+     * entries listed from tags and filesystems.
+     */
+    Nepomuk::Resource splitNepomukUrl( const KUrl& url, QString* filename = 0 );
+
+    /**
+     * Check if the resource represents a file on a removable media using a filex:/
+     * URL.
+     */
+    bool isRemovableMediaFile( const Nepomuk::Resource& res );
+
+    /**
+     * Create a Solid storage access interface from the volume UUID.
+     */
+    Solid::StorageAccess* storageFromUUID( const QString& uuid );
+
+    /**
+     * Mount a storage volume via Solid and wait for it to be mounted with
+     * a timeout of 20 seconds.
+     */
+    bool mountAndWait( Solid::StorageAccess* storage );
+
+    /**
+     * Get the mount path of a nfo:Filesystem resource as created by the removable storage service.
+     */
+    KUrl determineFilesystemPath( const Nepomuk::Resource& fsRes );
+
+    /**
+     * Determine the label for a filesystem \p res is stored on.
+     */
+    QString getFileSystemLabelForRemovableMediaFileUrl( const Nepomuk::Resource& res );
+
+    /**
+     * Convert a filex:/ URL into its actual local file URL.
+     *
+     * \param url The filex:/ URL to convert
+     * \param evenMountIfNecessary If true an existing unmouted volume will be mounted to grant access to the local file.
+     *
+     * \return The converted local URL or an invalid URL if the filesystem the file is stored on could not be/was not mounted.
+     */
+    KUrl convertRemovableMediaFileUrl( const KUrl& url, bool evenMountIfNecessary = false );
+
+    /**
+     * Stat a Nepomuk resource. Might start a local event loop
+     */
+    KIO::UDSEntry statNepomukResource( const Nepomuk::Resource& res );
+
+    /**
+     * \return \p true for all resources that will get a valid redirection url in
+     * redirectionUrl().
+     */
+    bool willBeRedirected( const Nepomuk::Resource& res );
+
+    /**
+     * Create a redirection query URL for resources such as tags or filesystems.
+     * For other resources an empty KUrl is returned.
+     */
+    KUrl redirectionUrl( const Nepomuk::Resource& res );
+
+    /**
+     * Convert a nepomuk:/ URL to a file:/ URL if possible.
+     * Otherwise return an empty KUrl.
+     */
+    KUrl nepomukToFileUrl( const KUrl& url, bool evenMountIfNecessary = false );
+}
+
+#endif
diff --git a/nepomuk/kioslaves/common/timelinetools.cpp b/nepomuk/kioslaves/common/timelinetools.cpp
new file mode 100644
index 0000000..8e14ccb
--- /dev/null
+++ b/nepomuk/kioslaves/common/timelinetools.cpp
@@ -0,0 +1,173 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License version 2 as published by the Free Software Foundation.
+
+   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 "timelinetools.h"
+
+#include <Soprano/Node>
+#include <Soprano/Vocabulary/XMLSchema>
+
+#include "nie.h"
+#include "nfo.h"
+#include "nie.h"
+#include "nuao.h"
+
+#include <KUrl>
+#include <KCalendarSystem>
+#include <KGlobal>
+#include <KLocale>
+#include <KDebug>
+
+#include <QtCore/QDate>
+#include <QtCore/QRegExp>
+
+
+namespace {
+    QDate applyRelativeDateModificators( const QDate& date, const QMap<QString, QString>& modificators )
+    {
+        QDate newDate( date );
+        const QString dayKey = QLatin1String("relDays");
+        const QString weekKey = QLatin1String("relWeeks");
+        const QString monthKey = QLatin1String("relMonths");
+        const QString yearKey = QLatin1String("relYears");
+        bool ok = false;
+
+        if (modificators.contains(yearKey)) {
+            int relYears = modificators[yearKey].toInt(&ok);
+            if (ok) {
+                newDate = newDate.addYears(relYears);
+            }
+        }
+        if (modificators.contains(monthKey)) {
+            int relMonths = modificators[monthKey].toInt(&ok);
+            if (ok) {
+                newDate = newDate.addMonths(relMonths);
+            }
+        }
+        if (modificators.contains(weekKey)) {
+            int relWeeks = modificators[weekKey].toInt(&ok);
+            if (ok) {
+                const KCalendarSystem* calSystem = KGlobal::locale()->calendar();
+                newDate = newDate.addDays(relWeeks * calSystem->daysInWeek(date));
+            }
+        }
+        if (modificators.contains(dayKey)) {
+            int relDays = modificators[dayKey].toInt(&ok);
+            if (ok) {
+                newDate = newDate.addDays(relDays);
+            }
+        }
+        return newDate;
+    }
+}
+
+
+Nepomuk::TimelineFolderType Nepomuk::parseTimelineUrl( const KUrl& url, QDate* date, QString* filename )
+{
+    kDebug() << url;
+
+    static QRegExp s_dateRegexp( QLatin1String("\\d{4}-\\d{2}(?:-(\\d{2}))?") );
+
+    // reset
+    *date = QDate();
+
+    const QString path = url.path(KUrl::RemoveTrailingSlash);
+
+    if( path.isEmpty() || path == QLatin1String("/") ) {
+        kDebug() << url << "is root folder";
+        return RootFolder;
+    }
+    else if( path.startsWith( QLatin1String( "/today" ) ) ) {
+        *date = QDate::currentDate();
+        if ( filename )
+            *filename = path.mid( 7 );
+        kDebug() << url << "is today folder:" << *date;
+        return DayFolder;
+    }
+    else if( path == QLatin1String( "/calendar" ) ) {
+        kDebug() << url << "is calendar folder";
+        return CalendarFolder;
+    }
+    else {
+        QStringList sections = path.split( QLatin1String( "/" ), QString::SkipEmptyParts );
+        QString dateString;
+        if ( s_dateRegexp.exactMatch( sections.last() ) ) {
+            dateString = sections.last();
+        }
+        else if ( sections.count() > 1 && s_dateRegexp.exactMatch( sections[sections.count()-2] ) ) {
+            dateString = sections[sections.count()-2];
+            if ( filename )
+                *filename = sections.last();
+        }
+        else {
+            kDebug() << url << "COULD NOT PARSE";
+            return NoFolder;
+        }
+
+        if ( s_dateRegexp.cap( 1 ).isEmpty() ) {
+            // no day -> month listing
+            kDebug() << "parsing " << dateString;
+            *date = QDate::fromString( dateString, QLatin1String("yyyy-MM") );
+            kDebug() << url << "is month folder:" << date->month() << date->year();
+            if ( date->month() > 0 && date->year() > 0 )
+                return MonthFolder;
+        }
+        else {
+            kDebug() << "parsing " << dateString;
+            *date = applyRelativeDateModificators( QDate::fromString( dateString, "yyyy-MM-dd" ), url.queryItems() );
+            // only in day folders we can have filenames
+            kDebug() << url << "is day folder:" << *date;
+            if ( date->isValid() )
+                return DayFolder;
+        }
+    }
+
+    return NoFolder;
+}
+
+
+KUrl Nepomuk::buildTimelineQueryUrl( const QDate& date )
+{
+    static const char* DATEFORMATSTART("yyyy-MM-ddT00:00:00.000Z");
+    static const char* DATEFORMATEND("yyyy-MM-ddT23:59:59.999Z");
+
+    QString dateFrom = date.toString(DATEFORMATSTART);
+    QString dateTo = date.toString(DATEFORMATEND);
+
+    QString query = QString("select distinct ?r where { "
+                            "?r a %1 . "
+                            "{ ?r %2 ?date . } "
+                            "UNION "
+                            "{ ?r %3 ?date . } "
+                            "UNION "
+                            "{ ?r %4 ?date . } "
+                            "FILTER(?date > '%5'^^%7 && ?date < '%6'^^%7) . "
+                            "OPTIONAL { ?r2 a %8 . FILTER(?r=?r2) . } . FILTER(!BOUND(?r2)) . "
+                            "}")
+                    .arg( Soprano::Node::resourceToN3(Nepomuk::Vocabulary::NFO::FileDataObject()),
+                          Soprano::Node::resourceToN3(Nepomuk::Vocabulary::NIE::lastModified()),
+                          Soprano::Node::resourceToN3(Nepomuk::Vocabulary::NUAO::lastUsage()),
+                          Soprano::Node::resourceToN3(Nepomuk::Vocabulary::NIE::contentCreated()),
+                          dateFrom,
+                          dateTo,
+                          Soprano::Node::resourceToN3(Soprano::Vocabulary::XMLSchema::dateTime()),
+                          Soprano::Node::resourceToN3(Nepomuk::Vocabulary::NFO::Folder()) );
+    KUrl url("nepomuksearch:/");
+    url.addQueryItem( "sparql", query );
+    return url;
+}
diff --git a/nepomuk/kioslaves/common/timelinetools.h b/nepomuk/kioslaves/common/timelinetools.h
new file mode 100644
index 0000000..12efa30
--- /dev/null
+++ b/nepomuk/kioslaves/common/timelinetools.h
@@ -0,0 +1,50 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License version 2 as published by the Free Software Foundation.
+
+   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_TIMELINE_TOOLS_H_
+#define _NEPOMUK_TIMELINE_TOOLS_H_
+
+class QDate;
+class KUrl;
+class QString;
+
+namespace Nepomuk {
+    enum TimelineFolderType {
+        NoFolder = 0,    /// nothing
+        RootFolder,      /// the root folder
+        CalendarFolder,  /// the calendar folder listing all months
+        MonthFolder,     /// a folder listing a month's days (m_date contains the month)
+        DayFolder        /// a folder listing a day (m_date); optionally m_filename is set
+    };
+
+    /**
+     * Parse a timeline URL like timeline:/today and return the type of folder it
+     * represents. If DayFolder is returned \p date is set to the date that should be listed.
+     * Otherwise it is an invalid date. \p filename is optionally set to the name of the file
+     * in the folder.
+     */
+    TimelineFolderType parseTimelineUrl( const KUrl& url, QDate* date, QString* filename = 0 );
+
+    /**
+     * Create a nepomuksearch:/ URL that lists all files modified at \p date.
+     */
+    KUrl buildTimelineQueryUrl( const QDate& date );
+}
+
+#endif
diff --git a/nepomuk/kioslaves/nepomuk/CMakeLists.txt b/nepomuk/kioslaves/nepomuk/CMakeLists.txt
index c4210f7..e4edc05 100644
--- a/nepomuk/kioslaves/nepomuk/CMakeLists.txt
+++ b/nepomuk/kioslaves/nepomuk/CMakeLists.txt
@@ -6,7 +6,8 @@ include_directories(
 
 set(kio_nepomuk_PART_SRCS 
   kio_nepomuk.cpp
-  resourcepagegenerator.cpp)
+  resourcepagegenerator.cpp
+  ../common/resourcestat.cpp)
 
 soprano_add_ontology(kio_nepomuk_PART_SRCS ${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nie/nie.trig "NIE" "Nepomuk::Vocabulary" "trig")
 soprano_add_ontology(kio_nepomuk_PART_SRCS ${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nie/nfo.trig "NFO" "Nepomuk::Vocabulary" "trig")
diff --git a/nepomuk/kioslaves/nepomuk/kio_nepomuk.cpp b/nepomuk/kioslaves/nepomuk/kio_nepomuk.cpp
index a1ae66a..ac8dc81 100644
--- a/nepomuk/kioslaves/nepomuk/kio_nepomuk.cpp
+++ b/nepomuk/kioslaves/nepomuk/kio_nepomuk.cpp
@@ -21,15 +21,16 @@
 #include "kio_nepomuk.h"
 #include "nie.h"
 #include "nfo.h"
+//#include "nmm.h"
 #include "pimo.h"
 #include "resourcepagegenerator.h"
 #include "nepomuksearchurltools.h"
+#include "resourcestat.h"
 
 #include <QtCore/QByteArray>
 #include <QtCore/QDateTime>
 #include <QtCore/QFile>
 #include <QtCore/QCoreApplication>
-#include <QtCore/QEventLoop>
 #include <QtCore/QTimer>
 #include <QtDBus/QDBusConnection>
 
@@ -60,170 +61,6 @@
 #include <Solid/StorageAccess>
 
 
-namespace {
-    /**
-     * Check if the resource represents a local file with an existing nie:url property.
-     */
-    bool isLocalFile( const Nepomuk::Resource& res )
-    {
-        if ( res.hasProperty( Nepomuk::Vocabulary::NIE::url() ) ) {
-            KUrl url = res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl();
-            return ( !url.isEmpty() &&
-                     QFile::exists( url.toLocalFile() ) );
-        }
-        else {
-            return false;
-        }
-    }
-
-    /**
-     * Check if the resource represents a file on a removable media using a filex:/
-     * URL.
-     */
-    bool isRemovableMediaFile( const Nepomuk::Resource& res )
-    {
-        if ( res.hasProperty( Nepomuk::Vocabulary::NIE::url() ) ) {
-            KUrl url = res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl();
-            return ( url.protocol() == QLatin1String( "filex" ) );
-        }
-        else {
-            return false;
-        }
-    }
-
-    /**
-     * Mount a storage volume via Solid and wait for it to be mounted with
-     * a timeout of 20 seconds.
-     */
-    bool mountAndWait( Solid::StorageAccess* storage )
-    {
-        kDebug() << storage;
-        QEventLoop loop;
-        loop.connect( storage,
-                      SIGNAL(accessibilityChanged(bool, QString)),
-                      SLOT(quit()) );
-        // timeout 20 second
-        QTimer::singleShot( 20000, &loop, SLOT(quit()) );
-
-        storage->setup();
-        loop.exec();
-
-        kDebug() << storage << storage->isAccessible();
-
-        return storage->isAccessible();
-    }
-
-    /**
-     * Create a Solid storage access interface from the volume UUID.
-     */
-    Solid::StorageAccess* storageFromUUID( const QString& uuid )
-    {
-        QString solidQuery = QString::fromLatin1( "[ StorageVolume.usage=='FileSystem' AND StorageVolume.uuid=='%1' ]" ).arg( uuid.toLower() );
-        QList<Solid::Device> devices = Solid::Device::listFromQuery( solidQuery );
-        kDebug() << uuid << solidQuery << devices.count();
-        if ( !devices.isEmpty() )
-            return devices.first().as<Solid::StorageAccess>();
-        else
-            return 0;
-    }
-
-    /**
-     * Convert a filex:/ URL into its actual local file URL.
-     *
-     * \param url The filex:/ URL to convert
-     * \param evenMountIfNecessary If true an existing unmouted volume will be mounted to grant access to the local file.
-     *
-     * \return The converted local URL or an invalid URL if the filesystem the file is stored on could not be/was not mounted.
-     */
-    KUrl convertRemovableMediaFileUrl( const KUrl& url, bool evenMountIfNecessary = false )
-    {
-        Solid::StorageAccess* storage = storageFromUUID( url.host() );
-        kDebug() << url << storage;
-        if ( storage &&
-             ( storage->isAccessible() ||
-               ( evenMountIfNecessary && mountAndWait( storage ) ) ) ) {
-            kDebug() << "converted:" << KUrl( storage->filePath() + QLatin1String( "/" ) + url.path() );
-            return storage->filePath() + QLatin1String( "/" ) + url.path();
-        }
-        else {
-            return KUrl();
-        }
-    }
-
-    /**
-     * Get the mount path of a nfo:Filesystem resource as created by the removable storage service.
-     */
-    KUrl determineFilesystemPath( const Nepomuk::Resource& fsRes )
-    {
-        QString uuidQuery = QString::fromLatin1( "select ?uuid where { %1 %2 ?uuid . }" )
-                            .arg( Soprano::Node::resourceToN3( fsRes.resourceUri() ),
-                                  Soprano::Node::resourceToN3( Soprano::Vocabulary::NAO::identifier() ) );
-        Soprano::QueryResultIterator it = Nepomuk::ResourceManager::instance()->mainModel()->executeQuery( uuidQuery, Soprano::Query::QueryLanguageSparql );
-        if ( it.next() ) {
-            Solid::StorageAccess* storage = storageFromUUID( it["uuid"].toString() );
-            it.close();
-            if ( storage &&
-                 ( storage->isAccessible() ||
-                   mountAndWait( storage ) ) ) {
-                return storage->filePath();
-            }
-        }
-        return KUrl();
-    }
-
-    /**
-     * Determine the label for a filesystem \p res is stored on.
-     */
-    QString getFileSystemLabelForRemovableMediaFileUrl( const Nepomuk::Resource& res )
-    {
-        QList<Soprano::Node> labelNodes
-            = Nepomuk::ResourceManager::instance()->mainModel()->executeQuery( QString::fromLatin1( "select ?label where { "
-                                                                                                    "%1 nie:isPartOf ?fs . "
-                                                                                                    "?fs a nfo:Filesystem . "
-                                                                                                    "?fs nao:prefLabel ?label . "
-                                                                                                    "} LIMIT 1" )
-                                                                               .arg( Soprano::Node::resourceToN3( res.resourceUri() ) ),
-                                                                               Soprano::Query::QueryLanguageSparql ).iterateBindings( "label" ).allNodes();
-
-        if ( !labelNodes.isEmpty() )
-            return labelNodes.first().toString();
-        else
-            return res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl().host(); // Solid UUID
-    }
-
-    KUrl stripQuery( const KUrl& url )
-    {
-        KUrl newUrl( url );
-        newUrl.setEncodedQuery( QByteArray() );
-        return newUrl;
-    }
-
-    /**
-     * Split the filename part off a nepomuk:/ URI. This is used in many methods for identifying
-     * entries listed from tags and filesystems.
-     */
-    Nepomuk::Resource splitNepomukUrl( const KUrl& url, QString& filename )
-    {
-        //
-        // let's try to extract the resource from the url in case we listed a tag or
-        // filesystem and need to stat the entries in those virtual folders
-        //
-        // pre KDE 4.4 resources had just a single section, in KDE 4.4 we have "/res/<UUID>"
-        //
-        QString urlStr = stripQuery( url ).url();
-        int pos = urlStr.indexOf( '/', urlStr.startsWith( QLatin1String( "nepomuk:/res/" ) ) ? 13 : 9 );
-        if ( pos > 0 ) {
-            KUrl resourceUri = urlStr.left(pos);
-            filename = urlStr.mid( pos+1 );
-            return resourceUri;
-        }
-        else {
-            return stripQuery( url );
-        }
-    }
-}
-
-
 Nepomuk::NepomukProtocol::NepomukProtocol( const QByteArray& poolSocket, const QByteArray& appSocket )
     : KIO::ForwardingSlaveBase( "nepomuk", poolSocket, appSocket )
 {
@@ -247,28 +84,12 @@ void Nepomuk::NepomukProtocol::listDir( const KUrl& url )
     // anything.
     // See README for details
     //
-    QString filename;
-    Nepomuk::Resource res = splitNepomukUrl( url, filename );
-
-    if ( res.hasType( Nepomuk::Vocabulary::NFO::Folder() ) ) {
-        redirection( res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl() );
-        finished();
-    }
-    else if ( res.hasType( Soprano::Vocabulary::NAO::Tag() ) ) {
-        Query::ComparisonTerm term( Soprano::Vocabulary::NAO::hasTag(), Query::ResourceTerm( res ), Query::ComparisonTerm::Equal );
-        redirection( Query::Query( term ).toSearchUrl().url() );
+    Nepomuk::Resource res = Nepomuk::splitNepomukUrl( url );
+    KUrl reUrl = Nepomuk::redirectionUrl( res );
+    if ( !reUrl.isEmpty() ) {
+        redirection( reUrl );
         finished();
     }
-    else if ( res.hasType( Nepomuk::Vocabulary::NFO::Filesystem() ) ) {
-        KUrl fsUrl = determineFilesystemPath( res );
-        if ( fsUrl.isValid() ) {
-            redirection( fsUrl );
-            finished();
-        }
-        else {
-            error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() );
-        }
-    }
     else {
         error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() );
     }
@@ -284,29 +105,14 @@ void Nepomuk::NepomukProtocol::get( const KUrl& url )
 
     m_currentOperation = Get;
 
-    //
-    // First we check if it is a generic resource which cannot be forwarded
-    // If we could rewrite the URL than we can continue as Get operation
-    // which will also try to mount removable devices.
-    // If not we generate a HTML page.
-    //
-    KUrl newUrl;
-    if ( rewriteUrl( url, newUrl ) ) {
-        //
-        // rewriteUrl() returns true even if we have no new url for removable media
-        //
-        if ( newUrl.isEmpty() ) {
-            QString filename;
-            Nepomuk::Resource res = splitNepomukUrl( url, filename );
-            if ( isRemovableMediaFile( res ) ) {
-                error( KIO::ERR_SLAVE_DEFINED,
-                       i18nc( "@info", "Please insert the removable medium <resource>%1</resource> to access this file.",
-                              getFileSystemLabelForRemovableMediaFileUrl( res ) ) );
-            }
-        }
-        else {
-            ForwardingSlaveBase::get( url );
-        }
+    Nepomuk::Resource res = splitNepomukUrl( url );
+    if ( Nepomuk::isRemovableMediaFile( res ) ) {
+        error( KIO::ERR_SLAVE_DEFINED,
+               i18nc( "@info", "Please insert the removable medium <resource>%1</resource> to access this file.",
+                      getFileSystemLabelForRemovableMediaFileUrl( res ) ) );
+    }
+    else if ( !Nepomuk::nepomukToFileUrl( url ).isEmpty() ) {
+        ForwardingSlaveBase::get( url );
     }
     else {
         // TODO: call the share service for remote files (KDE 4.5)
@@ -358,34 +164,18 @@ void Nepomuk::NepomukProtocol::stat( const KUrl& url )
     kDebug() << url;
 
     m_currentOperation = Stat;
-    KUrl newUrl;
-    if ( rewriteUrl( url, newUrl ) ) {
+    if ( !Nepomuk::nepomukToFileUrl( url ).isEmpty() ) {
         ForwardingSlaveBase::stat( url );
     }
     else {
-        newUrl = stripQuery( url );
-        Nepomuk::Resource res( newUrl );
+        KUrl strippedUrl = stripQuery( url );
+        Nepomuk::Resource res( strippedUrl );
 
         if ( !res.exists() ) {
-            error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() );
+            error( KIO::ERR_DOES_NOT_EXIST, strippedUrl.prettyUrl() );
         }
         else {
-            KIO::UDSEntry uds = statNepomukResource( res );
-
-            // special case: tags and filesystems are handled as folders
-            if ( res.hasType( Soprano::Vocabulary::NAO::Tag() ) ||
-                 res.hasType( Nepomuk::Vocabulary::NFO::Filesystem() ) ) {
-                kDebug() << res.resourceUri() << "is tag or filesystem -> mimetype inode/directory";
-                uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, QLatin1String( "inode/directory" ) );
-                uds.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
-            }
-
-            // special case: tags cannot be redirected in stat, thus we need to use UDS_URL here
-            if ( res.hasType( Soprano::Vocabulary::NAO::Tag() ) ) {
-                Query::ComparisonTerm term( Soprano::Vocabulary::NAO::hasTag(), Query::ResourceTerm( res ), Query::ComparisonTerm::Equal );
-                uds.insert( KIO::UDSEntry::UDS_URL, Query::Query( term ).toSearchUrl().url() );
-            }
-
+            KIO::UDSEntry uds = Nepomuk::statNepomukResource( res );
             statEntry( uds );
             finished();
         }
@@ -393,88 +183,6 @@ void Nepomuk::NepomukProtocol::stat( const KUrl& url )
 }
 
 
-KIO::UDSEntry Nepomuk::NepomukProtocol::statNepomukResource( const Nepomuk::Resource& res )
-{
-    //
-    // We do not have a local file
-    // This is where the magic starts to happen.
-    // This is where we only use Nepomuk properties
-    //
-    KIO::UDSEntry uds;
-
-    // The display name can be anything
-    uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, res.genericLabel() );
-
-    // UDS_NAME needs to be unique but can be ugly
-    uds.insert( KIO::UDSEntry::UDS_NAME, resourceUriToUdsName( res.resourceUri() ) );
-
-    //
-    // There can still be file resources that have a mimetype but are
-    // stored remotely, thus they do not have a local nie:url
-    //
-    // Sadly Strigi's mimetype is not very useful (yet)
-    /* QStringList mimeTypes = res.property( Vocabulary::NIE::mimeType() ).toStringList();
-    if ( !mimeTypes.isEmpty() ) {
-        uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, mimeTypes.first() );
-    }
-    else */
-    if ( isRemovableMediaFile( res ) ) {
-        KMimeType::Ptr mt = KMimeType::findByUrl( res.property( Vocabulary::NIE::url() ).toUrl(),
-                                                  0,
-                                                  false, /* no local file as it is not accessible at the moment */
-                                                  true   /* fast mode */ );
-        if ( mt ) {
-            uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, mt->name() );
-        }
-    }
-    else {
-        // Use nice display types like "Person", "Project" and so on
-        Nepomuk::Types::Class type( res.resourceType() );
-        if (!type.label().isEmpty())
-            uds.insert( KIO::UDSEntry::UDS_DISPLAY_TYPE, type.label() );
-
-        QString icon = res.genericIcon();
-        if ( !icon.isEmpty() ) {
-            uds.insert( KIO::UDSEntry::UDS_ICON_NAME, icon );
-        }
-        else {
-            // a fallback icon for nepomuk resources
-            uds.insert( KIO::UDSEntry::UDS_ICON_NAME, "nepomuk" );
-        }
-    }
-
-    //
-    // Add some random values
-    //
-    uds.insert( KIO::UDSEntry::UDS_ACCESS, 0700 );
-    uds.insert( KIO::UDSEntry::UDS_USER, KUser().loginName() );
-    if ( res.hasProperty( Vocabulary::NIE::lastModified() ) ) {
-        // remotely stored files
-        uds.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, res.property( Vocabulary::NIE::lastModified() ).toDateTime().toTime_t() );
-    }
-    else {
-        // all nepomuk resources
-        uds.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, res.property( Soprano::Vocabulary::NAO::lastModified() ).toDateTime().toTime_t() );
-        uds.insert( KIO::UDSEntry::UDS_CREATION_TIME, res.property( Soprano::Vocabulary::NAO::created() ).toDateTime().toTime_t() );
-    }
-
-    if ( res.hasProperty( Vocabulary::NIE::contentSize() ) ) {
-        // remotely stored files
-        uds.insert( KIO::UDSEntry::UDS_SIZE, res.property( Vocabulary::NIE::contentSize() ).toInt() );
-    }
-
-
-    //
-    // Starting with KDE 4.4 we have the pretty UDS_NEPOMUK_URI which makes
-    // everything much cleaner since kio slaves can decide if the resources can be
-    // annotated or not.
-    //
-    uds.insert( KIO::UDSEntry::UDS_NEPOMUK_URI, KUrl( res.resourceUri() ).url() );
-
-    return uds;
-}
-
-
 void Nepomuk::NepomukProtocol::mimetype( const KUrl& url )
 {
     if ( !ensureNepomukRunning() )
@@ -485,18 +193,15 @@ void Nepomuk::NepomukProtocol::mimetype( const KUrl& url )
     m_currentOperation = Other;
 
     QString filename;
-    Nepomuk::Resource res = splitNepomukUrl( url, filename );
+    Nepomuk::Resource res = Nepomuk::splitNepomukUrl( url, &filename );
     if ( filename.isEmpty() &&
-         ( res.hasType( Soprano::Vocabulary::NAO::Tag() ) ||
-           res.hasType( Nepomuk::Vocabulary::NFO::Filesystem() ) ) ) {
+         Nepomuk::willBeRedirected( res ) ) {
         kDebug() << res.resourceUri() << "is tag or file system -> mimetype inode/directory";
-        // in listDir() we list tags as search folders
         mimeType( QLatin1String( "inode/directory" ) );
         finished();
     }
     else {
-        KUrl newUrl;
-        if ( rewriteUrl( url, newUrl ) ) {
+        if ( !Nepomuk::nepomukToFileUrl( url ).isEmpty() ) {
             ForwardingSlaveBase::mimetype( url );
         }
         else {
@@ -548,73 +253,11 @@ bool Nepomuk::NepomukProtocol::rewriteUrl( const KUrl& url, KUrl& newURL )
     if ( url.queryItemValue( QLatin1String( "noFollow" ) ) == QLatin1String( "true" ) )
         return false;
 
-    QString filename;
-    Nepomuk::Resource res = splitNepomukUrl( url, filename );
-
-    if ( !res.exists() )
-        return false;
-
-    //
-    // let's see if it is a pimo thing which refers to a file
-    //
-    if ( res.hasType( Nepomuk::Vocabulary::PIMO::Thing() ) ) {
-        if ( !res.pimoThing().groundingOccurrences().isEmpty() ) {
-            res = res.pimoThing().groundingOccurrences().first();
-        }
-    }
-
-    if ( isLocalFile( res ) ) {
-        newURL = res.property( Vocabulary::NIE::url() ).toUrl();
-    }
-    else if ( isRemovableMediaFile( res ) ) {
-        const KUrl removableMediaUrl = res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl();
-        newURL = convertRemovableMediaFileUrl( res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl(), m_currentOperation == Get );
-        if ( !newURL.isValid() && m_currentOperation == Get ) {
-            // error handling in get()
-            return true;
-        }
-        kDebug() << "Rewriting removable media URL" << url << "to" << newURL;
-    }
-
-    if ( newURL.isValid() && !filename.isEmpty() ) {
-        newURL.addPath( filename );
-    }
-
-    kDebug() << url << newURL;
-
+    newURL = Nepomuk::nepomukToFileUrl( url, m_currentOperation == Get );
     return newURL.isValid();
 }
 
 
-void Nepomuk::NepomukProtocol::prepareUDSEntry( KIO::UDSEntry& uds,
-                                                bool listing ) const
-{
-    // this will set mimetype and UDS_LOCAL_PATH for local files
-    ForwardingSlaveBase::prepareUDSEntry( uds, listing );
-
-    // make sure we have unique names for everything
-    uds.insert( KIO::UDSEntry::UDS_NAME, resourceUriToUdsName( requestedUrl() ) );
-
-    // make sure we do not use these ugly names for display
-    if ( !uds.contains( KIO::UDSEntry::UDS_DISPLAY_NAME ) ) {
-        Nepomuk::Resource res( requestedUrl() );
-        if ( res.hasType( Nepomuk::Vocabulary::PIMO::Thing() ) ) {
-            if ( !res.pimoThing().groundingOccurrences().isEmpty() ) {
-                res = res.pimoThing().groundingOccurrences().first();
-            }
-        }
-
-        if ( res.hasProperty( Nepomuk::Vocabulary::NIE::url() ) ) {
-            KUrl fileUrl( res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl() );
-            uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, fileUrl.fileName() );
-        }
-        else {
-            uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, res.genericLabel() );
-        }
-    }
-}
-
-
 bool Nepomuk::NepomukProtocol::ensureNepomukRunning()
 {
     if ( Nepomuk::ResourceManager::instance()->init() ) {
diff --git a/nepomuk/kioslaves/nepomuk/kio_nepomuk.h b/nepomuk/kioslaves/nepomuk/kio_nepomuk.h
index 68af535..1299f30 100644
--- a/nepomuk/kioslaves/nepomuk/kio_nepomuk.h
+++ b/nepomuk/kioslaves/nepomuk/kio_nepomuk.h
@@ -45,9 +45,6 @@ namespace Nepomuk {
          */
         bool rewriteUrl( const KUrl& url, KUrl& newURL );
 
-        void prepareUDSEntry( KIO::UDSEntry &entry,
-                              bool listing = false ) const;
-
     private:
         enum Operation {
             Get,
@@ -56,11 +53,6 @@ namespace Nepomuk {
         };
         Operation m_currentOperation;
         bool ensureNepomukRunning();
-
-        /**
-         * Creates an UDS entry for an arbitrary Nepomuk resource by relying on its properties.
-         */
-        KIO::UDSEntry statNepomukResource( const Nepomuk::Resource& res );
     };
 }
 
diff --git a/nepomuk/kioslaves/search/CMakeLists.txt b/nepomuk/kioslaves/search/CMakeLists.txt
index afa1e52..65e21ad 100644
--- a/nepomuk/kioslaves/search/CMakeLists.txt
+++ b/nepomuk/kioslaves/search/CMakeLists.txt
@@ -18,6 +18,7 @@ add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS} -DDISABLE_NEPOMUK_LEGACY)
 set(kio_nepomuksearch_PART_SRCS
   kio_nepomuksearch.cpp
   searchfolder.cpp
+  ../common/resourcestat.cpp
 )
 
 soprano_add_ontology(kio_nepomuksearch_PART_SRCS
@@ -41,6 +42,7 @@ kde4_add_plugin(kio_nepomuksearch
 
 target_link_libraries(kio_nepomuksearch
   ${KDE4_KIO_LIBS}
+  ${KDE4_SOLID_LIBS}
   ${NEPOMUK_LIBRARIES}
   ${NEPOMUK_QUERY_LIBRARIES}
   ${SOPRANO_LIBRARIES}
diff --git a/nepomuk/kioslaves/search/kdedmodule/CMakeLists.txt b/nepomuk/kioslaves/search/kdedmodule/CMakeLists.txt
index d994262..13887ef 100644
--- a/nepomuk/kioslaves/search/kdedmodule/CMakeLists.txt
+++ b/nepomuk/kioslaves/search/kdedmodule/CMakeLists.txt
@@ -11,6 +11,7 @@ add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS} -DDISABLE_NEPOMUK_LEGACY)
 set(nepomuksearchmodule_SRCS
   nepomuksearchmodule.cpp
   searchurllistener.cpp
+  ../../common/timelinetools.cpp
 )
 
 soprano_add_ontology(nepomuksearchmodule_SRCS
@@ -18,6 +19,16 @@ soprano_add_ontology(nepomuksearchmodule_SRCS
   "NIE"
   "Nepomuk::Vocabulary"
   "trig")
+soprano_add_ontology(nepomuksearchmodule_SRCS
+  ${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nie/nfo.trig
+  "NFO"
+  "Nepomuk::Vocabulary"
+  "trig")
+soprano_add_ontology(nepomuksearchmodule_SRCS
+  ${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nepomuk/nuao.trig
+  "NUAO"
+  "Nepomuk::Vocabulary"
+  "trig")
 
 set_source_files_properties(
   ${nepomuk_kio_slaves_SOURCE_DIR}/../interfaces/org.kde.nepomuk.Query.xml
diff --git a/nepomuk/kioslaves/search/kdedmodule/nepomuksearchmodule.cpp b/nepomuk/kioslaves/search/kdedmodule/nepomuksearchmodule.cpp
index 1358654..34a1baf 100644
--- a/nepomuk/kioslaves/search/kdedmodule/nepomuksearchmodule.cpp
+++ b/nepomuk/kioslaves/search/kdedmodule/nepomuksearchmodule.cpp
@@ -21,8 +21,10 @@
 #include "searchurllistener.h"
 #include "nie.h"
 #include "dbusoperators_p.h"
+#include "timelinetools.h"
 
 #include <QtDBus/QDBusConnection>
+#include <QtDBus/QDBusServiceWatcher>
 
 #include <kdebug.h>
 #include <kdirnotify.h>
@@ -30,9 +32,20 @@
 namespace {
     inline bool isNepomukSearchUrl( const KUrl& url )
     {
-        static const char* s_nepProName = "nepomuksearch";
+        static const char s_nepProName[] = "nepomuksearch";
         return url.protocol() == QLatin1String( s_nepProName );
     }
+
+    inline bool isTimelineUrl( const KUrl& url )
+    {
+        static const char s_timelineProName[] = "timeline";
+        return url.protocol() == QLatin1String( s_timelineProName );
+    }
+
+    inline bool isNepomukSearchOrTimelineUrl( const KUrl& url )
+    {
+        return isNepomukSearchUrl( url ) || isTimelineUrl( url );
+    }
 }
 
 
@@ -47,10 +60,11 @@ Nepomuk::SearchModule::SearchModule( QObject* parent, const QList<QVariant>& )
     // connect to serviceOwnerChanged to catch crashed clients that never unregistered
     // themselves
     //
-    connect( QDBusConnection::sessionBus().interface(),
-             SIGNAL( serviceOwnerChanged( const QString&, const QString&, const QString& ) ),
-             this,
-             SLOT( slotServiceOwnerChanged( const QString&, const QString&, const QString& ) ) );
+    m_watcher = new QDBusServiceWatcher( this );
+    m_watcher->setConnection( QDBusConnection::sessionBus() );
+    m_watcher->setWatchMode( QDBusServiceWatcher::WatchForUnregistration );
+    connect( m_watcher, SIGNAL( serviceUnregistered( const QString& ) ),
+             this, SLOT( slotServiceUnregistered( const QString& ) ) );
 
     //
     // connect to KDirLister telling us that it entered a dir
@@ -80,12 +94,22 @@ Nepomuk::SearchModule::~SearchModule()
 void Nepomuk::SearchModule::registerSearchUrl( const QString& urlString )
 {
     const KUrl url( urlString );
+    KUrl queryUrl;
 
     if ( isNepomukSearchUrl( url ) ) {
+        queryUrl = url;
+    }
+    else if ( isTimelineUrl( url ) ) {
+        QDate date;
+        if ( Nepomuk::parseTimelineUrl( url, &date ) == Nepomuk::DayFolder )
+            queryUrl = Nepomuk::buildTimelineQueryUrl( date );
+    }
+
+    if ( queryUrl.isValid() ) {
         kDebug() << "REGISTER REGISTER REGISTER REGISTER REGISTER REGISTER" << url;
         QHash<KUrl, SearchUrlListener*>::iterator it = m_queryHash.find( url );
         if ( it == m_queryHash.end() ) {
-            SearchUrlListener* listener = new SearchUrlListener( url );
+            SearchUrlListener* listener = new SearchUrlListener( queryUrl, url );
             listener->ref();
             m_queryHash.insert( url, listener );
         }
@@ -93,8 +117,10 @@ void Nepomuk::SearchModule::registerSearchUrl( const QString& urlString )
             it.value()->ref();
         }
 
-        if ( calledFromDBus() )
+        if ( calledFromDBus() ) {
             m_dbusServiceUrlHash.insert( message().service(), url );
+            m_watcher->addWatchedService( message().service() );
+        }
     }
 }
 
@@ -102,11 +128,14 @@ void Nepomuk::SearchModule::registerSearchUrl( const QString& urlString )
 void Nepomuk::SearchModule::unregisterSearchUrl( const QString& urlString )
 {
     const KUrl url( urlString );
-    if ( isNepomukSearchUrl( url ) ) {
+    if ( isNepomukSearchOrTimelineUrl( url ) ) {
         kDebug() << "UNREGISTER UNREGISTER UNREGISTER UNREGISTER UNREGISTER" << url;
         unrefUrl( url );
-        if ( calledFromDBus() )
+        if ( calledFromDBus() ) {
             m_dbusServiceUrlHash.remove( message().service(), url );
+            if ( !m_dbusServiceUrlHash.contains( message().service() ) )
+                m_watcher->removeWatchedService( message().service() );
+        }
     }
 }
 
@@ -117,18 +146,15 @@ QStringList Nepomuk::SearchModule::watchedSearchUrls()
 }
 
 
-void Nepomuk::SearchModule::slotServiceOwnerChanged( const QString& serviceName,
-                                                     const QString&,
-                                                     const QString& newOwner )
+void Nepomuk::SearchModule::slotServiceUnregistered( const QString& serviceName )
 {
-    if ( newOwner.isEmpty() ) {
-        QHash<QString, KUrl>::iterator it = m_dbusServiceUrlHash.find( serviceName );
-        while ( it != m_dbusServiceUrlHash.end() ) {
-            unrefUrl( it.value() );
-            m_dbusServiceUrlHash.erase( it );
-            it = m_dbusServiceUrlHash.find( serviceName );
-        }
+    QHash<QString, KUrl>::iterator it = m_dbusServiceUrlHash.find( serviceName );
+    while ( it != m_dbusServiceUrlHash.end() ) {
+        unrefUrl( it.value() );
+        m_dbusServiceUrlHash.erase( it );
+        it = m_dbusServiceUrlHash.find( serviceName );
     }
+    m_watcher->removeWatchedService( serviceName );
 }
 
 
diff --git a/nepomuk/kioslaves/search/kdedmodule/nepomuksearchmodule.desktop b/nepomuk/kioslaves/search/kdedmodule/nepomuksearchmodule.desktop
index 78d8f5d..195ae84 100644
--- a/nepomuk/kioslaves/search/kdedmodule/nepomuksearchmodule.desktop
+++ b/nepomuk/kioslaves/search/kdedmodule/nepomuksearchmodule.desktop
@@ -6,6 +6,9 @@ X-KDE-DBus-ModuleName=nepomuksearchmodule
 X-KDE-Kded-autoload=true
 X-KDE-Kded-load-on-demand=false
 Name=Nepomuk Search Module
+Name[ar]=وحدة بحث نبومك
+Name[bg]=Модул за търсене Nepomuk
+Name[bn]=নেপোমুক সন্ধান মডিউল
 Name[ca]=Mòdul de cerques del Nepomuk
 Name[ca@valencia]=Mòdul de cerques del Nepomuk
 Name[da]=Nepomuk søgemodul
@@ -15,12 +18,15 @@ Name[en_GB]=Nepomuk Search Module
 Name[es]=Módulo de búsqueda Nepomuk
 Name[et]=Nepomuki otsingumoodul
 Name[eu]=Nepomuk bilaketa mudulua
+Name[fi]=Nepomukin hakumoduuli
 Name[fr]=Service de recherche Nepomuk
+Name[fy]=Nepomuk syk module
 Name[ga]=Modúl Cuardaigh Nepomuk
 Name[he]=מודול החיפוש של Nepomuk
 Name[hi]=नेपोमक खोज मोड्यूल
 Name[hr]=Nepomukov modul za pretraživanje
-Name[hu]=Nepomuk kereső modul
+Name[hu]=Nepomuk keresőmodul
+Name[ia]=Modulo de cerca de Nepomuk
 Name[id]=Modul Pencarian Nepomuk
 Name[is]=Nepomuk leitareining
 Name[it]=Modulo di ricerca di Nepomuk
@@ -28,17 +34,21 @@ Name[ja]=Nepomuk 検索モジュール
 Name[kk]=Nepomuk іздеу модулі
 Name[km]=ម៉ូឌុល​ស្វែងរក​របស់ Nepomuk
 Name[kn]=ನೆಪೋಮುಕ್ ಹುಡುಕು ಘಟಕ
+Name[ko]=Nepomuk 검색 모듈
 Name[lt]=Nepomuk paieškos modulis
 Name[lv]=Nepomuk meklēšanas modulis
 Name[mk]=Модул на Непомук за пребарување
+Name[ml]=നെപ്പോമുക്ക് തെരച്ചില്‍ മൊഡ്യൂള്‍
 Name[nb]=Nepomuk søkemodul
 Name[nds]=Nepomuk-Söökmoduul
 Name[nl]=Nepomuk-zoekmodule
 Name[nn]=Nepomuk søkjemodul
+Name[pa]=ਨਿਪੋਮੁਕ ਖੋਜ ਮੋਡੀਊਲ
 Name[pl]=Moduł wyszukiwania Nepomuka
 Name[pt]=Módulo de Pesquisa do Nepomuk
 Name[pt_BR]=Módulo de pesquisa do Nepomuk
 Name[ro]=Modul de căutare Nepomuk
+Name[ru]=Модуль поиска Nepomuk
 Name[sk]=Modul vyhľadávania Nepomuk
 Name[sl]=Nepomukov modul za iskanje
 Name[sr]=Претраживачки модул Непомука
@@ -46,7 +56,7 @@ Name[sr@ijekavian]=Претраживачки модул Непомука
 Name[sr@ijekavianlatin]=Pretraživački modul Nepomuka
 Name[sr@latin]=Pretraživački modul Nepomuka
 Name[sv]=Nepomuk-sökmodul
-Name[tg]=Хидматҳои Nepomuk
+Name[tg]=Хидматҳои ҷустуҷӯии Nepomuk
 Name[th]=มอดูลค้นหาของบริการ Neomuk
 Name[tr]=Nepomuk Arama Modülü
 Name[uk]=Модуль пошуку Nepomuk
@@ -54,6 +64,7 @@ Name[x-test]=xxNepomuk Search Modulexx
 Name[zh_CN]=Nepomuk 搜索模块
 Name[zh_TW]=Nepomuk 搜尋模組
 Comment=Helper module for KIO to ensure automatic updates of nepomuksearch listings.
+Comment[ar]=وحدة مساعدة لKIO لتضمن التحديث الآلي لقوائم nepomuksearch
 Comment[ca]=Mòdul ajudant per al KIO que assegura les actualitzacions automàtiques dels llistats del «nepomuksearch».
 Comment[ca@valencia]=Mòdul ajudant per al KIO que assegura les actualitzacions automàtiques dels llistats del «nepomuksearch».
 Comment[da]=Hjælpemodul til KIO til at sikre automatisk opdatering af nepomuksearchs oplistninger.
@@ -63,14 +74,19 @@ Comment[en_GB]=Helper module for KIO to ensure automatic updates of nepomuksearc
 Comment[es]=Módulo auxiliar de KIO para asegurar la actualización automática de listados de búsquedas con Nepomuk.
 Comment[et]=KIO abimoodul Nepomuki otsinguloendite automaatseks uuendamiseks.
 Comment[eu]=KIOrentzako modulu laguntzailea nepomuksearch zerrenden eguneraketa automatikoa ziurtatzeko.
+Comment[fi]=KIO-apumoduuli, joka takaa nepomuksearch-luettelointien automaattiset päivitykset
 Comment[fr]=Module assistant pour KIO qui assure les mises à jours automatiques des listes de NepomukSearch 
+Comment[fy]=Helper module foar KIO om wis te wêze dat nepomuksearch listen automatysk fernije.
+Comment[ga]=Modúl cabhrach le haghaidh KIO a dhéanann cinnte go bhfuil eolairí nepomuksearch nuashonraithe go huathoibríoch.
 Comment[hr]=Pomoćni modul za KIO koji osigurava automatsko ažuriranje izlistavanja nepomuk pretraga.
-Comment[hu]=Súgó modul a KIO számára, hogy biztos legyen a nepomuk keresési listázások automatikus frissítése.
+Comment[ia]=Modulo de Adjuta pro KIO per assecurar actualisationes automatic de listas de nepomuksearch.
 Comment[id]=Modul penolong untuk KIO untuk memastikan pemutakhiran otomatis pengurutan nepomuksearch.
+Comment[is]=KIO hjálpareining sem tryggir sjálfvirkar uppfærslur á leitarlistum Nepomuk leitareiningar.
 Comment[it]=Modulo ausiliare per KIO per assicurare gli aggiornamenti automatici delle liste di ricerca di Nepomuk.
 Comment[ja]=Nepomuk 検索一覧を自動的に更新するための KIO ヘルパーモジュール
 Comment[kk]=nepomuksearch тізімдерін автоматты түрде жаңартуға арналған KIO-нің көмекші модулі
-Comment[km]=ម៉ឌុល​កម្មវិធី​ជំនួយ​សម្រាប់ KIO ដើម្បី​ប្រាកដ​ថា​មាន​ភាព​​ធ្វើ​ឲ្យ​ទាន់សម័យ​​របស់ nepomuksearch ។
+Comment[km]=ម៉ឌុល​កម្មវិធី​ជំនួយ​សម្រាប់ KIO ដើម្បី​ប្រាកដ​ថា ធ្វើ​​បច្ចុប្បន្នភាព​ការ​រាយ​របស់ nepomuksearch ដោយ​ស្វ័យ​ប្រវត្តិ ។
+Comment[ko]=nepomuksearch 목록을 자동으로 업데이트하는 KIO 모듈입니다.
 Comment[lt]=Pagalbos modulis, skirtas KIO, užtikrinantis automatinius atnaujinimus nepomuk paieškos sąrašuose.
 Comment[nb]=Hjelpemodul for KIO – for å sikre automatiske oppdateringer av nepomuksearch-resultater.
 Comment[nds]=Hülpmoduul för de KDE-In-/Utgaav för automaatsch Opfrischen vun Nepomuk-Sööklisten
@@ -79,6 +95,7 @@ Comment[nn]=Hjelpemodul for KIO – for å sikra automatiske oppdateringar av ne
 Comment[pl]=Moduł pomocniczy dla KIO służący do zapewnienia automatycznych uaktualnień list nepomuksearch.
 Comment[pt]=Módulo auxiliar do KIO para garantir as actualizações automáticas das listagens do 'nepomuksearch'.
 Comment[pt_BR]=Módulo assistente do KIO para garantir atualizações automáticas das listagens do nepomuksearch.
+Comment[ru]=Вспомогательный модуль KIO, необходимый для обновления результатов поиска.
 Comment[sk]=Pomocný modul pre KIO, ktorý zabezpečuje automatickú aktualizáciu zoznamov nepomuksearch.
 Comment[sl]=Pomožni modul za KIO, ki zagotavlja samodejne posodobitve seznamov nepomuksearch
 Comment[sr]=Помоћни модул за К‑У/И који обезбеђује аутоматско ажурирање спискова Непомукове претраге.
diff --git a/nepomuk/kioslaves/search/kdedmodule/nepomuksearchmodule.h b/nepomuk/kioslaves/search/kdedmodule/nepomuksearchmodule.h
index 1fcb25f..97f005d 100644
--- a/nepomuk/kioslaves/search/kdedmodule/nepomuksearchmodule.h
+++ b/nepomuk/kioslaves/search/kdedmodule/nepomuksearchmodule.h
@@ -26,6 +26,8 @@
 #include <QtDBus/QDBusContext>
 #include <QtCore/QMultiHash>
 
+class QDBusServiceWatcher;
+
 namespace Nepomuk {
 
     class SearchUrlListener;
@@ -45,15 +47,15 @@ namespace Nepomuk {
         Q_SCRIPTABLE QStringList watchedSearchUrls();
 
     private Q_SLOTS:
-        void slotServiceOwnerChanged( const QString& serviceName,
-                                      const QString&,
-                                      const QString& newOwner );
+        void slotServiceUnregistered( const QString& serviceName );
 
     private:
         void unrefUrl( const KUrl& url );
 
         QHash<KUrl, SearchUrlListener*> m_queryHash;
         QMultiHash<QString, KUrl> m_dbusServiceUrlHash;
+
+        QDBusServiceWatcher *m_watcher;
     };
 }
 
diff --git a/nepomuk/kioslaves/search/kdedmodule/searchurllistener.cpp b/nepomuk/kioslaves/search/kdedmodule/searchurllistener.cpp
index 726ab7e..eb93e8d 100644
--- a/nepomuk/kioslaves/search/kdedmodule/searchurllistener.cpp
+++ b/nepomuk/kioslaves/search/kdedmodule/searchurllistener.cpp
@@ -25,6 +25,7 @@
 #include <kdirnotify.h>
 #include <kdebug.h>
 #include <nepomuk/result.h>
+#include <nepomuk/query.h>
 
 #include <QtCore/QHash>
 #include <QtDBus/QDBusConnection>
@@ -46,13 +47,16 @@ namespace {
 }
 
 
-Nepomuk::SearchUrlListener::SearchUrlListener( const KUrl& queryUrl )
+Nepomuk::SearchUrlListener::SearchUrlListener( const KUrl& queryUrl, const KUrl& notifyUrl )
     : QObject( 0 ),
       m_ref( 0 ),
       m_queryUrl( queryUrl ),
+      m_notifyUrl( notifyUrl ),
       m_queryInterface( 0 )
 {
-    kDebug() << queryUrl;
+    kDebug() << queryUrl << notifyUrl;
+    if ( m_notifyUrl.isEmpty() )
+        m_notifyUrl = queryUrl;
 
     const QString queryService = QLatin1String( "org.kde.nepomuk.services.nepomukqueryservice" );
     if ( QDBusConnection::sessionBus().interface()->isServiceRegistered( queryService ) ) {
@@ -97,7 +101,7 @@ int Nepomuk::SearchUrlListener::unref()
 
 void Nepomuk::SearchUrlListener::slotNewEntries( const QList<Nepomuk::Query::Result>& )
 {
-    org::kde::KDirNotify::emitFilesAdded( m_queryUrl.url() );
+    org::kde::KDirNotify::emitFilesAdded( m_notifyUrl.url() );
 }
 
 
@@ -105,7 +109,7 @@ void Nepomuk::SearchUrlListener::slotEntriesRemoved( const QStringList& entries
 {
     QStringList urls;
     foreach( const QString& uri, entries ) {
-        KUrl resultUrl( m_queryUrl );
+        KUrl resultUrl( m_notifyUrl );
         resultUrl.addPath( Nepomuk::resourceUriToUdsName( uri ) );
         urls << resultUrl.url();
     }
@@ -122,7 +126,7 @@ void Nepomuk::SearchUrlListener::slotQueryServiceInitialized( bool success )
         createInterface();
 
         // inform KIO that results are available
-        org::kde::KDirNotify::emitFilesAdded( m_queryUrl.url() );
+        org::kde::KDirNotify::emitFilesAdded( m_notifyUrl.url() );
     }
 }
 
@@ -138,7 +142,7 @@ void Nepomuk::SearchUrlListener::createInterface()
                                                            "/nepomukqueryservice",
                                                            QDBusConnection::sessionBus() );
 
-    QDBusReply<QDBusObjectPath> r = queryServiceInterface.sparqlQuery( Nepomuk::queryFromUrl( m_queryUrl ),
+    QDBusReply<QDBusObjectPath> r = queryServiceInterface.sparqlQuery( Nepomuk::Query::Query::sparqlFromQueryUrl( m_queryUrl ),
                                                                        nieUriReqProp() );
 
     if ( r.isValid() ) {
diff --git a/nepomuk/kioslaves/search/kdedmodule/searchurllistener.h b/nepomuk/kioslaves/search/kdedmodule/searchurllistener.h
index e45e63e..fdf2700 100644
--- a/nepomuk/kioslaves/search/kdedmodule/searchurllistener.h
+++ b/nepomuk/kioslaves/search/kdedmodule/searchurllistener.h
@@ -36,7 +36,7 @@ namespace Nepomuk {
         Q_OBJECT
 
     public:
-        SearchUrlListener( const KUrl& queryUrl );
+        SearchUrlListener( const KUrl& queryUrl, const KUrl& notifyUrl = KUrl() );
         ~SearchUrlListener();
 
         int ref();
@@ -52,6 +52,7 @@ namespace Nepomuk {
 
         int m_ref;
         KUrl m_queryUrl;
+        KUrl m_notifyUrl;
         org::kde::nepomuk::Query* m_queryInterface;
     };
 }
diff --git a/nepomuk/kioslaves/search/kio_nepomuksearch.cpp b/nepomuk/kioslaves/search/kio_nepomuksearch.cpp
index bd0f6ab..839f380 100644
--- a/nepomuk/kioslaves/search/kio_nepomuksearch.cpp
+++ b/nepomuk/kioslaves/search/kio_nepomuksearch.cpp
@@ -29,18 +29,25 @@
 #include <KDebug>
 #include <KAboutData>
 #include <KApplication>
-#include <KConfig>
+#include <KSharedConfig>
 #include <KConfigGroup>
 #include <KCmdLineArgs>
 #include <kio/global.h>
 #include <kio/job.h>
 #include <KMimeType>
 #include <KStandardDirs>
+#include <KFileItem>
+#include <KDirNotify>
 
-#include <Nepomuk/Resource>
+#include <Nepomuk/Thing>
 #include <Nepomuk/ResourceManager>
 #include <Nepomuk/Variant>
 #include <Nepomuk/Query/QueryServiceClient>
+#include <Nepomuk/Query/ComparisonTerm>
+#include <Nepomuk/Query/ResourceTypeTerm>
+#include <Nepomuk/Query/AndTerm>
+#include <Nepomuk/Query/NegationTerm>
+#include <Nepomuk/Query/Query>
 
 #include <Soprano/Vocabulary/RDF>
 #include <Soprano/Vocabulary/RDFS>
@@ -53,14 +60,16 @@
 
 
 namespace {
-    KIO::UDSEntry statDefaultSearchFolder( const QString& name ) {
+    KIO::UDSEntry statSearchFolder( const KUrl& url ) {
         KIO::UDSEntry uds;
-        uds.insert( KIO::UDSEntry::UDS_NAME, name );
-        uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, i18n("Query Results") );
         uds.insert( KIO::UDSEntry::UDS_ACCESS, 0700 );
         uds.insert( KIO::UDSEntry::UDS_USER, KUser().loginName() );
         uds.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
         uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1( "inode/directory" ) );
+        uds.insert( KIO::UDSEntry::UDS_ICON_OVERLAY_NAMES, QLatin1String( "nepomuk" ) );
+        uds.insert( KIO::UDSEntry::UDS_NAME, Nepomuk::resourceUriToUdsName( url ) );
+        uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, Nepomuk::Query::Query::titleFromQueryUrl( url ) );
+        uds.insert( KIO::UDSEntry::UDS_URL, url.url() );
         return uds;
     }
 
@@ -69,9 +78,9 @@ namespace {
      * Empty if the path only contains the query.
      */
     QString fileNameFromUrl( const KUrl& url ) {
-        QString fn;
         if ( url.hasQueryItem( QLatin1String( "sparql" ) ) ||
              url.hasQueryItem( QLatin1String( "query" ) ) ||
+             url.hasQueryItem( QLatin1String( "encodedquery" ) ) ||
              url.directory() != QLatin1String( "/" ) ) {
             return url.fileName();
         }
@@ -85,30 +94,13 @@ namespace {
         return( !url.hasQuery() &&
                 ( path.isEmpty() || path == QLatin1String("/") ) );
     }
-
-    // do not cache more than SEARCH_CACHE_MAX search folders at the same time
-    const int SEARCH_CACHE_MAX = 5;
+    const int s_historyMax = 10;
 }
 
 
 Nepomuk::SearchProtocol::SearchProtocol( const QByteArray& poolSocket, const QByteArray& appSocket )
     : KIO::ForwardingSlaveBase( "nepomuksearch", poolSocket, appSocket )
 {
-    // FIXME: trueg: install a file watch on this file and update it whenever the queries change.
-    // FIXME: trueg: also emit a KDirNotify signal to inform KIO about that change
-    KConfig config("kionepomukuserqueriesrc" );
-
-    foreach( QString search, config.group("Searches").readEntry("All searches", QStringList() ) )
-    {
-        search = search.simplified();
-        KConfigGroup grp = config.group(search);
-        KUrl url( grp.readEntry("Query", QString() ) );
-        url.setScheme( QLatin1String( "nepomuksearch" ) );
-        QString name = grp.readEntry( "Name", QString() );
-        if ( !name.isEmpty() ) {
-            addDefaultSearch( name, url );
-        }
-    }
 }
 
 
@@ -137,45 +129,10 @@ bool Nepomuk::SearchProtocol::ensureNepomukRunning( bool emitError )
 }
 
 
-void Nepomuk::SearchProtocol::addDefaultSearch( const QString& name, const KUrl& url )
-{
-    m_defaultSearches.insert( name, url );
-}
-
-
-Nepomuk::SearchFolder* Nepomuk::SearchProtocol::extractSearchFolder( const KUrl& url )
-{
-    kDebug() << url;
-    if ( SearchFolder* sf = getDefaultQueryFolder( url.fileName() ) ) {
-        kDebug() << "-----> is default search folder";
-        return sf;
-    }
-    else if ( SearchFolder* sf = getQueryFolder( url ) ) {
-        kDebug() << "-----> is on-the-fly search folder";
-        return sf;
-    }
-    else {
-        kDebug() << "-----> does not exist.";
-        return 0;
-    }
-}
-
-
 void Nepomuk::SearchProtocol::listDir( const KUrl& url )
 {
     kDebug() << url;
 
-    //
-    // Root dir: * list default searches: "all music files", "recent files"
-    //           * list configuration entries: "create new default search"
-    //
-    // Root dir with query:
-    //           * execute the query (cached) and list its results
-    //
-    // some folder:
-    //           * Look for a default search and execute that
-    //
-
     if ( isRootUrl( url ) ) {
         listRoot();
     }
@@ -185,8 +142,10 @@ void Nepomuk::SearchProtocol::listDir( const KUrl& url )
             listEntry( KIO::UDSEntry(),  true);
             finished();
         }
-        else if ( SearchFolder* folder = extractSearchFolder( url ) ) {
+        else if ( SearchFolder* folder = getQueryFolder( url ) ) {
             folder->list();
+            listEntry( KIO::UDSEntry(), true );
+            finished();
         }
         else {
             error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() );
@@ -226,8 +185,7 @@ void Nepomuk::SearchProtocol::mimetype( const KUrl& url )
         mimeType( QString::fromLatin1( "inode/directory" ) );
         finished();
     }
-    else if ( url.directory() == QLatin1String( "/" ) &&
-              m_defaultSearches.contains( url.fileName() ) ) {
+    else if ( url.directory() == QLatin1String( "/" ) ) {
         mimeType( QString::fromLatin1( "inode/directory" ) );
         finished();
     }
@@ -248,7 +206,7 @@ void Nepomuk::SearchProtocol::stat( const KUrl& url )
         //
         KIO::UDSEntry uds;
         uds.insert( KIO::UDSEntry::UDS_NAME, QString::fromLatin1( "/" ) );
-        uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, i18n("Query Results") );
+        uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, i18n("Desktop Queries") );
         uds.insert( KIO::UDSEntry::UDS_ICON_NAME, QString::fromLatin1( "nepomuk" ) );
         uds.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
         uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1( "inode/directory" ) );
@@ -258,8 +216,7 @@ void Nepomuk::SearchProtocol::stat( const KUrl& url )
     }
     else if ( fileNameFromUrl( url ).isEmpty() ) {
         kDebug() << "Stat search folder" << url;
-        // we use the encoded query url as UDS_NAME
-        statEntry( statDefaultSearchFolder( QString::fromAscii( url.toEncoded().toPercentEncoding( QByteArray(), QByteArray(), '_' ) ) ) );
+        statEntry( statSearchFolder( url ) );
         finished();
     }
     else {
@@ -284,8 +241,8 @@ bool Nepomuk::SearchProtocol::rewriteUrl( const KUrl& url, KUrl& newURL )
 {
     // we do it the speedy but slightly umpf way: decode the encoded URI from the filename
     newURL = Nepomuk::udsNameToResourceUri( url.fileName() );
-    kDebug() << "NEW URL:" << newURL << newURL.protocol() << newURL.path() << newURL.fileName();
-    return newURL.isValid();
+    kDebug() << "URL:" << url << "NEW URL:" << newURL << newURL.protocol() << newURL.path() << newURL.fileName();
+    return !newURL.isEmpty();
 }
 
 
@@ -299,69 +256,34 @@ void Nepomuk::SearchProtocol::listRoot()
 {
     kDebug();
 
-    listDefaultSearches();
-    listActions();
-
     listEntry( KIO::UDSEntry(), true );
     finished();
 }
 
 
-void Nepomuk::SearchProtocol::listActions()
-{
-    // FIXME: manage default searches
-}
-
-
 Nepomuk::SearchFolder* Nepomuk::SearchProtocol::getQueryFolder( const KUrl& url )
 {
+    // this is necessary to properly handle user queries which are encoded in the filename in
+    // statSearchFolder(). This is necessary for cases in which UDS_URL is ignored like in
+    // KUrlNavigator's popup menus
+    KUrl normalizedUrl = Nepomuk::udsNameToResourceUri( url.fileName() );
+    if ( normalizedUrl.protocol() != QLatin1String( "nepomuksearch" ) ) {
+        normalizedUrl = url;
+    }
+
     // here we strip off the entry's name since that is not part of the query URL
-    KUrl strippedUrl( url );
     if ( url.hasQuery() ) {
-        strippedUrl.setPath( QLatin1String( "/" ) );
+        normalizedUrl.setPath( QLatin1String( "/" ) );
     }
     else if ( url.directory() != QLatin1String( "/" ) ) {
-        strippedUrl.setPath( QLatin1String( "/" ) + url.path().section( '/', 0, 0 ) );
+        normalizedUrl.setPath( QLatin1String( "/" ) + url.path().section( '/', 0, 0 ) );
     }
 
-    QString urlStr = strippedUrl.url();
-    SearchFolder* folder = new SearchFolder( strippedUrl, this );
+    SearchFolder* folder = new SearchFolder( normalizedUrl, this );
     return folder;
 }
 
 
-Nepomuk::SearchFolder* Nepomuk::SearchProtocol::getDefaultQueryFolder( const QString& name )
-{
-    if ( m_defaultSearches.contains( name ) ) {
-        return getQueryFolder( m_defaultSearches[name] );
-    }
-    else {
-        return 0;
-    }
-}
-
-
-void Nepomuk::SearchProtocol::listDefaultSearches()
-{
-    for ( QHash<QString, KUrl>::const_iterator it = m_defaultSearches.constBegin();
-          it != m_defaultSearches.constEnd(); ++it ) {
-        listEntry( statDefaultSearchFolder( it.key() ), false );
-    }
-}
-
-
-void Nepomuk::SearchProtocol::listDefaultSearch( const QString& name )
-{
-    kDebug() << name;
-    if ( m_defaultSearches.contains( name ) ) {
-        getDefaultQueryFolder( name )->list();
-    }
-    else {
-        error( KIO::ERR_CANNOT_ENTER_DIRECTORY, "Unknown default search: " + name );
-        finished();
-    }
-}
-
 extern "C"
 {
     KDE_EXPORT int kdemain( int argc, char **argv )
diff --git a/nepomuk/kioslaves/search/kio_nepomuksearch.h b/nepomuk/kioslaves/search/kio_nepomuksearch.h
index 8977425..0f9c65b 100644
--- a/nepomuk/kioslaves/search/kio_nepomuksearch.h
+++ b/nepomuk/kioslaves/search/kio_nepomuksearch.h
@@ -80,21 +80,11 @@ namespace Nepomuk {
     private:
         bool ensureNepomukRunning( bool emitError = true );
         void listRoot();
-        void listActions();
-        void listDefaultSearches();
-        void listDefaultSearch( const QString& path );
-        void addDefaultSearch( const QString& name, const KUrl& url );
-
-        SearchFolder* extractSearchFolder( const KUrl& url );
 
         /**
          * Get (possibly cached) query folder
          */
         SearchFolder* getQueryFolder( const KUrl& url );
-        SearchFolder* getDefaultQueryFolder( const QString& name );
-
-        // the default search folders
-        QHash<QString, KUrl> m_defaultSearches;
     };
 }
 
diff --git a/nepomuk/kioslaves/search/nepomuksearch.protocol b/nepomuk/kioslaves/search/nepomuksearch.protocol
index 5c0a1c7..9fa8cb7 100644
--- a/nepomuk/kioslaves/search/nepomuksearch.protocol
+++ b/nepomuk/kioslaves/search/nepomuksearch.protocol
@@ -14,3 +14,4 @@ source=false
 Icon=nepomuk
 Class=:local
 maxInstances=20
+X-DocPath=kioslave/nepomuksearch/index.html
diff --git a/nepomuk/kioslaves/search/searchfolder.cpp b/nepomuk/kioslaves/search/searchfolder.cpp
index 941bdf8..4829133 100644
--- a/nepomuk/kioslaves/search/searchfolder.cpp
+++ b/nepomuk/kioslaves/search/searchfolder.cpp
@@ -23,6 +23,7 @@
 #include "nie.h"
 #include "pimo.h"
 #include "nepomuksearchurltools.h"
+#include "resourcestat.h"
 
 #include <Soprano/Vocabulary/Xesam>
 #include <Soprano/Vocabulary/NAO>
@@ -55,8 +56,19 @@ Nepomuk::SearchFolder::SearchFolder( const KUrl& url, KIO::SlaveBase* slave )
 
     qRegisterMetaType<QList<QUrl> >();
 
-    // parse URL
-    m_query = queryFromUrl( url );
+    // parse URL (this may fail in which case we fall back to pure SPARQL below)
+    m_query = Nepomuk::Query::Query::fromQueryUrl( url );
+
+    // the only request property we handle is nie:url
+    m_query.setRequestProperties( QList<Query::Query::RequestProperty>() << Query::Query::RequestProperty( Nepomuk::Vocabulary::NIE::url() ) );
+
+    if ( m_query.isValid() ) {
+        m_sparqlQuery = m_query.toSparqlQuery();
+    }
+    else {
+        // the URL contains pure sparql. We simply list it without trying to change the limit
+        m_sparqlQuery = Nepomuk::Query::Query::sparqlFromQueryUrl( url );
+    }
 }
 
 
@@ -87,9 +99,7 @@ void Nepomuk::SearchFolder::run()
              this, SLOT( slotFinishedListing() ),
              Qt::DirectConnection );
 
-    Query::Query q;
-    q.addRequestProperty( Query::Query::RequestProperty( Nepomuk::Vocabulary::NIE::url() ) );
-    m_client->sparqlQuery( m_query, q.requestPropertyMap() );
+    m_client->sparqlQuery( m_sparqlQuery, m_query.requestPropertyMap() );
     exec();
     delete m_client;
 
@@ -109,9 +119,6 @@ void Nepomuk::SearchFolder::list()
 
     kDebug() << "listing done";
 
-    m_slave->listEntry( KIO::UDSEntry(), true );
-    m_slave->finished();
-
     // shutdown and delete
     exit();
     deleteLater();
@@ -121,7 +128,7 @@ void Nepomuk::SearchFolder::list()
 // always called in search thread
 void Nepomuk::SearchFolder::slotNewEntries( const QList<Nepomuk::Query::Result>& results )
 {
-    kDebug() << m_url << QThread::currentThread();
+    kDebug() << m_url;
 
     m_resultMutex.lock();
     m_resultsQueue += results;
@@ -137,7 +144,7 @@ void Nepomuk::SearchFolder::slotNewEntries( const QList<Nepomuk::Query::Result>&
 // always called in search thread
 void Nepomuk::SearchFolder::slotFinishedListing()
 {
-    kDebug() << m_url << QThread::currentThread();
+    kDebug() << m_url;
     QMutexLocker lock( &m_resultMutex );
     m_initialListingFinished = true;
     m_resultWaiter.wakeAll();
@@ -155,7 +162,7 @@ void Nepomuk::SearchFolder::statResults()
             KIO::UDSEntry uds = statResult( result );
             if ( uds.count() ) {
                 kDebug() << "listing" << result.resource().resourceUri();
-                m_slave->listEntry( uds, false );
+                m_slave->listEntries( KIO::UDSEntryList() << uds );
             }
         }
         else if ( !m_initialListingFinished ) {
@@ -171,81 +178,100 @@ void Nepomuk::SearchFolder::statResults()
 
 
 namespace {
-    bool statFile( const KUrl& url, KIO::UDSEntry& uds )
+    bool statFile( const KUrl& url, const KUrl& fileUrl, KIO::UDSEntry& uds )
     {
         // the akonadi kio slave is just way too slow and
         // in KDE 4.4 akonadi items should have nepomuk:/res/<uuid> URIs anyway
         if ( url.scheme() == QLatin1String( "akonadi" ) )
             return false;
 
-        bool success = false;
-
-        if ( KIO::StatJob* job = KIO::stat( url, KIO::HideProgressInfo ) ) {
-            job->setAutoDelete( false );
-            if ( KIO::NetAccess::synchronousRun( job, 0 ) ) {
-                uds = job->statResult();
-                success = true;
-            }
-            else {
-                kDebug() << "failed to stat" << url;
+        if ( !fileUrl.isEmpty() ) {
+            if ( KIO::StatJob* job = KIO::stat( fileUrl, KIO::HideProgressInfo ) ) {
+                // we do not want to wait for the event loop to delete the job
+                QScopedPointer<KIO::StatJob> sp( job );
+                job->setAutoDelete( false );
+                if ( KIO::NetAccess::synchronousRun( job, 0 ) ) {
+                    uds = job->statResult();
+                    return true;
+                }
             }
-            delete job;
         }
 
-        return success;
+        Nepomuk::Resource res( url );
+        if ( res.exists() ) {
+            uds = Nepomuk::statNepomukResource( res );
+            return true;
+        }
+
+        kDebug() << "failed to stat" << url;
+        return false;
     }
 }
 
 
 // always called in main thread
+// This method tries to avoid loading the Nepomuk::Resource as long as possible by only using the
+// request property nie:url in the Result for local files.
 KIO::UDSEntry Nepomuk::SearchFolder::statResult( const Query::Result& result )
 {
     Resource res( result.resource() );
-    KUrl url = res.resourceUri();
+    KUrl url( res.resourceUri() );
+    KUrl nieUrl( result[Nepomuk::Vocabulary::NIE::url()].uri() );
+    if ( nieUrl.isEmpty() )
+        nieUrl = Nepomuk::nepomukToFileUrl( url );
 
     KIO::UDSEntry uds;
-    if ( statFile( url, uds ) ) {
-        if ( result.resource().hasProperty( Nepomuk::Vocabulary::NIE::url() ) ) {
-            KUrl fileUrl( res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl() );
-
+    if ( statFile( url, nieUrl, uds ) ) {
+        if ( !nieUrl.isEmpty() ) {
             // needed since the nepomuk:/ KIO slave does not do stating of files in its own
             // subdirs (tags and filesystems), and neither do we with real subdirs
             if ( uds.isDir() )
-                uds.insert( KIO::UDSEntry::UDS_URL, fileUrl.url() );
-
-            if ( fileUrl.isLocalFile() ) {
-                uds.insert( KIO::UDSEntry::UDS_LOCAL_PATH, fileUrl.toLocalFile() );
+                uds.insert( KIO::UDSEntry::UDS_URL, nieUrl.url() );
+
+            if ( nieUrl.isLocalFile() ) {
+                // There is a trade-off between using UDS_TARGET_URL or not. The advantage is that we get proper
+                // file names in opening applications and non-KDE apps can handle the URLs properly. The downside
+                // is that we lose the context information, i.e. query results cannot be browsed in the opening
+                // application. We decide pro-filenames and pro-non-kde-apps here.
+                if( !uds.isDir() )
+                    uds.insert( KIO::UDSEntry::UDS_TARGET_URL, nieUrl.url() );
+                uds.insert( KIO::UDSEntry::UDS_LOCAL_PATH, nieUrl.toLocalFile() );
             }
+
+            // make sure we have unique names for everything
+            uds.insert( KIO::UDSEntry::UDS_NAME, resourceUriToUdsName( nieUrl ) );
+        }
+        else {
+            // make sure we have unique names for everything
+            uds.insert( KIO::UDSEntry::UDS_NAME, resourceUriToUdsName( url ) );
         }
 
         // needed since the file:/ KIO slave does not create them and KFileItem::nepomukUri()
         // cannot know that it is a local file since it is forwarded
         uds.insert( KIO::UDSEntry::UDS_NEPOMUK_URI, url.url() );
 
-        // make sure we have unique names for everything
-        uds.insert( KIO::UDSEntry::UDS_NAME, resourceUriToUdsName( url ) );
-
         // make sure we do not use these ugly names for display
         if ( !uds.contains( KIO::UDSEntry::UDS_DISPLAY_NAME ) ) {
-            if ( res.hasType( Nepomuk::Vocabulary::PIMO::Thing() ) ) {
+            // by checking nieUrl we avoid loading the resource for local files
+            if ( nieUrl.isEmpty() &&
+                 res.hasType( Nepomuk::Vocabulary::PIMO::Thing() ) ) {
                 if ( !res.pimoThing().groundingOccurrences().isEmpty() ) {
                     res = res.pimoThing().groundingOccurrences().first();
                 }
             }
 
-            if ( res.hasProperty( Nepomuk::Vocabulary::NIE::url() ) ) {
-                KUrl fileUrl( res.property( Nepomuk::Vocabulary::NIE::url() ).toUrl() );
-                uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, fileUrl.fileName() );
+            if ( !nieUrl.isEmpty() ) {
+                uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, nieUrl.fileName() );
 
                 // since we change the UDS_NAME KFileItem cannot handle mimetype and such anymore
                 QString mimetype = uds.stringValue( KIO::UDSEntry::UDS_MIME_TYPE );
                 if ( mimetype.isEmpty() ) {
-                    mimetype = KMimeType::findByUrl(fileUrl)->name();
+                    mimetype = KMimeType::findByUrl(nieUrl)->name();
                     uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, mimetype );
                 }
             }
             else {
-                uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, result.resource().genericLabel() );
+                uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, res.genericLabel() );
             }
         }
 
diff --git a/nepomuk/kioslaves/search/searchfolder.h b/nepomuk/kioslaves/search/searchfolder.h
index e005c27..bce8d11 100644
--- a/nepomuk/kioslaves/search/searchfolder.h
+++ b/nepomuk/kioslaves/search/searchfolder.h
@@ -47,12 +47,31 @@ namespace Nepomuk {
         Q_OBJECT
 
     public:
+        /**
+         * Create a new search folder which reads the query from \a url.
+         * Call list() to actually let it list results via slave->listEntry()
+         */
         SearchFolder( const KUrl& url, KIO::SlaveBase* slave );
+
+        /**
+         * Destructor
+         */
         ~SearchFolder();
 
-        QString query() const { return m_query; }
+        /**
+         * Query URL used by this folder.
+         */
         KUrl url() const { return m_url; }
 
+        /**
+         * The query used by this folder or an invalid one in case
+         * the query URL contains a pure SPARQL query string.
+         */
+        Query::Query query() const { return m_query; }
+
+        /**
+         * List the results directly on the parent slave.
+         */
         void list();
 
     private Q_SLOTS:
@@ -83,8 +102,12 @@ namespace Nepomuk {
         // folder properties
         KUrl m_url;
 
+        /// might be invalid in case the url contained a SPARQL query which
+        /// we could not parse. In that case use m_sparqlQuery
+        Query::Query m_query;
+
         // SPARQL query that is actually sent to the query service
-        QString m_query;
+        QString m_sparqlQuery;
 
         // result cache, filled by the search thread
         QQueue<Query::Result> m_resultsQueue;
diff --git a/nepomuk/kioslaves/timeline/CMakeLists.txt b/nepomuk/kioslaves/timeline/CMakeLists.txt
index e7aa40c..a3f7fb1 100644
--- a/nepomuk/kioslaves/timeline/CMakeLists.txt
+++ b/nepomuk/kioslaves/timeline/CMakeLists.txt
@@ -5,11 +5,30 @@ include_directories(
   ${KDE4_INCLUDES}
   ${KDE4_KIO_INCLUDES}
   ${NEPOMUK_INCLUDE_DIR}
+  ${nepomuk_kio_slaves_SOURCE_DIR}/common
 )
 
 ########### next target ###############
 
-set(kio_timeline_PART_SRCS kio_timeline.cpp)
+set(kio_timeline_PART_SRCS
+  kio_timeline.cpp
+  ../common/timelinetools.cpp)
+
+soprano_add_ontology(kio_timeline_PART_SRCS
+  ${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nie/nfo.trig
+  "NFO"
+  "Nepomuk::Vocabulary"
+  "trig")
+soprano_add_ontology(kio_timeline_PART_SRCS
+  ${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nie/nie.trig
+  "NIE"
+  "Nepomuk::Vocabulary"
+  "trig")
+soprano_add_ontology(kio_timeline_PART_SRCS
+  ${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nepomuk/nuao.trig
+  "NUAO"
+  "Nepomuk::Vocabulary"
+  "trig")
 
 kde4_add_plugin(kio_timeline ${kio_timeline_PART_SRCS})
 
diff --git a/nepomuk/kioslaves/timeline/kio_timeline.cpp b/nepomuk/kioslaves/timeline/kio_timeline.cpp
index cbed3c3..25b8e30 100644
--- a/nepomuk/kioslaves/timeline/kio_timeline.cpp
+++ b/nepomuk/kioslaves/timeline/kio_timeline.cpp
@@ -20,6 +20,11 @@
 
 #include "kio_timeline.h"
 
+#include "nfo.h"
+#include "nie.h"
+#include "nuao.h"
+#include "timelinetools.h"
+
 #include <KUrl>
 #include <kio/global.h>
 #include <klocale.h>
@@ -28,8 +33,8 @@
 #include <KDebug>
 #include <KLocale>
 #include <kio/netaccess.h>
-#include <KCalendarSystem>
 #include <KComponentData>
+#include <KCalendarSystem>
 
 #include <Soprano/Vocabulary/NAO>
 #include <Soprano/Vocabulary/XMLSchema>
@@ -47,38 +52,6 @@ using namespace KIO;
 
 
 namespace {
-    const char* DATEFORMATSTART("yyyy-MM-ddT00:00:00.000Z");
-    const char* DATEFORMATEND("yyyy-MM-ddT23:59:59.999Z");
-
-    KUrl buildQueryUrl( const QDate& date )
-    {
-        QString dateFrom = date.toString(DATEFORMATSTART);
-        QString dateTo = date.toString(DATEFORMATEND);
-
-        QString query = QString("select distinct ?r where { "
-                                "?r a nfo:FileDataObject . "
-                                "{"
-                                "  ?r nie:lastModified ?date . "
-                                "} "
-#ifdef NEPOMUK_TIMELINE_WITH_NTAO
-                                "UNION "
-                                "{"
-                                "  ?de a ?det . ?det rdfs:subClassOf ntao:DataObjectEvent . "
-                                "  ?de ntao:timestamp ?date . "
-                                "  ?de ntao:dataObject ?r . "
-                                "} "
-#endif
-                                "FILTER(?date > '%1'^^%3 && ?date < '%2'^^%3) . "
-                                "OPTIONAL { ?r2 a nfo:Folder . FILTER(?r=?r2) . } . FILTER(!BOUND(?r2)) . "
-                                "}")
-                        .arg(dateFrom)
-                        .arg(dateTo)
-                        .arg(Soprano::Node::resourceToN3(Soprano::Vocabulary::XMLSchema::dateTime()));
-        KUrl url("nepomuksearch:/");
-        url.addQueryItem( "sparql", query );
-        return url;
-    }
-
     KIO::UDSEntry createFolderUDSEntry( const QString& name, const QString& displayName, const QDate& date )
     {
         KIO::UDSEntry uds;
@@ -116,50 +89,11 @@ namespace {
                                      KGlobal::locale()->formatDate( date, KLocale::FancyLongDate ),
                                      date );
     }
-
-    QDate applyRelativeDateModificators( const QDate& date, const QMap<QString, QString>& modificators )
-    {
-        QDate newDate( date );
-        const QString dayKey = QLatin1String("relDays");
-        const QString weekKey = QLatin1String("relWeeks");
-        const QString monthKey = QLatin1String("relMonths");
-        const QString yearKey = QLatin1String("relYears");
-        bool ok = false;
-
-        if (modificators.contains(yearKey)) {
-            int relYears = modificators[yearKey].toInt(&ok);
-            if (ok) {
-                newDate = newDate.addYears(relYears);
-            }
-        }
-        if (modificators.contains(monthKey)) {
-            int relMonths = modificators[monthKey].toInt(&ok);
-            if (ok) {
-                newDate = newDate.addMonths(relMonths);
-            }
-        }
-        if (modificators.contains(weekKey)) {
-            int relWeeks = modificators[weekKey].toInt(&ok);
-            if (ok) {
-                const KCalendarSystem * calSystem = KGlobal::locale()->calendar();
-                newDate = newDate.addDays(relWeeks * calSystem->daysInWeek(date));
-            }
-        }
-        if (modificators.contains(dayKey)) {
-            int relDays = modificators[dayKey].toInt(&ok);
-            if (ok) {
-                newDate = newDate.addDays(relDays);
-            }
-        }
-        return newDate;
-    }
 }
 
 
 Nepomuk::TimelineProtocol::TimelineProtocol( const QByteArray& poolSocket, const QByteArray& appSocket )
-    : KIO::ForwardingSlaveBase( "timeline", poolSocket, appSocket ),
-      m_folderType( NoFolder ),
-      m_dateRegexp( QLatin1String("\\d{4}-\\d{2}(?:-(\\d{2}))?") )
+    : KIO::ForwardingSlaveBase( "timeline", poolSocket, appSocket )
 {
     kDebug();
 }
@@ -173,39 +107,34 @@ Nepomuk::TimelineProtocol::~TimelineProtocol()
 
 void Nepomuk::TimelineProtocol::listDir( const KUrl& url )
 {
-    if ( parseUrl( url ) ) {
-        switch( m_folderType ) {
-        case RootFolder:
-            listEntry( createFolderUDSEntry( QLatin1String("today"), i18n("Today"), QDate::currentDate() ), false );
-            listEntry( createFolderUDSEntry( QLatin1String("calendar"), i18n("Calendar"), QDate::currentDate() ), false );
-            listEntry( KIO::UDSEntry(), true );
-            finished();
-            break;
-
-        case CalendarFolder:
-            listThisYearsMonths();
-            // TODO: add entry for previous years
-            listEntry( KIO::UDSEntry(), true );
-            finished();
-            break;
-
-        case MonthFolder:
-            listDays( m_date.month(), m_date.year() );
-            listEntry( KIO::UDSEntry(), true );
-            finished();
-            break;
-
-        case DayFolder:
-            ForwardingSlaveBase::listDir( url );
-            break;
-
-        default:
-            error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() );
-            break;
-        }
-    }
-    else {
+    switch( parseTimelineUrl( url, &m_date, &m_filename ) ) {
+    case RootFolder:
+        listEntry( createFolderUDSEntry( QLatin1String("today"), i18n("Today"), QDate::currentDate() ), false );
+        listEntry( createFolderUDSEntry( QLatin1String("calendar"), i18n("Calendar"), QDate::currentDate() ), false );
+        listEntry( KIO::UDSEntry(), true );
+        finished();
+        break;
+
+    case CalendarFolder:
+        listThisYearsMonths();
+        // TODO: add entry for previous years
+        listEntry( KIO::UDSEntry(), true );
+        finished();
+        break;
+
+    case MonthFolder:
+        listDays( m_date.month(), m_date.year() );
+        listEntry( KIO::UDSEntry(), true );
+        finished();
+        break;
+
+    case DayFolder:
+        ForwardingSlaveBase::listDir( url );
+        break;
+
+    default:
         error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() );
+        break;
     }
 }
 
@@ -221,7 +150,7 @@ void Nepomuk::TimelineProtocol::get( const KUrl& url )
 {
     kDebug() << url;
 
-    if ( parseUrl( url ) && !m_filename.isEmpty() ) {
+    if ( parseTimelineUrl( url, &m_date, &m_filename ) && !m_filename.isEmpty() ) {
         ForwardingSlaveBase::get( url );
     }
     else {
@@ -234,7 +163,7 @@ void Nepomuk::TimelineProtocol::put( const KUrl& url, int permissions, KIO::JobF
 {
     kDebug() << url;
 
-    if ( parseUrl( url ) && !m_filename.isEmpty() ) {
+    if ( parseTimelineUrl( url, &m_date, &m_filename ) && !m_filename.isEmpty() ) {
         ForwardingSlaveBase::put( url, permissions, flags );
     }
     else {
@@ -280,46 +209,41 @@ void Nepomuk::TimelineProtocol::mimetype( const KUrl& url )
 
 void Nepomuk::TimelineProtocol::stat( const KUrl& url )
 {
-    if ( parseUrl( url ) ) {
-        switch( m_folderType ) {
-        case RootFolder: {
-            KIO::UDSEntry uds;
-            uds.insert( KIO::UDSEntry::UDS_NAME, QString::fromLatin1( "/" ) );
-            uds.insert( KIO::UDSEntry::UDS_ICON_NAME, QString::fromLatin1( "nepomuk" ) );
-            uds.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
-            uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1( "inode/directory" ) );
-            statEntry( uds );
-            finished();
-            break;
-        }
+    switch( parseTimelineUrl( url, &m_date, &m_filename ) ) {
+    case RootFolder: {
+        KIO::UDSEntry uds;
+        uds.insert( KIO::UDSEntry::UDS_NAME, QString::fromLatin1( "/" ) );
+        uds.insert( KIO::UDSEntry::UDS_ICON_NAME, QString::fromLatin1( "nepomuk" ) );
+        uds.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
+        uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1( "inode/directory" ) );
+        statEntry( uds );
+        finished();
+        break;
+    }
 
-        case CalendarFolder:
-            statEntry( createFolderUDSEntry( QLatin1String("calendar"), i18n("Calendar"), QDate::currentDate() ) );
-            finished();
-            break;
+    case CalendarFolder:
+        statEntry( createFolderUDSEntry( QLatin1String("calendar"), i18n("Calendar"), QDate::currentDate() ) );
+        finished();
+        break;
+
+    case MonthFolder:
+        statEntry( createMonthUDSEntry( m_date.month(), m_date.year() ) );
+        finished();
+        break;
 
-        case MonthFolder:
-            statEntry( createMonthUDSEntry( m_date.month(), m_date.year() ) );
+    case DayFolder:
+        if ( m_filename.isEmpty() ) {
+            statEntry( createDayUDSEntry( m_date ) );
             finished();
-            break;
-
-        case DayFolder:
-            if ( m_filename.isEmpty() ) {
-                statEntry( createDayUDSEntry( m_date ) );
-                finished();
-            }
-            else {
-                ForwardingSlaveBase::stat( url );
-            }
-            break;
-
-        default:
-            error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() );
-            break;
         }
-    }
-    else {
+        else {
+            ForwardingSlaveBase::stat( url );
+        }
+        break;
+
+    default:
         error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() );
+        break;
     }
 }
 
@@ -327,8 +251,8 @@ void Nepomuk::TimelineProtocol::stat( const KUrl& url )
 // only used for the queries
 bool Nepomuk::TimelineProtocol::rewriteUrl( const KUrl& url, KUrl& newURL )
 {
-    if ( parseUrl( url ) && m_folderType == DayFolder ) {
-        newURL = buildQueryUrl( m_date );
+    if ( parseTimelineUrl( url, &m_date, &m_filename ) == DayFolder ) {
+        newURL = buildTimelineQueryUrl( m_date );
         newURL.setPath( QLatin1String( "/" ) + m_filename );
         return true;
     }
@@ -377,67 +301,6 @@ void Nepomuk::TimelineProtocol::listPreviousYears()
 }
 
 
-bool Nepomuk::TimelineProtocol::parseUrl( const KUrl& url )
-{
-    kDebug() << url;
-
-    // rest
-    m_date = QDate();
-    m_filename.truncate(0);
-
-    const QString path = url.path(KUrl::RemoveTrailingSlash);
-
-    if( path.isEmpty() || path == QLatin1String("/") ) {
-        m_folderType = RootFolder;
-        kDebug() << url << "is root folder";
-        return true;
-    }
-    else if( path.startsWith( QLatin1String( "/today" ) ) ) {
-        m_folderType = DayFolder;
-        m_date = QDate::currentDate();
-        m_filename = path.mid( 7 );
-        kDebug() << url << "is today folder:" << m_date << m_filename;
-        return true;
-    }
-    else if( path == QLatin1String( "/calendar" ) ) {
-        m_folderType = CalendarFolder;
-        kDebug() << url << "is calendar folder";
-        return true;
-    }
-    else {
-        QStringList sections = path.split( QLatin1String( "/" ), QString::SkipEmptyParts );
-        QString dateString;
-        if ( m_dateRegexp.exactMatch( sections.last() ) ) {
-            dateString = sections.last();
-        }
-        else if ( sections.count() > 1 && m_dateRegexp.exactMatch( sections[sections.count()-2] ) ) {
-            dateString = sections[sections.count()-2];
-            m_filename = sections.last();
-        }
-        else {
-            kDebug() << url << "COULD NOT PARSE";
-            return false;
-        }
-
-        if ( m_dateRegexp.cap( 1 ).isEmpty() ) {
-            // no day -> month listing
-            m_folderType = MonthFolder;
-            kDebug() << "parsing " << dateString;
-            m_date = QDate::fromString( dateString, QLatin1String("yyyy-MM") );
-            kDebug() << url << "is month folder:" << m_date.month() << m_date.year();
-            return m_date.month() > 0 && m_date.year() > 0;
-        }
-        else {
-            m_folderType = DayFolder;
-            kDebug() << "parsing " << dateString;
-            m_date = applyRelativeDateModificators( QDate::fromString( dateString, "yyyy-MM-dd" ), url.queryItems() );
-            // only in day folders we can have filenames
-            kDebug() << url << "is day folder:" << m_date << m_filename;
-            return m_date.isValid();
-        }
-    }
-}
-
 extern "C"
 {
     KDE_EXPORT int kdemain( int argc, char **argv )
diff --git a/nepomuk/kioslaves/timeline/kio_timeline.h b/nepomuk/kioslaves/timeline/kio_timeline.h
index ffcb8fc..c31d6ee 100644
--- a/nepomuk/kioslaves/timeline/kio_timeline.h
+++ b/nepomuk/kioslaves/timeline/kio_timeline.h
@@ -24,8 +24,6 @@
 #include <kio/forwardingslavebase.h>
 
 #include <QtCore/QDate>
-#include <QtCore/QRegExp>
-
 
 namespace Nepomuk {
     class TimelineProtocol : public KIO::ForwardingSlaveBase
@@ -100,24 +98,9 @@ namespace Nepomuk {
         void listThisYearsMonths();
         void listPreviousYears();
 
-        /// will set m_date, m_filename, and m_folderType
-        bool parseUrl( const KUrl& url );
-
-        /// folder type that is set by parseUrl
-        enum FolderType {
-            NoFolder = 0,    /// nothing
-            RootFolder,      /// the root folder
-            CalendarFolder,  /// the calendar folder listing all months
-            MonthFolder,     /// a folder listing a month's days (m_date contains the month)
-            DayFolder        /// a folder listing a day (m_date); optionally m_filename is set
-        };
-
         /// temp vars for the currently handled URL
         QDate m_date;
         QString m_filename;
-        FolderType m_folderType;
-
-        const QRegExp m_dateRegexp;
     };
 }
 
diff --git a/nepomuk/server/CMakeLists.txt b/nepomuk/server/CMakeLists.txt
index 565ea6a..e0a23ad 100644
--- a/nepomuk/server/CMakeLists.txt
+++ b/nepomuk/server/CMakeLists.txt
@@ -18,7 +18,6 @@ set(nepomukserver_SRCS
   servicecontroller.cpp
   processcontrol.cpp
   main.cpp
-  legacystoragebridge.cpp
   )
 
 # Server configuration
diff --git a/nepomuk/server/nepomukserver.cpp b/nepomuk/server/nepomukserver.cpp
index 46d0df2..0625244 100644
--- a/nepomuk/server/nepomukserver.cpp
+++ b/nepomuk/server/nepomukserver.cpp
@@ -21,7 +21,6 @@
 #include "nepomukserversettings.h"
 #include "servicemanager.h"
 #include "servicemanageradaptor.h"
-#include "legacystoragebridge.h"
 
 #include <Soprano/Global>
 
@@ -39,7 +38,6 @@ Nepomuk::Server* Nepomuk::Server::s_self = 0;
 Nepomuk::Server::Server( QObject* parent )
     : QObject( parent ),
       m_enabled( false ),
-      m_legacyStorageBridge( 0 ),
       m_strigiServiceName( "nepomukstrigiservice" )
 {
     s_self = this;
@@ -80,20 +78,13 @@ void Nepomuk::Server::enableNepomuk( bool enabled )
 {
     kDebug() << "enableNepomuk" << enabled;
     if ( enabled != m_enabled ) {
+        m_enabled = enabled;
         if ( enabled ) {
             // start all autostart services
             m_serviceManager->startAllServices();
 
             // register the service manager interface
             QDBusConnection::sessionBus().registerObject( "/servicemanager", m_serviceManager );
-
-            // provide the storage interface for backwards compatibility
-            if ( !m_legacyStorageBridge ) {
-                m_legacyStorageBridge = new LegacyStorageBridge( this );
-            }
-
-            // now nepomuk is enabled
-            m_enabled = true;
         }
         else {
             // stop all running services
@@ -101,13 +92,6 @@ void Nepomuk::Server::enableNepomuk( bool enabled )
 
             // unregister the service manager interface
             QDBusConnection::sessionBus().unregisterObject( "/servicemanager" );
-
-            // we delete since Soprano::Server::ServerCore does not have an unregister method yet
-            delete m_legacyStorageBridge;
-            m_legacyStorageBridge = 0;
-
-            // nepomuk is disabled
-            m_enabled = false;
         }
     }
 }
diff --git a/nepomuk/server/nepomukserver.desktop b/nepomuk/server/nepomukserver.desktop
index c7bf6f4..180bba4 100644
--- a/nepomuk/server/nepomukserver.desktop
+++ b/nepomuk/server/nepomukserver.desktop
@@ -6,7 +6,7 @@ X-KDE-autostart-condition=nepomukserverrc:Basic Settings:Start Nepomuk:true
 OnlyShowIn=KDE;
 X-KDE-autostart-phase=1
 Name=Nepomuk Server
-Name[ar]=خادم  نيبموك
+Name[ar]=خادم نبومك
 Name[be@latin]=Server „Nepomuk”
 Name[bg]=Сървър Nepomuk
 Name[bn]=নেপোমুক সার্ভার
@@ -35,6 +35,7 @@ Name[hne]=नेपोमक सेवा
 Name[hr]=Poslužitelj Nepomuk
 Name[hsb]=Nepomuk Serwer
 Name[hu]=Nepomuk szolgáltatás
+Name[ia]=Servitor de Nepomuk
 Name[id]=Server Nepomuk
 Name[is]=Nepomuk miðlari
 Name[it]=Server di Nepomuk
@@ -63,7 +64,7 @@ Name[ro]=Server Nepomuk
 Name[ru]=Сервер Nepomuk
 Name[se]=Nepomuk-bálvá
 Name[si]=Nepomuk ධාරකය
-Name[sk]=Nepomuk server
+Name[sk]=Server Nepomuk
 Name[sl]=Strežnik Nepomuk
 Name[sr]=Сервер Непомука
 Name[sr@ijekavian]=Сервер Непомука
@@ -107,14 +108,15 @@ Comment[gu]=નેપોમુક સર્વર સંગ્રહ સેવ
 Comment[he]=שרת Nepomuk מספק שירותי אחסון ושליטת strigi
 Comment[hi]=नेपोमक सर्वर - भंडारण सेवाएँ तथा स्ट्रिगि नियंत्रण प्रदान करता है
 Comment[hne]=नेपोमक सर्वर जउन भंडार सेवा अउ स्ट्रिगि कंट्रोल देथे
-Comment[hr]=Nepomuk poslužitelj koji pruža usluge pohrane i upravljanja Strigijem
+Comment[hr]=Poslužitelj Nepomuk omogućuje usluge pohrane i upravljanja Strigijem
 Comment[hsb]=Nepomuk-serwer staji składowanske słužby a strigi-kontrolu k dispoziciji.
 Comment[hu]=A Nepomuk szolgáltatás tárolási lehetőséget biztosít és a Strigi vezérlését végzi
+Comment[ia]=Le servitor Nepomuk forniente servicios de Storage e controlante de strigi
 Comment[id]=Server Nepomuk memberikan layanan Penyimpanan dan pengendalian strigi
 Comment[is]=Nepomuk miðlarinn heldur utanum geymsluþjónustur og Strigi stýringu
 Comment[it]=Il server Nepomuk fornisce servizi di memorizzazione e controllo di Strigi
 Comment[ja]=ストレージサービスを提供し Strigi を制御する Nepomuk サーバ
-Comment[kk]=Сақтау қызметі және strigi бақлауын атқаратын Nepomuk сервері
+Comment[kk]=Сақтау қызметі және strigi бақылауын атқаратын Nepomuk сервері
 Comment[km]=ម៉ាស៊ីន​បម្រើ Nepomuk ផ្ដល់​សេវា​ផ្ទុក និង​ការត្រួតពិនិត្យ strigi
 Comment[kn]=ಸ್ಟ್ರಿಗಿ ನಿಯಂತ್ರಣ ಮತ್ತು ಸಂಗ್ರಹ ಸೇವೆಗಳನ್ನು ಒದಗಿಸುವ ನೆಪೋಮುಕ್ ಪರಿಚಾರಕ (ಸರ್ವರ್)
 Comment[ko]=저장소 서비스를 제공하는 Nepomuk 서버와 Strigi 제어
@@ -146,7 +148,7 @@ Comment[sr@latin]=Server Nepomuka pruža servis za skladištenje i kontrolu Stri
 Comment[sv]=Nepomuk-server som tillhandahåller lagringstjänster och styrning av Strigi
 Comment[ta]=The Nepomuk Server providing Storage services and strigi controlling
 Comment[te]=Nepomuk సేవిక నిల్వ సేవలను మరియు strigi నింయత్రణను అందిస్తుంది
-Comment[tg]=Сервер Nepomuk предоставляет службы хранения данных и управление Strigi
+Comment[tg]=Хидматгоҳи Nepomuk хидматҳои захира ва идоракунии маълумот дастрас мекунад
 Comment[th]=บริการ Nepomuk จะให้บริการจัดเก็บข้อมูลและทำการควบคุม strigi
 Comment[tr]=Nepomuk Sunucusu Depolama servislerini ve Strigi uygulamasının kontrolünü sağlar
 Comment[uk]=Сервер Nepomuk надає служби збереження і керування strigi
diff --git a/nepomuk/server/nepomukserver.h b/nepomuk/server/nepomukserver.h
index f069676..f2fb1eb 100644
--- a/nepomuk/server/nepomukserver.h
+++ b/nepomuk/server/nepomukserver.h
@@ -30,7 +30,6 @@ namespace Soprano {
 namespace Nepomuk {
 
     class ServiceManager;
-    class LegacyStorageBridge;
 
     class Server : public QObject
     {
@@ -63,8 +62,6 @@ namespace Nepomuk {
         ServiceManager* m_serviceManager;
         bool m_enabled;
 
-        LegacyStorageBridge* m_legacyStorageBridge;
-
         KSharedConfigPtr m_config;
 
         const QString m_strigiServiceName;
diff --git a/nepomuk/server/nepomukservice.desktop b/nepomuk/server/nepomukservice.desktop
index b7530d6..6cd0f15 100644
--- a/nepomuk/server/nepomukservice.desktop
+++ b/nepomuk/server/nepomukservice.desktop
@@ -32,6 +32,7 @@ Comment[hne]=नेपोमक सेवा
 Comment[hr]=Usluga Nepomuk
 Comment[hsb]=Nepomuk-słužba
 Comment[hu]=Nepomuk szolgáltatás
+Comment[ia]=Servicio de Nepomuk
 Comment[id]=Layanan Nepomuk
 Comment[is]=Nepomuk þjónusta
 Comment[it]=Servizio Nepomuk
diff --git a/nepomuk/server/processcontrol.cpp b/nepomuk/server/processcontrol.cpp
index 694665f..e47b542 100644
--- a/nepomuk/server/processcontrol.cpp
+++ b/nepomuk/server/processcontrol.cpp
@@ -90,27 +90,27 @@ void ProcessControl::slotFinished( int exitCode, QProcess::ExitStatus exitStatus
         if ( mPolicy == RestartOnCrash ) {
              // don't try to start an unstartable application
             if ( !mFailedToStart && --mCrashCount >= 0 ) {
-                qDebug( "Application '%s' crashed! %d restarts left.", qPrintable( mApplication ), mCrashCount );
+                qDebug( "Application '%s' crashed! %d restarts left.", qPrintable( commandLine() ), mCrashCount );
                 start();
             } else {
                 if ( mFailedToStart ) {
-                    qDebug( "Application '%s' failed to start!", qPrintable( mApplication ) );
+                    qDebug( "Application '%s' failed to start!", qPrintable( commandLine() ) );
                 } else {
-                    qDebug( "Application '%s' crashed to often. Giving up!", qPrintable( mApplication ) );
+                    qDebug( "Application '%s' crashed to often. Giving up!", qPrintable( commandLine() ) );
                 }
                 emit finished(false);
             }
         } else {
-            qDebug( "Application '%s' crashed. No restart!", qPrintable( mApplication ) );
+            qDebug( "Application '%s' crashed. No restart!", qPrintable( commandLine() ) );
         }
     } else {
         if ( exitCode != 0 ) {
             qDebug( "ProcessControl: Application '%s' returned with exit code %d (%s)",
-                    qPrintable( mApplication ), exitCode, qPrintable( mProcess.errorString() ) );
+                    qPrintable( commandLine() ), exitCode, qPrintable( mProcess.errorString() ) );
             mFailedToStart = true;
             emit finished(false);
         } else {
-            qDebug( "Application '%s' exited normally...", qPrintable( mApplication ) );
+            qDebug( "Application '%s' exited normally...", qPrintable( commandLine() ) );
             emit finished(true);
         }
     }
@@ -145,4 +145,9 @@ bool ProcessControl::isRunning() const
     return mProcess.state() == QProcess::Running;
 }
 
+QString ProcessControl::commandLine() const
+{
+    return mApplication + QLatin1String(" ") + mArguments.join(QLatin1String(" "));
+}
+
 #include "processcontrol.moc"
diff --git a/nepomuk/server/processcontrol.h b/nepomuk/server/processcontrol.h
index 4f4e12f..59c2b95 100644
--- a/nepomuk/server/processcontrol.h
+++ b/nepomuk/server/processcontrol.h
@@ -97,6 +97,8 @@ private Q_SLOTS:
 private:
     bool start();
 
+    QString commandLine() const;
+
     QProcess mProcess;
     QString mApplication;
     QStringList mArguments;
diff --git a/nepomuk/server/servicecontroller.cpp b/nepomuk/server/servicecontroller.cpp
index e60f80f..6a01cdc 100644
--- a/nepomuk/server/servicecontroller.cpp
+++ b/nepomuk/server/servicecontroller.cpp
@@ -24,13 +24,15 @@
 #include <QtCore/QEventLoop>
 #include <QtCore/QTimer>
 
+#include <QtDBus/QDBusServiceWatcher>
+
 #include <KStandardDirs>
 #include <KConfigGroup>
 #include <KDebug>
 
 
 namespace {
-    QString dbusServiceName( const QString& serviceName ) {
+    inline QString dbusServiceName( const QString& serviceName ) {
         return QString("org.kde.nepomuk.services.%1").arg(serviceName);
     }
 }
@@ -42,7 +44,9 @@ public:
     Private()
         : processControl( 0 ),
           serviceControlInterface( 0 ),
+          dbusServiceWatcher( 0 ),
           attached( false ),
+          started( false ),
           initialized( false ),
           failedToInitialize( false ) {
     }
@@ -54,11 +58,15 @@ public:
 
     ProcessControl* processControl;
     OrgKdeNepomukServiceControlInterface* serviceControlInterface;
+    QDBusServiceWatcher* dbusServiceWatcher;
 
     // true if we attached to an already running instance instead of
     // starting our own (in that case processControl will be 0)
     bool attached;
 
+    // true if we were asked to start the service
+    bool started;
+
     bool initialized;
     bool failedToInitialize;
 
@@ -66,6 +74,7 @@ public:
     QList<QEventLoop*> loops;
 
     void init( KService::Ptr service );
+    void reset();
 };
 
 
@@ -86,11 +95,31 @@ void Nepomuk::ServiceController::Private::init( KService::Ptr s )
 }
 
 
+void Nepomuk::ServiceController::Private::reset()
+{
+    initialized = false;
+    attached = false;
+    started = false;
+    failedToInitialize = false;
+    delete serviceControlInterface;
+    serviceControlInterface = 0;
+}
+
+
 Nepomuk::ServiceController::ServiceController( KService::Ptr service, QObject* parent )
     : QObject( parent ),
       d(new Private())
 {
     d->init( service );
+
+    d->dbusServiceWatcher = new QDBusServiceWatcher( dbusServiceName(name()),
+                                                     QDBusConnection::sessionBus(),
+                                                     QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration,
+                                                     this );
+    connect( d->dbusServiceWatcher, SIGNAL( serviceRegistered( QString ) ),
+             this, SLOT( slotServiceRegistered( QString ) ) );
+    connect( d->dbusServiceWatcher, SIGNAL( serviceUnregistered( QString ) ),
+             this, SLOT( slotServiceUnregistered( QString ) ) );
 }
 
 
@@ -155,11 +184,11 @@ bool Nepomuk::ServiceController::start()
         return true;
     }
 
-    d->initialized = false;
-    d->failedToInitialize = false;
+    d->reset();
+    d->started = true;
 
     // check if the service is already running, ie. has been started by someone else or by a crashed instance of the server
-    // we cannot rely on the auto-restart feature of ProcessControl here. So we handle that completely in slotServiceOwnerChanged
+    // we cannot rely on the auto-restart feature of ProcessControl here. So we handle that completely via DBus signals
     if( QDBusConnection::sessionBus().interface()->isServiceRegistered( dbusServiceName( name() ) ) ) {
         kDebug() << "Attaching to already running service" << name();
         d->attached = true;
@@ -175,10 +204,7 @@ bool Nepomuk::ServiceController::start()
                      this, SLOT( slotProcessFinished( bool ) ) );
         }
 
-        connect( QDBusConnection::sessionBus().interface(),
-                 SIGNAL( serviceOwnerChanged( const QString&, const QString&, const QString& ) ),
-                 this,
-                 SLOT( slotServiceOwnerChanged( const QString&, const QString&, const QString& ) ) );
+        // wait for the service to be registered with DBus before creating the service interface
 
         d->processControl->setCrashPolicy( ProcessControl::RestartOnCrash );
         return d->processControl->start( KGlobal::dirs()->locate( "exe", "nepomukservicestub" ),
@@ -193,6 +219,7 @@ void Nepomuk::ServiceController::stop()
         kDebug() << "Stopping" << name();
 
         d->attached = false;
+        d->started = false;
 
         if( d->processControl ) {
             d->processControl->setCrashPolicy( ProcessControl::StopOnCrash );
@@ -254,33 +281,40 @@ bool Nepomuk::ServiceController::waitForInitialized( int timeout )
 void Nepomuk::ServiceController::slotProcessFinished( bool /*clean*/ )
 {
     kDebug() << "Service" << name() << "went down";
-    d->initialized = false;
-    d->attached = false;
-    disconnect( QDBusConnection::sessionBus().interface() );
-    delete d->serviceControlInterface;
-    d->serviceControlInterface = 0;
+    d->reset();
     foreach( QEventLoop* loop, d->loops ) {
         loop->exit();
     }
 }
 
 
-void Nepomuk::ServiceController::slotServiceOwnerChanged( const QString& serviceName,
-                                                          const QString& oldOwner,
-                                                          const QString& newOwner )
+void Nepomuk::ServiceController::slotServiceRegistered( const QString& serviceName )
 {
-    if( !newOwner.isEmpty() && serviceName == dbusServiceName( name() ) ) {
+    if( serviceName == dbusServiceName( name() ) ) {
+        kDebug() << serviceName;
         createServiceControlInterface();
+        if( !d->processControl || !d->processControl->isRunning() ) {
+            d->attached = true;
+        }
     }
+}
 
+void Nepomuk::ServiceController::slotServiceUnregistered( const QString& serviceName )
+{
     // an attached service was not started through ProcessControl. Thus, we cannot rely
     // on its restart-on-crash feature and have to do it manually. Afterwards it is back
-    // to normals
-    else if( d->attached &&
-             oldOwner == dbusServiceName( name() ) ) {
-        kDebug() << "Attached service" << name() << "went down. Restarting ourselves.";
-        d->attached = false;
-        start();
+    // to normal
+    if( serviceName == dbusServiceName( name() ) ) {
+        if( d->attached && d->started ) {
+            kDebug() << "Attached service" << name() << "went down. Restarting ourselves.";
+            start();
+        }
+        else {
+            d->reset();
+            foreach( QEventLoop* loop, d->loops ) {
+                loop->exit();
+            }
+        }
     }
 }
 
@@ -293,8 +327,13 @@ void Nepomuk::ServiceController::createServiceControlInterface()
                                                                            "/servicecontrol",
                                                                            QDBusConnection::sessionBus(),
                                                                            this );
-    connect( d->serviceControlInterface, SIGNAL( serviceInitialized( bool ) ),
-             this, SLOT( slotServiceInitialized( bool ) ) );
+    if( d->serviceControlInterface->isInitialized() ) {
+        slotServiceInitialized( true );
+    }
+    else {
+        connect( d->serviceControlInterface, SIGNAL( serviceInitialized( bool ) ),
+                 this, SLOT( slotServiceInitialized( bool ) ) );
+    }
 
     if ( d->serviceControlInterface->isInitialized() ) {
         slotServiceInitialized( true );
diff --git a/nepomuk/server/servicecontroller.h b/nepomuk/server/servicecontroller.h
index 55e7bd0..d1cea8e 100644
--- a/nepomuk/server/servicecontroller.h
+++ b/nepomuk/server/servicecontroller.h
@@ -80,9 +80,8 @@ namespace Nepomuk {
         
     private Q_SLOTS:
         void slotProcessFinished( bool );
-        void slotServiceOwnerChanged( const QString& serviceName,
-                                      const QString&,
-                                      const QString& newOwner );
+        void slotServiceRegistered( const QString& serviceName );
+        void slotServiceUnregistered( const QString& serviceName );
         void slotServiceInitialized( bool success );
         
     private:
diff --git a/nepomuk/server/servicemanager.cpp b/nepomuk/server/servicemanager.cpp
index 2d16c5b..a5becd7 100644
--- a/nepomuk/server/servicemanager.cpp
+++ b/nepomuk/server/servicemanager.cpp
@@ -155,8 +155,9 @@ public:
 
     /**
      * Stop a service and all services depending on it.
+     * Return true if it was stopped, false if it was not running.
      */
-    void stopService( ServiceController* );
+    bool stopService( ServiceController* );
 
     /**
      * Start pending services based on the newly initialized service newService
@@ -244,8 +245,12 @@ void Nepomuk::ServiceManager::Private::startService( ServiceController* sc )
 }
 
 
-void Nepomuk::ServiceManager::Private::stopService( ServiceController* sc )
+bool Nepomuk::ServiceManager::Private::stopService( ServiceController* sc )
 {
+    // make sure the service is not scheduled to be started later anymore
+    pendingServices.remove( sc );
+
+    // stop it if already running
     if( sc->isRunning() ) {
         // shut down any service depending of this one first
         foreach( const QString &dep, dependencyTree.servicesDependingOn( sc->name() ) ) {
@@ -253,6 +258,10 @@ void Nepomuk::ServiceManager::Private::stopService( ServiceController* sc )
         }
 
         sc->stop();
+        return true;
+    }
+    else {
+        return false;
     }
 }
 
@@ -316,6 +325,7 @@ void Nepomuk::ServiceManager::startAllServices()
 
 void Nepomuk::ServiceManager::stopAllServices()
 {
+    d->pendingServices.clear();
     for( QHash<QString, ServiceController*>::iterator it = d->services.begin();
          it != d->services.end(); ++it ) {
         ServiceController* serviceControl = it.value();
@@ -327,39 +337,8 @@ void Nepomuk::ServiceManager::stopAllServices()
 bool Nepomuk::ServiceManager::startService( const QString& name )
 {
     if( ServiceController* sc = d->findService( name ) ) {
-        if( !sc->isRunning() ) {
-            // start dependencies if possible
-            foreach( const QString &dependency, d->dependencyTree[name] ) {
-                if ( ServiceController* depSc = d->findService( dependency ) ) {
-                    if( depSc->autostart() || depSc->startOnDemand() ) {
-                        if ( !startService( dependency ) ) {
-                            kDebug() << "Cannot start dependency" << dependency;
-                            return false;
-                        }
-                    }
-                    else {
-                        kDebug() << "Dependency" << dependency << "can not be started automatically. It is not an autostart or start on demand service";
-                        return false;
-                    }
-                }
-                else {
-                    kDebug() << "Invalid dependency:" << dependency;
-                    return false;
-                }
-            }
-
-            if ( sc->start() ) {
-                return sc->waitForInitialized();
-            }
-            else {
-                // failed to start service
-                return false;
-            }
-        }
-        else {
-            // service already running
-            return true;
-        }
+        d->startService( sc );
+        return sc->waitForInitialized();
     }
     else {
         // could not find service
@@ -371,12 +350,8 @@ bool Nepomuk::ServiceManager::startService( const QString& name )
 bool Nepomuk::ServiceManager::stopService( const QString& name )
 {
     if( ServiceController* sc = d->findService( name ) ) {
-        if( sc->isRunning() ) {
-            d->stopService( sc );
-            return true;
-        }
+        return d->stopService( sc );
     }
-
     return false;
 }
 
diff --git a/nepomuk/services/CMakeLists.txt b/nepomuk/services/CMakeLists.txt
index b629881..a8da670 100644
--- a/nepomuk/services/CMakeLists.txt
+++ b/nepomuk/services/CMakeLists.txt
@@ -5,3 +5,5 @@ add_subdirectory(filewatch)
 add_subdirectory(queryservice)
 add_subdirectory(strigi)
 add_subdirectory(removablestorage)
+
+add_subdirectory(activities)
diff --git a/nepomuk/services/activities/CMakeLists.txt b/nepomuk/services/activities/CMakeLists.txt
new file mode 100644
index 0000000..9fc009b
--- /dev/null
+++ b/nepomuk/services/activities/CMakeLists.txt
@@ -0,0 +1,48 @@
+include(SopranoAddOntology)
+
+set(nepomukactivitiesservice_SRCS
+   nepomukactivitiesservice.cpp
+   )
+
+qt4_add_dbus_adaptor(nepomukactivitiesservice_SRCS
+   org.kde.nepomuk.ActivitiesService.xml
+   nepomukactivitiesservice.h
+   NepomukActivitiesService
+   )
+
+soprano_add_ontology(
+   nepomukactivitiesservice_SRCS
+   "${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nie/nie.trig"
+   "nie"
+   "Ontologies"
+   "trig"
+   )
+
+kde4_add_plugin(
+   nepomukactivitiesservice ${nepomukactivitiesservice_SRCS}
+   )
+
+target_link_libraries(nepomukactivitiesservice
+   ${SOPRANO_CLIENT_LIBRARIES}
+   ${SOPRANO_LIBRARIES}
+   ${QT_QTCORE_LIBRARY}
+   ${QT_QTDBUS_LIBRARY}
+   ${KDE4_KDECORE_LIBS}
+   ${NEPOMUK_LIBRARIES}
+   ${NEPOMUK_QUERY_LIBRARIES}
+   )
+
+install(
+   FILES nepomukactivitiesservice.desktop
+   DESTINATION ${SERVICES_INSTALL_DIR}
+   )
+
+install(
+   TARGETS nepomukactivitiesservice
+   DESTINATION ${PLUGIN_INSTALL_DIR}
+   )
+
+# install(FILES
+#    org.kde.nepomuk.ActivitiesService.xml
+#    DESTINATION ${DBUS_INTERFACES_INSTALL_DIR}
+#    )
diff --git a/nepomuk/services/activities/nepomukactivitiesservice.cpp b/nepomuk/services/activities/nepomukactivitiesservice.cpp
new file mode 100644
index 0000000..7ab28fc
--- /dev/null
+++ b/nepomuk/services/activities/nepomukactivitiesservice.cpp
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2010 Ivan Cukic <ivan.cukic(at)kde.org>
+ * Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * 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 "nepomukactivitiesservice.h"
+#include "activitiesserviceadaptor.h"
+
+#include <QUuid>
+#include <QDebug>
+
+#include <KPluginFactory>
+#include <KDebug>
+#include <KConfig>
+#include <KStandardDirs>
+
+#include <Soprano/Model>
+#include <Soprano/StatementIterator>
+#include <Soprano/Statement>
+#include <Soprano/Node>
+#include <Soprano/NodeIterator>
+#include <Soprano/QueryResultIterator>
+#include <Soprano/Vocabulary/NAO>
+#include <Soprano/Vocabulary/RDF>
+
+#include <Nepomuk/Resource>
+#include <Nepomuk/ResourceManager>
+#include <Nepomuk/Variant>
+#include <Nepomuk/Query/Query>
+#include <Nepomuk/Query/AndTerm>
+#include <Nepomuk/Query/OrTerm>
+#include <Nepomuk/Query/ComparisonTerm>
+#include <Nepomuk/Query/ResourceTypeTerm>
+#include <Nepomuk/Query/ResourceTerm>
+#include <Nepomuk/Query/LiteralTerm>
+
+#include "nie.h"
+
+#define URL_ACTIVITY_TYPE "http://www.kde.org/ontologies/activities#Activity"
+#define ACTIVITIES_PROTOCOL "activities://"
+
+/**
+ * this macro creates a service factory which can then be found by the Qt/KDE
+ * plugin system in the Nepomuk server.
+ */
+NEPOMUK_EXPORT_SERVICE( NepomukActivitiesService, "nepomukactivitiesservice" )
+
+NepomukActivitiesService::NepomukActivitiesService(QObject * parent, const QList < QVariant > & params)
+    : Nepomuk::Service( parent )
+{
+    kDebug() << "started";
+
+    Q_UNUSED(parent)
+    Q_UNUSED(params)
+
+    Nepomuk::ResourceManager::instance()->init();
+
+    new NepomukActivitiesServiceAdaptor(this);
+
+    m_model = mainModel();
+
+    setServiceInitialized(true);
+}
+
+NepomukActivitiesService::~NepomukActivitiesService()
+{
+}
+
+QStringList NepomukActivitiesService::listAvailable() const
+{
+    QStringList result;
+
+    foreach (const Nepomuk::Resource & resource,
+            Nepomuk::ResourceManager::instance()->allResourcesOfType(QUrl(URL_ACTIVITY_TYPE))) {
+
+        kDebug() << "url for resource" << resource << urlForResource(resource);
+
+        result << activityId(resource);
+    }
+
+    return result;
+}
+
+void NepomukActivitiesService::add(const QString & id, const QString & name)
+{
+    Nepomuk::Resource activity = activityResource(id);
+    activity.setLabel(name);
+    activity.addType(QUrl(URL_ACTIVITY_TYPE));
+    activity.addIdentifier(ACTIVITIES_PROTOCOL + id);
+
+    kDebug() << activity << id << name;
+}
+
+void NepomukActivitiesService::remove(const QString & id)
+{
+    Nepomuk::Resource activity = activityResource(id);
+
+    kDebug() << activity << id;
+
+    activity.remove();
+}
+
+QString NepomukActivitiesService::name(const QString & id) const
+{
+    return activityResource(id).label();
+}
+
+void NepomukActivitiesService::setName(const QString & id, const QString & name)
+{
+    activityResource(id).setLabel(name);
+}
+
+QString NepomukActivitiesService::icon(const QString & id) const
+{
+    QStringList symbols = activityResource(id).symbols();
+
+    if (symbols.isEmpty()) {
+        return QString();
+    } else {
+        return symbols.first();
+    }
+}
+
+void NepomukActivitiesService::setIcon(const QString & id, const QString & icon)
+{
+    QStringList symbols;
+
+    symbols << icon;
+
+    activityResource(id).setSymbols(symbols);
+}
+
+QString NepomukActivitiesService::resourceUri(const QString & id) const
+{
+    return KUrl(activityResource(id).resourceUri()).url();
+}
+
+QString NepomukActivitiesService::uri(const QString & id) const
+{
+    return ACTIVITIES_PROTOCOL + id;
+}
+
+void NepomukActivitiesService::associateResource(const QString & activityId,
+    const QString & resourceUri, const QString & typeUri)
+{
+    Nepomuk::Resource activity = activityResource(activityId);
+    Nepomuk::Resource resource = Nepomuk::Resource(resourceUri);
+
+    kDebug() << activity << resource;
+
+    activity.addIsRelated(resource);
+
+    if (!typeUri.isEmpty()) {
+        resource.addType(QUrl(typeUri));
+        kDebug() << "set the resource type to" << typeUri;
+    }
+}
+
+void NepomukActivitiesService::disassociateResource(const QString & activityId,
+    const QString & resourceUri)
+{
+    Nepomuk::Resource activity = activityResource(activityId);
+    Nepomuk::Resource resource = Nepomuk::Resource(resourceUri);
+
+    kDebug() << activity << resource;
+
+    QList< Nepomuk::Resource > v = activity.isRelateds();
+    v.removeAll(resource);
+    activity.setIsRelateds(v);
+}
+
+QStringList NepomukActivitiesService::associatedResources(
+    const QString & id, const QString & resourceType) const
+{
+
+    Nepomuk::Resource activity = activityResource(id);
+
+    Nepomuk::Query::Term term = Nepomuk::Query::ComparisonTerm(
+            Soprano::Vocabulary::NAO::isRelated(),
+            Nepomuk::Query::ResourceTerm(activity)
+        ).inverted();
+
+    if (!resourceType.isEmpty()) {
+        // OrTerm so that we can support programs that use
+        // types not available in ontologies
+        KUrl resourceTypeUri(resourceType);
+
+        term = Nepomuk::Query::AndTerm(
+            term,
+            Nepomuk::Query::OrTerm(
+                Nepomuk::Query::ComparisonTerm(
+                    Soprano::Vocabulary::RDF::type(),
+                    Nepomuk::Query::ResourceTerm(Nepomuk::Resource(resourceTypeUri))
+                ),
+                Nepomuk::Query::ResourceTypeTerm(resourceTypeUri)
+            )
+        );
+    }
+
+    Nepomuk::Query::Query query(term);
+
+    Soprano::QueryResultIterator it = m_model->executeQuery(query.toSparqlQuery(),
+        Soprano::Query::QueryLanguageSparql );
+
+    QStringList result;
+
+    while ( it.next() ) {
+        QUrl uri = it["r"].uri();
+
+        Nepomuk::Resource resource(uri);
+
+        result << urlForResource(resource);
+    }
+
+    return result;
+}
+
+QStringList NepomukActivitiesService::forResource(const QString & uri) const
+{
+    kDebug() << "uri" << uri;
+
+    Nepomuk::Resource resource = Nepomuk::Resource(KUrl(uri));
+    Nepomuk::Resource activityType(QUrl(URL_ACTIVITY_TYPE));
+
+    Nepomuk::Query::Query query(
+        Nepomuk::Query::AndTerm(
+            Nepomuk::Query::ComparisonTerm(
+                Soprano::Vocabulary::RDF::type(),
+                Nepomuk::Query::ResourceTerm(activityType)
+            ),
+            Nepomuk::Query::ComparisonTerm(
+                Soprano::Vocabulary::NAO::isRelated(),
+                Nepomuk::Query::ResourceTerm(resource)
+            )
+        )
+    );
+
+    Soprano::QueryResultIterator it = m_model->executeQuery(query.toSparqlQuery(),
+        Soprano::Query::QueryLanguageSparql);
+
+    QStringList result;
+
+    while ( it.next() ) {
+        QUrl uri = it["r"].uri();
+
+        Nepomuk::Resource resource(uri);
+
+        kDebug() << urlForResource(resource);
+
+        result << activityId(resource);
+    }
+
+    return result;
+
+}
+
+void NepomukActivitiesService::_deleteAll()
+{
+    foreach (Nepomuk::Resource resource,
+            Nepomuk::ResourceManager::instance()->allResourcesOfType(QUrl(URL_ACTIVITY_TYPE))) {
+        kDebug() << "NepomukActivitiesService::_deleteAllActivities: resource: " << resource <<
+                resource.exists();
+        resource.remove();
+    }
+}
+
+QString NepomukActivitiesService::_serviceIteration() const
+{
+    return "0.3";
+}
+
+// Private
+
+Nepomuk::Resource NepomukActivitiesService::activityResource(const QString & id) const
+{
+    return Nepomuk::Resource(KUrl(ACTIVITIES_PROTOCOL + id));
+}
+
+QString NepomukActivitiesService::urlForResource(const Nepomuk::Resource & resource) const
+{
+    if (resource.identifiers().size()) {
+        return resource.identifiers()[0];
+
+    } else if (resource.hasProperty(Ontologies::nie::url())) {
+        return KUrl(resource.property(Ontologies::nie::url()).toUrl()).url();
+
+    } else {
+        kDebug() << resource.properties().keys();
+
+        return KUrl(resource.resourceUri()).url();
+
+    }
+}
+
+QString NepomukActivitiesService::activityId(const Nepomuk::Resource & resource) const
+{
+    foreach(QString identifier, resource.identifiers()) { // krazy:exclude=foreach
+        if (identifier.startsWith(ACTIVITIES_PROTOCOL)) {
+            return identifier.replace(QLatin1String(ACTIVITIES_PROTOCOL), QString());
+        }
+    }
+
+    return KUrl(resource.resourceUri()).url()
+            .replace(QLatin1String(ACTIVITIES_PROTOCOL), QString());
+}
+
+#include "nepomukactivitiesservice.moc"
diff --git a/nepomuk/services/activities/nepomukactivitiesservice.desktop b/nepomuk/services/activities/nepomukactivitiesservice.desktop
new file mode 100644
index 0000000..d7c6c69
--- /dev/null
+++ b/nepomuk/services/activities/nepomukactivitiesservice.desktop
@@ -0,0 +1,57 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=NepomukService
+X-KDE-Library=nepomukactivitiesservice
+X-KDE-Nepomuk-autostart=true
+X-KDE-Nepomuk-start-on-demand=false
+Name=Nepomuk Activities Service
+Name[ar]=خدمة أنشطة نبومك
+Name[bg]=Услуга за активност Nepomuk
+Name[ca]=Servei d'activitats del Nepomuk
+Name[ca@valencia]=Servei d'activitats del Nepomuk
+Name[da]=Nepomuk aktivitetstjeneste
+Name[de]=Nepomuk-Aktivitäten-Dienst
+Name[el]=Υπηρεσία δραστηριοτήτων Nepomuk
+Name[en_GB]=Nepomuk Activities Service
+Name[es]=Servicio de actividades de Nepomuk
+Name[et]=Nepomuki tegevuste teenus
+Name[eu]=Nepomuk jarduera zerbitzua
+Name[fi]=Nepomukin aktiviteettipalvelu
+Name[fr]=Service d'agencements de Nepomuk
+Name[fy]=Nepomuk aktiviteits tsjinst
+Name[ga]=Seirbhís Ghníomhaíochta Nepomuk
+Name[hr]=Usluga Aktivnosti Nepomuka
+Name[ia]=Servicio de Activitate de Nepomuk
+Name[id]=Layanan Aktivitas Nepomuk
+Name[is]=Nepomuk virkniþjónusta
+Name[it]=Servizio delle attività di Nepomuk
+Name[ja]=Nepomuk アクティビティサービス
+Name[kk]=Nepomuk белсенділік қызметі
+Name[km]=សេវា​សកម្មភាព​របស់ Nepomuk
+Name[kn]=ನೆಪೋಮುಕ್ ಚಟುವಟಿಕೆಗಳ ಸೇವೆ
+Name[ko]=Nepomuk 활동 서비스
+Name[lt]=Nepomuk veiklų tarnyba
+Name[lv]=Nepomuk aktivitāšu serviss
+Name[ml]=നെപ്പോമുക്ക് ആക്റ്റിവിറ്റികളുടെ സേവനം
+Name[nb]=Nepomuk aktivitetstjeneste
+Name[nds]=Nepomuk-Aktivitetendeenst
+Name[nl]=Nepomuk activiteitenservice
+Name[nn]=Nepomuk aktivitetsteneste
+Name[pa]=ਨਿਪੋਮੁਕ ਸਟਰੀਗੀ ਸਰਵਿਸ
+Name[pl]=Usługa aktywności Nepomuka
+Name[pt]=Serviço de Actividades do Nepomuk
+Name[pt_BR]=Serviço de Atividades do Nepomuk
+Name[sk]=Služba aktivít Nepomuku
+Name[sl]=Storitev dejavnosti za Nepomuk
+Name[sr]=Непомуков сервис активности
+Name[sr@ijekavian]=Непомуков сервис активности
+Name[sr@ijekavianlatin]=Nepomukov servis aktivnosti
+Name[sr@latin]=Nepomukov servis aktivnosti
+Name[sv]=Nepomuk aktivitetstjänst
+Name[th]=บริการ Nepomuk Activities
+Name[tr]=Nepomuk Eylemler Servisi
+Name[uk]=Служба просторів дій Nepomuk
+Name[x-test]=xxNepomuk Activities Servicexx
+Name[zh_CN]=Nepomuk 活动服务
+Name[zh_TW]=Nepomuk 活動服務
+Comment=
diff --git a/nepomuk/services/activities/nepomukactivitiesservice.h b/nepomuk/services/activities/nepomukactivitiesservice.h
new file mode 100644
index 0000000..994e86e
--- /dev/null
+++ b/nepomuk/services/activities/nepomukactivitiesservice.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2010 Ivan Cukic <ivan.cukic(at)kde.org>
+ * Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * 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_ACTIVITIES_SERVICE_H
+#define NEPOMUK_ACTIVITIES_SERVICE_H
+
+#include <Nepomuk/Service>
+#include <Nepomuk/Resource>
+
+#include <QtCore/QVariant>
+#include <QtCore/QUrl>
+
+#include <KConfigGroup>
+
+/**
+ * Nepomuk service for storing workspace activities
+ */
+class NepomukActivitiesService: public Nepomuk::Service {
+    Q_OBJECT
+    Q_CLASSINFO("D-Bus Interface", "org.kde.nepomuk.services.NepomukActivitiesService")
+
+public:
+    /**
+     * Creates a new ActivitiesService
+     */
+    NepomukActivitiesService(QObject* parent, const QVariantList & args);
+
+    /**
+     * Destroys this ActivitiesService
+     */
+    ~NepomukActivitiesService();
+
+public Q_SLOTS:
+    /**
+     * @returns the list of all activities
+     */
+    QStringList listAvailable() const;
+
+    /**
+     * Creates a new activity. If the activity already
+     * exists, only the name is set
+     * @param activityId id to be used
+     * @param activityName name of the activity
+     */
+    void add(const QString & activityId,
+            const QString & activityName);
+
+    /**
+     * Remove the specified activity
+     * @param activityId id of the activity to delete
+     */
+    void remove(const QString & activityId);
+
+    /**
+     * @returns the name of the specified activity
+     * @param activityId id of the activity
+     */
+    QString name(const QString & activityId) const;
+
+    /**
+     * Sets the name of the specified activity
+     * @param activityId id of the activity
+     * @param name name to be set
+     */
+    void setName(const QString & activityId, const QString & name);
+
+    /**
+     * @returns the icon of the specified activity
+     * @param activityId id of the activity
+     */
+    QString icon(const QString & activityId) const;
+
+    /**
+     * Sets the icon of the specified activity.
+     * @param activityId id of the activity
+     * @param icon path or freedesktop.org icon name
+     */
+    void setIcon(const QString & activityId, const QString & icon);
+
+    /**
+     * @returns the Nepomuk URI of the specified activity
+     * @param activityId id of the activity
+     */
+    QString resourceUri(const QString & activityId) const;
+
+    /**
+     * @returns activity uri for the specified activity
+     * @param activityId id of the activity
+     */
+    QString uri(const QString & activityId) const;
+
+    /**
+     * Links the resource and the activity. (Adds 'is related to' link
+     * from the resource to the activity)
+     * @param activityID id of the activity
+     * @param resourceUri Nepomuk resource URI
+     * @param typeUri type to assign to the resource to be linked
+     */
+    void associateResource(const QString & activityID,
+        const QString & resourceUri, const QString & typeUri = QString());
+
+    /**
+     * Unlinks the resource and the activity. (Removes 'is related to' link
+     * from the resource to the activity)
+     * @param activityID id of the activity
+     * @param resourceUri Nepomuk resource URI
+     */
+    void disassociateResource(const QString & activityID,
+        const QString & resourceUri);
+
+    /**
+     * @returns the list of resources that are related to
+     * the specified activity
+     * @param activityId id of the activity
+     */
+    QStringList associatedResources(const QString & activityId, const QString & resourceType = QString()) const;
+
+    /**
+     * @returns the list of activities associated with the
+     * specified resource
+     */
+    QStringList forResource(const QString & uri) const;
+
+    /**
+     * This function is for debugging purposes only,
+     * and will be deleted
+     */
+    void _deleteAll();
+
+    /**
+     * This function is for debugging purposes only,
+     * and will be deleted
+     */
+    QString _serviceIteration() const;
+
+private:
+    Soprano::Model * m_model;
+
+    Nepomuk::Resource activityResource(const QString & activityId) const;
+    QString activityId(const Nepomuk::Resource & resource) const;
+
+    QString urlForResource(const Nepomuk::Resource & resource) const;
+
+};
+
+#endif // NEPOMUK_ACTIVITIES_SERVICE_H
diff --git a/nepomuk/services/activities/org.kde.nepomuk.ActivitiesService.xml b/nepomuk/services/activities/org.kde.nepomuk.ActivitiesService.xml
new file mode 100644
index 0000000..68027fc
--- /dev/null
+++ b/nepomuk/services/activities/org.kde.nepomuk.ActivitiesService.xml
@@ -0,0 +1,70 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+  <interface name="org.kde.nepomuk.services.NepomukActivitiesService">
+    <method name="listAvailable">
+      <arg type="as" direction="out"/>
+    </method>
+    <method name="add">
+      <arg name="activityId" type="s" direction="in"/>
+      <arg name="activityName" type="s" direction="in"/>
+    </method>
+    <method name="remove">
+      <arg name="activityId" type="s" direction="in"/>
+    </method>
+    <method name="name">
+      <arg type="s" direction="out"/>
+      <arg name="activityId" type="s" direction="in"/>
+    </method>
+    <method name="setName">
+      <arg name="activityId" type="s" direction="in"/>
+      <arg name="name" type="s" direction="in"/>
+    </method>
+    <method name="icon">
+      <arg type="s" direction="out"/>
+      <arg name="activityId" type="s" direction="in"/>
+    </method>
+    <method name="setIcon">
+      <arg name="activityId" type="s" direction="in"/>
+      <arg name="name" type="s" direction="in"/>
+    </method>
+    <method name="resourceUri">
+      <arg type="s" direction="out"/>
+      <arg name="activityId" type="s" direction="in"/>
+    </method>
+    <method name="uri">
+      <arg type="s" direction="out"/>
+      <arg name="activityId" type="s" direction="in"/>
+    </method>
+    <method name="associateResource">
+      <arg name="activityID" type="s" direction="in"/>
+      <arg name="resourceUri" type="s" direction="in"/>
+      <arg name="typeUri" type="s" direction="in"/>
+    </method>
+    <method name="associateResource">
+      <arg name="activityID" type="s" direction="in"/>
+      <arg name="resourceUri" type="s" direction="in"/>
+    </method>
+    <method name="disassociateResource">
+      <arg name="activityID" type="s" direction="in"/>
+      <arg name="resourceUri" type="s" direction="in"/>
+    </method>
+    <method name="associatedResources">
+      <arg type="as" direction="out"/>
+      <arg name="activityId" type="s" direction="in"/>
+      <arg name="resourceType" type="s" direction="in"/>
+    </method>
+    <method name="associatedResources">
+      <arg type="as" direction="out"/>
+      <arg name="activityId" type="s" direction="in"/>
+    </method>
+    <method name="forResource">
+      <arg type="as" direction="out"/>
+      <arg name="uri" type="s" direction="in"/>
+    </method>
+    <method name="_deleteAll">
+    </method>
+    <method name="_serviceIteration">
+      <arg type="s" direction="out"/>
+    </method>
+  </interface>
+</node>
diff --git a/nepomuk/services/filewatch/CMakeLists.txt b/nepomuk/services/filewatch/CMakeLists.txt
index 87251d6..4014496 100644
--- a/nepomuk/services/filewatch/CMakeLists.txt
+++ b/nepomuk/services/filewatch/CMakeLists.txt
@@ -16,8 +16,19 @@ set(SRCS
   nepomukfilewatch.cpp
   metadatamover.cpp
   updaterequest.cpp
+  invalidfileresourcecleaner.cpp
   )
 
+qt4_add_dbus_interface(SRCS ../../interfaces/org.kde.nepomuk.Strigi.xml strigiserviceinterface)
+
+if(CMAKE_SYSTEM_NAME MATCHES "Linux")
+  set(SRCS
+    ${SRCS}
+    kinotify.cpp
+)
+add_definitions(-DBUILD_KINOTIFY)
+endif(CMAKE_SYSTEM_NAME MATCHES "Linux")
+
 soprano_add_ontology(SRCS
   ${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nie/nie.trig
   "NIE"
diff --git a/nepomuk/services/filewatch/invalidfileresourcecleaner.cpp b/nepomuk/services/filewatch/invalidfileresourcecleaner.cpp
new file mode 100644
index 0000000..4b6c81a
--- /dev/null
+++ b/nepomuk/services/filewatch/invalidfileresourcecleaner.cpp
@@ -0,0 +1,86 @@
+/*
+   Copyright (C) 2010 Vishesh Handa <handa.vish@gmail.com>
+   Copyright (C) 2010 by Sebastian Trueg <trueg@kde.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License or (at your option) version 3 or any later version
+   accepted by the membership of KDE e.V. (or its successor approved
+   by the membership of KDE e.V.), which shall act as a proxy
+   defined in Section 14 of version 3 of the license.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "invalidfileresourcecleaner.h"
+#include "nie.h"
+
+#include <QtCore/QList>
+#include <QtCore/QFile>
+
+#include <Soprano/Node>
+#include <Soprano/Model>
+#include <Soprano/QueryResultIterator>
+
+#include <Nepomuk/ResourceManager>
+
+#include <KDebug>
+
+
+Nepomuk::InvalidFileResourceCleaner::InvalidFileResourceCleaner( QObject* parent )
+    : QThread( parent ),
+      m_stopped( false )
+{
+    connect( this, SIGNAL(finished()), this, SLOT(deleteLater()) );
+}
+
+
+Nepomuk::InvalidFileResourceCleaner::~InvalidFileResourceCleaner()
+{
+    // gently terminate the thread
+    m_stopped = true;
+    wait();
+}
+
+
+void Nepomuk::InvalidFileResourceCleaner::run()
+{
+    kDebug() << "Searching for invalid local file entries";
+    //
+    // Since the removal of the graphs could intefere with the iterator and result
+    // in jumping of rows (worst case) we cache all graphs to remove
+    //
+    QList<Soprano::Node> resourcesToRemove;
+    QString query = QString::fromLatin1( "select distinct ?r ?url where { "
+                                         "?r %1 ?url. "
+                                         "FILTER(regex(str(?url), 'file://')) . }" )
+                    .arg( Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::url() ) );
+    Soprano::QueryResultIterator it = Nepomuk::ResourceManager::instance()->mainModel()->executeQuery( query, Soprano::Query::QueryLanguageSparql );
+
+    while( it.next() && !m_stopped ) {
+        QUrl url( it["url"].uri() );
+        QString file = url.toLocalFile();
+
+        if( !file.isEmpty() && !QFile::exists(file) ) {
+            kDebug() << "REMOVING " << file;
+            resourcesToRemove << it["r"];
+        }
+    }
+
+    Q_FOREACH( const Soprano::Node& r, resourcesToRemove ) {
+        if ( m_stopped )
+            break;
+        Nepomuk::ResourceManager::instance()->mainModel()->removeAllStatements( r, Soprano::Node(), Soprano::Node() );
+        Nepomuk::ResourceManager::instance()->mainModel()->removeAllStatements( Soprano::Node(), Soprano::Node(), r );
+    }
+    kDebug() << "Done searching for invalid local file entries";
+}
+
+#include "invalidfileresourcecleaner.moc"
diff --git a/nepomuk/services/filewatch/invalidfileresourcecleaner.h b/nepomuk/services/filewatch/invalidfileresourcecleaner.h
new file mode 100644
index 0000000..61e76e8
--- /dev/null
+++ b/nepomuk/services/filewatch/invalidfileresourcecleaner.h
@@ -0,0 +1,64 @@
+/*
+   Copyright (C) 2010 Vishesh Handa <handa.vish@gmail.com>
+   Copyright (C) 2010 by Sebastian Trueg <trueg@kde.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License or (at your option) version 3 or any later version
+   accepted by the membership of KDE e.V. (or its successor approved
+   by the membership of KDE e.V.), which shall act as a proxy
+   defined in Section 14 of version 3 of the license.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NEPOMUK_INVALID_FILE_RESOURCE_CLEANER_H_
+#define _NEPOMUK_INVALID_FILE_RESOURCE_CLEANER_H_
+
+#include <QtCore/QThread>
+
+namespace Nepomuk {
+    /**
+     * Once started cleans up file resource entries for
+     * files that do not exist anymore.
+     * This is something that might happen when strigi is
+     * disabled and files have been removed while Nepomuk
+     * was not running.
+     *
+     * The class deletes itself once finished.
+     */
+    class InvalidFileResourceCleaner : public QThread
+    {
+        Q_OBJECT
+
+    public:
+        /**
+         * Creates a new instance but does not start the thread yet.
+         * Use start() to actually start the cleanup.
+         */
+        InvalidFileResourceCleaner( QObject* parent = 0 );
+
+        /**
+         * Deleting the class is normally not necessary
+         * since it will delete itself once finished. But
+         * it can also be deleted manually beforehand
+         * which will cancel the cleanup process gracefully.
+         */
+        ~InvalidFileResourceCleaner();
+
+    private:
+        void run();
+
+        bool m_stopped;
+    };
+}
+
+#endif
+
diff --git a/nepomuk/services/filewatch/kinotify.cpp b/nepomuk/services/filewatch/kinotify.cpp
new file mode 100644
index 0000000..b140b5a
--- /dev/null
+++ b/nepomuk/services/filewatch/kinotify.cpp
@@ -0,0 +1,420 @@
+/* This file is part of the KDE libraries
+   Copyright (C) 2007-2010 Sebastian Trueg <trueg@kde.org>
+
+   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 "kinotify.h"
+
+#include <QtCore/QSocketNotifier>
+#include <QtCore/QHash>
+#include <QtCore/QDirIterator>
+#include <QtCore/QFile>
+#include <QtCore/QQueue>
+
+#include <kdebug.h>
+
+#include <sys/inotify.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+
+
+namespace {
+    const int EVENT_STRUCT_SIZE = sizeof( struct inotify_event );
+
+    // we need one event to fit into the buffer, the problem is that the name
+    // is a variable length array
+    const int EVENT_BUFFER_SIZE = EVENT_STRUCT_SIZE + 1024*16;
+
+    QByteArray stripTrailingSlash( const QByteArray& path ) {
+        QByteArray p( path );
+        if ( p.endsWith( '/' ) )
+            p.truncate( p.length()-1 );
+        return p;
+    }
+
+    QByteArray concatPath( const QByteArray& p1, const QByteArray& p2 ) {
+        QByteArray p(p1);
+        if( p.isEmpty() || p[p.length()-1] != '/' )
+            p.append('/');
+        p.append(p2);
+        return p;
+    }
+}
+
+class KInotify::Private
+{
+public:
+    Private( KInotify* parent )
+        : watchHiddenFolders( false ),
+          m_inotifyFd( -1 ),
+          m_notifier( 0 ),
+          q( parent) {
+    }
+
+    ~Private() {
+        close();
+    }
+
+    QHash<int, QByteArray> cookies;
+    QHash<int, QByteArray> watchPathHash;
+    QHash<QByteArray, int> pathWatchHash;
+
+    /// queue of paths to install watches for
+    QQueue<QByteArray> pathsToWatch;
+
+    unsigned char eventBuffer[EVENT_BUFFER_SIZE];
+
+    // FIXME: only stored from the last addWatch call
+    WatchEvents mode;
+    WatchFlags flags;
+
+    bool watchHiddenFolders;
+
+    int inotify() {
+        if ( m_inotifyFd < 0 ) {
+            open();
+        }
+        return m_inotifyFd;
+    }
+
+    void close() {
+        kDebug();
+        delete m_notifier;
+        m_notifier = 0;
+
+        ::close( m_inotifyFd );
+        m_inotifyFd = -1;
+    }
+
+    bool addWatch( const QByteArray& path ) {
+        kDebug() << path;
+        // we always need the unmount event to maintain our path hash
+        const int mask = mode|flags|EventUnmount;
+
+        int wd = inotify_add_watch( inotify(), path.data(), mask );
+        if ( wd > 0 ) {
+//            kDebug() << "Successfully added watch for" << path << pathHash.count();
+            QByteArray normalized = stripTrailingSlash( path );
+            watchPathHash.insert( wd, normalized );
+            pathWatchHash.insert( normalized, wd );
+            return true;
+        }
+        else {
+            kDebug() << "Failed to create watch for" << path;
+            static bool userLimitReachedSignaled = false;
+            if ( !userLimitReachedSignaled && errno == ENOSPC ) {
+                kDebug() << "User limit reached. Please raise the inotify user watch limit.";
+                userLimitReachedSignaled = true;
+                emit q->watchUserLimitReached();
+            }
+            return false;
+        }
+    }
+
+    bool addWatchesRecursively( const QByteArray& path )
+    {
+        if ( !addWatch( path ) )
+            return false;
+
+        const int len = offsetof(struct dirent, d_name) +
+                pathconf(path.data(), _PC_NAME_MAX) + 1;
+        struct dirent* entry = ( struct dirent* )new char[len];
+
+        DIR* dir = opendir( path.data() );
+        if ( dir ) {
+            struct dirent *result = 0;
+            while ( !readdir_r( dir, entry, &result ) ) {
+
+                if ( !result ) {
+                    // end of folder
+                    break;
+                }
+
+                if ( ( entry->d_type == DT_UNKNOWN ||
+                      entry->d_type == DT_DIR ) &&
+                        ( watchHiddenFolders ||
+                         qstrncmp( entry->d_name, ".", 1 ) ) &&
+                        qstrcmp( entry->d_name, "." ) &&
+                        qstrcmp( entry->d_name, ".." ) ) {
+                    bool isDir = true;
+                    QByteArray subDir = concatPath( path, QByteArray::fromRawData( entry->d_name, qstrlen( entry->d_name ) ) );
+                    if ( entry->d_type == DT_UNKNOWN ) {
+                        struct stat buf;
+                        lstat( subDir.data(), &buf );
+                        isDir = S_ISDIR( buf.st_mode );
+                    }
+
+                    if ( isDir ) {
+                        pathsToWatch.enqueue( subDir );
+                    }
+                }
+            }
+
+            closedir( dir );
+            delete [] entry;
+
+            return true;
+        }
+        else {
+            kDebug() << "Could not open dir" << path;
+            return false;
+        }
+    }
+
+    void removeWatch( int wd ) {
+        kDebug() << wd << watchPathHash[wd];
+        pathWatchHash.remove( watchPathHash.take( wd ) );
+        inotify_rm_watch( inotify(), wd );
+    }
+
+    void _k_addWatches() {
+        // add the next batch of paths
+        for ( int i = 0; i < 100; ++i ) {
+            if ( pathsToWatch.isEmpty() ||
+                 !addWatchesRecursively( pathsToWatch.dequeue() ) ) {
+                return;
+            }
+        }
+
+        // asyncroneously add the next batch
+        if ( !pathsToWatch.isEmpty() ) {
+            QMetaObject::invokeMethod( q, "_k_addWatches", Qt::QueuedConnection );
+        }
+    }
+
+private:
+    void open() {
+        kDebug();
+        m_inotifyFd = inotify_init();
+        delete m_notifier;
+        if ( m_inotifyFd > 0 ) {
+            fcntl( m_inotifyFd, F_SETFD, FD_CLOEXEC );
+            kDebug() << "Successfully opened connection to inotify:" << m_inotifyFd;
+            m_notifier = new QSocketNotifier( m_inotifyFd, QSocketNotifier::Read );
+            connect( m_notifier, SIGNAL( activated( int ) ), q, SLOT( slotEvent( int ) ) );
+        }
+    }
+
+    int m_inotifyFd;
+    QSocketNotifier* m_notifier;
+
+    KInotify* q;
+};
+
+
+KInotify::KInotify( QObject* parent )
+    : QObject( parent ),
+      d( new Private( this ) )
+{
+}
+
+
+KInotify::~KInotify()
+{
+    delete d;
+}
+
+
+bool KInotify::available() const
+{
+    if( d->inotify() > 0 ) {
+        // trueg: Copied from KDirWatch.
+        struct utsname uts;
+        int major, minor, patch;
+        if ( uname(&uts) < 0 ) {
+            return false; // *shrug*
+        }
+        else if ( sscanf( uts.release, "%d.%d.%d", &major, &minor, &patch) != 3 ) {
+            return false; // *shrug*
+        }
+        else if( major * 1000000 + minor * 1000 + patch < 2006014 ) { // <2.6.14
+            kDebug(7001) << "Can't use INotify, Linux kernel too old";
+            return false;
+        }
+
+        return true;
+    }
+    else {
+        return false;
+    }
+}
+
+
+bool KInotify::watchingPath( const QString& path ) const
+{
+    const QByteArray p( stripTrailingSlash( QFile::encodeName( path ) ) );
+    return d->pathWatchHash.contains(p);
+}
+
+
+bool KInotify::addWatch( const QString& path, WatchEvents mode, WatchFlags flags )
+{
+    kDebug() << path;
+
+    d->mode = mode;
+    d->flags = flags;
+    d->pathsToWatch.append( QFile::encodeName( path ) );
+    d->_k_addWatches();
+    return true;
+}
+
+
+bool KInotify::removeWatch( const QString& path )
+{
+    kDebug() << path;
+    QByteArray encodedPath = QFile::encodeName( path );
+    QHash<int, QByteArray>::iterator it = d->watchPathHash.begin();
+    while ( it != d->watchPathHash.end() ) {
+        if ( it.value().startsWith( encodedPath ) ) {
+            inotify_rm_watch( d->inotify(), it.key() );
+            d->pathWatchHash.remove(it.value());
+            it = d->watchPathHash.erase( it );
+        }
+        else {
+            ++it;
+        }
+    }
+    return true;
+}
+
+
+void KInotify::slotEvent( int socket )
+{
+    // read at least one event
+    const int len = read( socket, d->eventBuffer, EVENT_BUFFER_SIZE );
+    int i = 0;
+    while ( i < len && len-i >= EVENT_STRUCT_SIZE  ) {
+        const struct inotify_event* event = ( struct inotify_event* )&d->eventBuffer[i];
+
+        QByteArray path;
+
+        // the event name only contains an interesting value if we get an event for a file/folder inside
+        // a watched folder. Otherwise we should ignore it
+        if ( event->mask & (EventDeleteSelf|EventMoveSelf) ) {
+            path = d->watchPathHash.value( event->wd );
+        }
+        else {
+            // we cannot use event->len here since it contains the size of the buffer and not the length of the string
+            const QByteArray eventName = QByteArray::fromRawData( event->name, qstrlen(event->name) );
+            const QByteArray hashedPath = d->watchPathHash.value( event->wd );
+            path = concatPath( hashedPath, eventName );
+        }
+
+        // now signal the event
+        if ( event->mask & EventAccess) {
+//            kDebug() << path << "EventAccess";
+            emit accessed( QFile::decodeName(path) );
+        }
+        if ( event->mask & EventAttributeChange ) {
+//            kDebug() << path << "EventAttributeChange";
+            emit attributeChanged( QFile::decodeName(path) );
+        }
+        if ( event->mask & EventCloseWrite ) {
+//            kDebug() << path << "EventCloseWrite";
+            emit closedWrite( QFile::decodeName(path) );
+        }
+        if ( event->mask & EventCloseRead ) {
+//            kDebug() << path << "EventCloseRead";
+            emit closedRead( QFile::decodeName(path) );
+        }
+        if ( event->mask & EventCreate ) {
+//            kDebug() << path << "EventCreate";
+            if ( event->mask & IN_ISDIR ) {
+                // FIXME: store the mode and flags somewhere
+                addWatch( path, d->mode, d->flags );
+            }
+            emit created( QFile::decodeName(path) );
+        }
+        if ( event->mask & EventDelete ) {
+//            kDebug() << path << "EventDelete";
+            // we watch all folders recursively. Thus, folder removing is reported in DeleteSelf.
+            if( !(event->mask & IN_ISDIR) )
+                emit deleted( QFile::decodeName(path), false );
+        }
+        if ( event->mask & EventDeleteSelf ) {
+//            kDebug() << path << "EventDeleteSelf";
+            d->removeWatch( event->wd );
+            emit deleted( QFile::decodeName(path), event->mask & IN_ISDIR );
+        }
+        if ( event->mask & EventModify ) {
+//            kDebug() << path << "EventModify";
+            emit modified( QFile::decodeName(path) );
+        }
+        if ( event->mask & EventMoveSelf ) {
+//            kDebug() << path << "EventMoveSelf";
+        }
+        if ( event->mask & EventMoveFrom ) {
+//            kDebug() << path << "EventMoveFrom";
+            d->cookies[event->cookie] = path;
+        }
+        if ( event->mask & EventMoveTo ) {
+            // check if we have a cookie for this one
+            if ( d->cookies.contains( event->cookie ) ) {
+                const QByteArray oldPath = d->cookies.take(event->cookie);
+
+                // update the path cache
+                if( event->mask & IN_ISDIR ) {
+                    QHash<QByteArray, int>::iterator it = d->pathWatchHash.find(oldPath);
+                    if( it != d->pathWatchHash.end() ) {
+                        kDebug() << oldPath << path;
+                        const int wd = it.value();
+                        d->watchPathHash[wd] = path;
+                        d->pathWatchHash.erase(it);
+                        d->pathWatchHash.insert( path, wd );
+                    }
+                }
+//                kDebug() << oldPath << "EventMoveTo" << path;
+                emit moved( QFile::encodeName(oldPath), QFile::decodeName(path) );
+            }
+            else {
+                kDebug() << "No cookie for move information of" << path;
+            }
+        }
+        if ( event->mask & EventOpen ) {
+//            kDebug() << path << "EventOpen";
+            emit opened( QFile::decodeName(path) );
+        }
+        if ( event->mask & EventUnmount ) {
+//            kDebug() << path << "EventUnmount. removing from path hash";
+            if ( event->mask & IN_ISDIR ) {
+                d->removeWatch( event->wd );
+            }
+            emit unmounted( QFile::decodeName(path) );
+        }
+        if ( event->mask & EventQueueOverflow ) {
+            // This should not happen since we grab all events as soon as they arrive
+            kDebug() << path << "EventQueueOverflow";
+//            emit queueOverflow();
+        }
+        if ( event->mask & EventIgnored ) {
+            kDebug() << path << "EventIgnored";
+        }
+
+        i += EVENT_STRUCT_SIZE + event->len;
+    }
+
+    if ( len < 0 ) {
+        kDebug() << "Failed to read event.";
+    }
+}
+
+#include "kinotify.moc"
diff --git a/nepomuk/services/filewatch/kinotify.h b/nepomuk/services/filewatch/kinotify.h
new file mode 100644
index 0000000..8055784
--- /dev/null
+++ b/nepomuk/services/filewatch/kinotify.h
@@ -0,0 +1,176 @@
+/* This file is part of the KDE libraries
+   Copyright (C) 2007-2010 Sebastian Trueg <trueg@kde.org>
+
+   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 _KINOTIFY_H_
+#define _KINOTIFY_H_
+
+#include <QtCore/QObject>
+#include <QtCore/QFlags>
+
+/**
+ * A simple wrapper around inotify which only allows
+ * to add folders recursively.
+ */
+class KInotify : public QObject
+{
+    Q_OBJECT
+
+public:
+    KInotify( QObject* parent = 0 );
+    ~KInotify();
+
+    /**
+     * Inotify events that can occur. Use with addWatch
+     * to define the events that should be watched.
+     *
+     * These flags correspond to the native Linux inotify flags.
+     */
+    enum WatchEvent {
+        EventAccess = 0x00000001, /**< File was accessed (read, compare inotify's IN_ACCESS) */
+        EventAttributeChange = 0x00000004, /**< Metadata changed (permissions, timestamps, extended attributes, etc., compare inotify's IN_ATTRIB) */
+        EventCloseWrite = 0x00000008, /**< File opened for writing was closed (compare inotify's IN_CLOSE_WRITE) */
+        EventCloseRead = 0x00000010, /**< File not opened for writing was closed (compare inotify's IN_CLOSE_NOWRITE) */
+        EventCreate = 0x00000100, /** File/directory created in watched directory (compare inotify's IN_CREATE) */
+        EventDelete = 0x00000200, /**< File/directory deleted from watched directory (compare inotify's IN_DELETE) */
+        EventDeleteSelf = 0x00000400, /**< Watched file/directory was itself deleted (compare inotify's IN_DELETE_SELF) */
+        EventModify = 0x00000002, /**< File was modified (compare inotify's IN_MODIFY) */
+        EventMoveSelf = 0x00000800, /**< Watched file/directory was itself moved (compare inotify's IN_MOVE_SELF) */
+        EventMoveFrom = 0x00000040, /**< File moved out of watched directory (compare inotify's IN_MOVED_FROM) */
+        EventMoveTo = 0x00000080, /**< File moved into watched directory (compare inotify's IN_MOVED_TO) */
+        EventOpen = 0x00000020, /**< File was opened (compare inotify's IN_OPEN) */
+        EventUnmount = 0x00002000, /**< Backing fs was unmounted (compare inotify's IN_UNMOUNT) */
+        EventQueueOverflow = 0x00004000, /**< Event queued overflowed (compare inotify's IN_Q_OVERFLOW) */
+        EventIgnored = 0x00008000, /**< File was ignored (compare inotify's IN_IGNORED) */
+        EventMove = ( EventMoveFrom|EventMoveTo),
+        EventAll = ( EventAccess|
+                     EventAttributeChange|
+                     EventCloseWrite|
+                     EventCloseRead|
+                     EventCreate|
+                     EventDelete|
+                     EventDeleteSelf|
+                     EventModify|
+                     EventMoveSelf|
+                     EventMoveFrom|
+                     EventMoveTo|
+                     EventOpen )
+    };
+    Q_DECLARE_FLAGS(WatchEvents, WatchEvent)
+
+    /**
+     * Watch flags
+     *
+     * These flags correspond to the native Linux inotify flags.
+     */
+    enum WatchFlag {
+        FlagOnlyDir = 0x01000000, /**< Only watch the path if it is a directory (IN_ONLYDIR) */
+        FlagDoNotFollow = 0x02000000, /**< Don't follow a sym link (IN_DONT_FOLLOW) */
+        FlagOneShot = 0x80000000 /**< Only send event once (IN_ONESHOT) */
+    };
+    Q_DECLARE_FLAGS(WatchFlags, WatchFlag)
+
+    /**
+     * \return \p true if inotify is available and usable.
+     */
+    bool available() const;
+
+    bool watchingPath( const QString& path ) const;
+
+public Q_SLOTS:
+    bool addWatch( const QString& path, WatchEvents modes, WatchFlags flags = WatchFlags() );
+    bool removeWatch( const QString& path );
+
+Q_SIGNALS:
+    /**
+     * Emitted if a file is accessed (KInotify::EventAccess)
+     */
+    void accessed( const QString& file );
+
+    /**
+     * Emitted if file attributes are changed (KInotify::EventAttributeChange)
+     */
+    void attributeChanged( const QString& file );
+
+    /**
+     * Emitted if FIXME (KInotify::EventCloseWrite)
+     */
+    void closedWrite( const QString& file );
+
+    /**
+     * Emitted if FIXME (KInotify::EventCloseRead)
+     */
+    void closedRead( const QString& file );
+
+    /**
+     * Emitted if a new file has been created in one of the watched
+     * folders (KInotify::EventCreate)
+     */
+    void created( const QString& file );
+
+    /**
+     * Emitted if a watched file or folder has been deleted.
+     * This includes files in watched foldes (KInotify::EventDelete and KInotify::EventDeleteSelf)
+     */
+    void deleted( const QString& file, bool isFolder );
+
+    /**
+     * Emitted if a watched file is modified (KInotify::EventModify)
+     */
+    void modified( const QString& file );
+
+    /**
+     * Emitted if a file or folder has been moved or renamed.
+     *
+     * \warning The moved signal will only be emitted if both the source and target folder
+     * are being watched.
+     */
+    void moved( const QString& oldName, const QString& newName );
+
+    /**
+     * Emitted if a file is opened (KInotify::EventOpen)
+     */
+    void opened( const QString& file );
+
+    /**
+     * Emitted if a watched path has been unmounted (KInotify::EventUnmount)
+     */
+    void unmounted( const QString& file );
+
+    /**
+     * Emitted if during updating the internal watch structures (recursive watches)
+     * the inotify user watch limit was reached.
+     *
+     * This means that not all requested paths can be watched until the user watch
+     * limit is increased.
+     *
+     * This signal will only be emitted once.
+     */
+    void watchUserLimitReached();
+
+private Q_SLOTS:
+    void slotEvent( int );
+
+private:
+    class Private;
+    Private* const d;
+
+    Q_PRIVATE_SLOT( d, void _k_addWatches() )
+};
+
+#endif
diff --git a/nepomuk/services/filewatch/metadatamover.cpp b/nepomuk/services/filewatch/metadatamover.cpp
index e12dd5f..f2df55f 100644
--- a/nepomuk/services/filewatch/metadatamover.cpp
+++ b/nepomuk/services/filewatch/metadatamover.cpp
@@ -1,5 +1,5 @@
 /* This file is part of the KDE Project
-   Copyright (c) 2009 Sebastian Trueg <trueg@kde.org>
+   Copyright (c) 2009-2010 Sebastian Trueg <trueg@kde.org>
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
@@ -19,6 +19,7 @@
 #include "metadatamover.h"
 #include "nie.h"
 #include "nfo.h"
+#include "nepomukfilewatch.h"
 
 #include <QtCore/QDir>
 #include <QtCore/QRegExp>
@@ -31,6 +32,7 @@
 #include <Soprano/Node>
 #include <Soprano/NodeIterator>
 #include <Soprano/QueryResultIterator>
+#include <Soprano/LiteralValue>
 #include <Soprano/Vocabulary/Xesam>
 
 #include <Nepomuk/Resource>
@@ -40,6 +42,7 @@
 #include <Nepomuk/Query/Query>
 #include <Nepomuk/Query/ComparisonTerm>
 #include <Nepomuk/Query/ResourceTerm>
+#include <Nepomuk/Query/LiteralTerm>
 
 #include <KDebug>
 
@@ -64,6 +67,7 @@ Nepomuk::MetadataMover::~MetadataMover()
 
 void Nepomuk::MetadataMover::stop()
 {
+    QMutexLocker lock( &m_queueMutex );
     m_stopped = true;
     m_queueWaiter.wakeAll();
 }
@@ -71,6 +75,7 @@ void Nepomuk::MetadataMover::stop()
 
 void Nepomuk::MetadataMover::moveFileMetadata( const KUrl& from, const KUrl& to )
 {
+    kDebug() << from << to;
     m_queueMutex.lock();
     UpdateRequest req( from, to );
     if ( !m_updateQueue.contains( req ) &&
@@ -83,18 +88,13 @@ void Nepomuk::MetadataMover::moveFileMetadata( const KUrl& from, const KUrl& to
 
 void Nepomuk::MetadataMover::removeFileMetadata( const KUrl& file )
 {
-    m_queueMutex.lock();
-    UpdateRequest req( file );
-    if ( !m_updateQueue.contains( req ) &&
-         !m_recentlyFinishedRequests.contains( req ) )
-        m_updateQueue.enqueue( req );
-    m_queueMutex.unlock();
-    m_queueWaiter.wakeAll();
+    removeFileMetadata( KUrl::List() << file );
 }
 
 
 void Nepomuk::MetadataMover::removeFileMetadata( const KUrl::List& files )
 {
+    kDebug() << files;
     m_queueMutex.lock();
     foreach( const KUrl& file, files ) {
         UpdateRequest req( file );
@@ -176,21 +176,53 @@ void Nepomuk::MetadataMover::removeMetadata( const KUrl& url )
         kDebug() << "empty path. Looks like a bug somewhere...";
     }
     else {
+        const bool isFolder = url.url().endsWith('/');
         Resource res( url );
         if ( res.exists() ) {
             kDebug() << "removing metadata for file" << url << "with resource URI" << res.resourceUri();
-            Query::Query query( Query::ComparisonTerm( Nepomuk::Vocabulary::NIE::isPartOf(), Query::ResourceTerm( res ) ) );
-            Soprano::QueryResultIterator it = m_model->executeQuery( query.toSparqlQuery(), Soprano::Query::QueryLanguageSparql );
-            while ( it.next() ) {
-                removeMetadata( it[0].uri() );
-            }
             res.remove();
         }
+
+        if( isFolder ) {
+            //
+            // Recursively remove children
+            // We cannot use the nie:isPartOf relation since only children could have metadata. Thus, we do a regex
+            // match on all files and folders below the URL we got.
+            //
+            // CAUTION: The trailing slash on the from URL is essential! Otherwise we might match the newly added
+            //          URLs, too (in case a rename only added chars to the name)
+            //
+            const QString query = QString::fromLatin1( "select distinct ?r where { "
+                                                       "?r %1 ?url . "
+                                                       "FILTER(REGEX(STR(?url),'^%2')) . "
+                                                       "}" )
+                                  .arg( Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::url() ),
+                                        url.url(KUrl::AddTrailingSlash) );
+            kDebug() << query;
+
+            //
+            // We cannot use one big loop since our updateMetadata calls below can change the iterator
+            // which could have bad effects like row skipping. Thus, we handle the urls in chunks of
+            // cached items.
+            //
+            while ( 1 ) {
+                QList<Soprano::Node> urls = m_model->executeQuery( query + QLatin1String( " LIMIT 100" ),
+                                                                   Soprano::Query::QueryLanguageSparql )
+                                            .iterateBindings( 0 ).allNodes();
+                if ( urls.isEmpty() )
+                    break;
+
+                for ( int i = 0; i < urls.count(); ++i ) {
+                    // the old URL of the resource to update
+                    Resource::fromResourceUri( urls[i].uri() ).remove();
+                }
+            }
+        }
     }
 }
 
 
-void Nepomuk::MetadataMover::updateMetadata( const KUrl& from, const KUrl& to )
+void Nepomuk::MetadataMover::updateMetadata( const KUrl& from, const KUrl& to, bool includeChildren )
 {
     kDebug() << from << "->" << to;
 
@@ -207,8 +239,8 @@ void Nepomuk::MetadataMover::updateMetadata( const KUrl& from, const KUrl& to )
     Resource oldResource( from );
 
     if ( oldResource.exists() ) {
-        QUrl oldResourceUri = oldResource.resourceUri();
-        QUrl newResourceUri = oldResourceUri;
+        const QUrl oldResourceUri = oldResource.resourceUri();
+        QUrl newResourceUri( oldResourceUri );
 
         //
         // Handle legacy file:/ resource URIs
@@ -217,31 +249,118 @@ void Nepomuk::MetadataMover::updateMetadata( const KUrl& from, const KUrl& to )
             newResourceUri = updateLegacyMetadata( oldResourceUri );
         }
 
-
         //
-        // Now update the nie:url and nie:isPartOf relations
+        // Now update the nie:url, nfo:fileName, and nie:isPartOf relations.
+        //
+        // We do NOT use Resource::setProperty to avoid the overhead and data clutter of creating
+        // new metadata graphs for the changed data.
         //
-        Resource newResource( newResourceUri );
-        newResource.setProperty( Nepomuk::Vocabulary::NIE::url(), to );
-        if ( newResource.hasProperty( Nepomuk::Vocabulary::NFO::fileName() ) )
-            newResource.setProperty( Nepomuk::Vocabulary::NFO::fileName(), to.fileName() );
-        Resource newParent( to.directory( KUrl::IgnoreTrailingSlash ) );
-        if ( newParent.exists() ) {
-            newResource.setProperty( Nepomuk::Vocabulary::NIE::isPartOf(), newParent );
+        // TODO: put this into a nice API which can act as the low-level version of Nepomuk::Resource
+        //
+        QString query = QString::fromLatin1( "select distinct ?g ?u ?f ?p where { "
+                                             "graph ?g { %1 ?prop ?obj . "
+                                             "OPTIONAL { %1 %2 ?u . } . "
+                                             "OPTIONAL { %1 %3 ?f . } . "
+                                             "OPTIONAL { %1 %4 ?p . } . "
+                                             "} . "
+                                             "FILTER(BOUND(?u) || BOUND(?f) || BOUND(?p)) . }" )
+                        .arg( Soprano::Node::resourceToN3( newResourceUri ),
+                              Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::url() ),
+                              Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NFO::fileName() ),
+                              Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::isPartOf() ) );
+        QList<Soprano::BindingSet> graphs
+            = m_model->executeQuery( query, Soprano::Query::QueryLanguageSparql ).allBindings();
+
+        Q_FOREACH( const Soprano::BindingSet& graph, graphs ) {
+
+            if ( graph["u"].isValid() ) {
+                m_model->removeStatement( newResourceUri,
+                                          Nepomuk::Vocabulary::NIE::url(),
+                                          graph["u"],
+                                          graph["g"] );
+                m_model->addStatement( newResourceUri,
+                                       Nepomuk::Vocabulary::NIE::url(),
+                                       to,
+                                       graph["g"] );
+            }
+
+            if ( graph["f"].isValid() ) {
+                m_model->removeStatement( newResourceUri,
+                                          Nepomuk::Vocabulary::NFO::fileName(),
+                                          graph["f"],
+                                          graph["g"] );
+                m_model->addStatement( newResourceUri,
+                                       Nepomuk::Vocabulary::NFO::fileName(),
+                                       Soprano::LiteralValue( to.fileName() ),
+                                       graph["g"] );
+            }
+
+            if ( graph["p"].isValid() ) {
+                m_model->removeStatement( newResourceUri,
+                                          Nepomuk::Vocabulary::NIE::isPartOf(),
+                                          graph["p"],
+                                          graph["g"] );
+                Resource newParent( to.directory( KUrl::IgnoreTrailingSlash ) );
+                if ( newParent.exists() ) {
+                    m_model->addStatement( newResourceUri,
+                                           Nepomuk::Vocabulary::NIE::isPartOf(),
+                                           newParent.resourceUri(),
+                                           graph["g"] );
+                }
+            }
         }
+    }
+    else {
+        //
+        // If we have no metadata yet we need to tell strigi (if running) so it can
+        // create the metadata in case the target folder is configured to be indexed.
+        //
+        emit movedWithoutData( to.directory( KUrl::IgnoreTrailingSlash ) );
+    }
 
+    if ( includeChildren && QFileInfo( to.toLocalFile() ).isDir() ) {
         //
         // Recursively update children
+        // We cannot use the nie:isPartOf relation since only children could have metadata. Thus, we do a regex
+        // match on all files and folders below the URL we got.
+        //
+        // CAUTION: The trailing slash on the from URL is essential! Otherwise we might match the newly added
+        //          URLs, too (in case a rename only added chars to the name)
+        //
+        const QString query = QString::fromLatin1( "select distinct ?url where { "
+                                                   "?r %1 ?url . "
+                                                   "FILTER(REGEX(STR(?url),'^%2')) . "
+                                                   "}" )
+                              .arg( Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::url() ),
+                                    from.url(KUrl::AddTrailingSlash) );
+        kDebug() << query;
+
+        const QString oldBasePath = from.path( KUrl::AddTrailingSlash );
+        const QString newBasePath = to.path( KUrl::AddTrailingSlash );
+
         //
-        Query::Query query( Query::ComparisonTerm( Nepomuk::Vocabulary::NIE::isPartOf(), Query::ResourceTerm( newResource ) ) );
-        query.addRequestProperty( Query::Query::RequestProperty( Nepomuk::Vocabulary::NIE::url() ) );
-        Soprano::QueryResultIterator it = m_model->executeQuery( query.toSparqlQuery(), Soprano::Query::QueryLanguageSparql );
-        while ( it.next() ) {
-            QUrl uri = it[0].uri();
-            KUrl url = it[1].uri();
-            KUrl newUrl( to );
-            newUrl.addPath( url.fileName() );
-            updateMetadata( url, newUrl );
+        // We cannot use one big loop since our updateMetadata calls below can change the iterator
+        // which could have bad effects like row skipping. Thus, we handle the urls in chunks of
+        // cached items.
+        //
+        while ( 1 ) {
+            QList<Soprano::Node> urls = m_model->executeQuery( query + QLatin1String( " LIMIT 100" ),
+                                                               Soprano::Query::QueryLanguageSparql )
+                                        .iterateBindings( 0 ).allNodes();
+            if ( urls.isEmpty() )
+                break;
+
+            for ( int i = 0; i < urls.count(); ++i ) {
+                // the old URL of the resource to update
+                const KUrl url = urls[i].uri();
+
+                // now construct the new URL
+                QString oldRelativePath = url.path().mid( oldBasePath.length() );
+                KUrl newUrl( newBasePath + oldRelativePath );
+
+                // finally update the metadata (excluding children since we already handle them all here)
+                updateMetadata( url, newUrl, false );
+            }
         }
     }
 }
@@ -259,9 +378,9 @@ QUrl Nepomuk::MetadataMover::updateLegacyMetadata( const QUrl& oldResourceUri )
     //
     // update the resource properties
     //
-    QList<Soprano::Statement> sl = m_model->listStatements( Soprano::Statement( oldResourceUri,
-                                                                                Soprano::Node(),
-                                                                                Soprano::Node() ) ).allStatements();
+    QList<Soprano::Statement> sl = m_model->listStatements( oldResourceUri,
+                                                            Soprano::Node(),
+                                                            Soprano::Node() ).allStatements();
     Q_FOREACH( const Soprano::Statement& s, sl ) {
         //
         // Skip all the stuff we will update later on
@@ -273,10 +392,10 @@ QUrl Nepomuk::MetadataMover::updateLegacyMetadata( const QUrl& oldResourceUri )
             continue;
         }
 
-        m_model->addStatement( Soprano::Statement( newResourceUri,
-                                                   s.predicate(),
-                                                   s.object(),
-                                                   s.context() ) );
+        m_model->addStatement( newResourceUri,
+                               s.predicate(),
+                               s.object(),
+                               s.context() );
     }
 
     m_model->removeStatements( sl );
diff --git a/nepomuk/services/filewatch/metadatamover.h b/nepomuk/services/filewatch/metadatamover.h
index d9129e1..c5f5925 100644
--- a/nepomuk/services/filewatch/metadatamover.h
+++ b/nepomuk/services/filewatch/metadatamover.h
@@ -50,6 +50,16 @@ namespace Nepomuk {
 
         void stop();
 
+    Q_SIGNALS:
+        /**
+         * Emitted for files (and folders) that have been moved but
+         * do not have metadata to be moved. This allows the strigi
+         * service to pick them up in case they are of interest. The
+         * typical example would be moving a file from a non-indexed into
+         * an indexed folder.
+         */
+        void movedWithoutData( const QString& path );
+
     private Q_SLOTS:
         void slotClearRecentlyFinishedRequests();
 
@@ -68,7 +78,7 @@ namespace Nepomuk {
          * If old pre-KDE 4.4 file:/ resource URIs are used these are
          * updated to the new nepomuk:/res/<UUID> scheme
          */
-        void updateMetadata( const KUrl& from, const KUrl& to );
+        void updateMetadata( const KUrl& from, const KUrl& to, bool includeChildren = true );
 
         /**
          * Convert old pre-KDE 4.4 style file:/ resource URIs to the
diff --git a/nepomuk/services/filewatch/nepomukfilewatch.cpp b/nepomuk/services/filewatch/nepomukfilewatch.cpp
index 5328864..655c7a1 100644
--- a/nepomuk/services/filewatch/nepomukfilewatch.cpp
+++ b/nepomuk/services/filewatch/nepomukfilewatch.cpp
@@ -1,5 +1,5 @@
 /* This file is part of the KDE Project
-   Copyright (c) 2007-2008 Sebastian Trueg <trueg@kde.org>
+   Copyright (c) 2007-2010 Sebastian Trueg <trueg@kde.org>
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
@@ -18,45 +18,76 @@
 
 #include "nepomukfilewatch.h"
 #include "metadatamover.h"
+#include "strigiserviceinterface.h"
+#include "invalidfileresourcecleaner.h"
+#include "nie.h"
+
+#ifdef BUILD_KINOTIFY
+#include "kinotify.h"
+#endif
 
 #include <QtCore/QDir>
+#include <QtCore/QThread>
 #include <QtDBus/QDBusConnection>
 
 #include <KDebug>
 #include <KUrl>
 #include <KPluginFactory>
 
+#include <Nepomuk/ResourceManager>
+
+#include <Soprano/Model>
+#include <Soprano/QueryResultIterator>
+#include <Soprano/Node>
 
-// Restrictions and TODO:
-// ----------------------
-//
-// * KIO slaves that do change the local file system may emit stuff like
-//   file:///foo/bar -> xyz://foobar while the file actually ends up in
-//   the local file system again. This is not handled here. It is maybe
-//   necessary to use KFileItem::mostLocalUrl to determine local paths
-//   before deciding to call updateMetaDataForResource.
-//
-// * Only operations done through KIO are caught
-//
 
 using namespace Soprano;
 
 
 NEPOMUK_EXPORT_SERVICE( Nepomuk::FileWatch, "nepomukfilewatch")
 
-
 Nepomuk::FileWatch::FileWatch( QObject* parent, const QList<QVariant>& )
     : Service( parent )
 {
     // start the mover thread
     m_metadataMover = new MetadataMover( mainModel(), this );
+    connect( m_metadataMover, SIGNAL(movedWithoutData(QString)),
+             this, SLOT(slotMovedWithoutData(QString)),
+             Qt::QueuedConnection );
     m_metadataMover->start();
 
-    // monitor KIO for changes
-    QDBusConnection::sessionBus().connect( QString(), QString(), "org.kde.KDirNotify", "FileMoved",
-                                           this, SIGNAL( slotFileMoved( const QString&, const QString& ) ) );
-    QDBusConnection::sessionBus().connect( QString(), QString(), "org.kde.KDirNotify", "FilesRemoved",
-                                           this, SIGNAL( slotFilesDeleted( const QStringList& ) ) );
+#ifdef BUILD_KINOTIFY
+    // monitor the file system for changes (restricted by the inotify limit)
+    m_dirWatch = new KInotify( this );
+
+    // FIXME: force to only use maxUserWatches-500 or something or always leave 500 free watches
+
+    connect( m_dirWatch, SIGNAL( moved( const QString&, const QString& ) ),
+             this, SLOT( slotFileMoved( const QString&, const QString& ) ) );
+    connect( m_dirWatch, SIGNAL( deleted( const QString&, bool ) ),
+             this, SLOT( slotFileDeleted( const QString&, bool ) ) );
+    connect( m_dirWatch, SIGNAL( created( const QString& ) ),
+             this, SLOT( slotFileCreated( const QString& ) ) );
+    connect( m_dirWatch, SIGNAL( modified( const QString& ) ),
+             this, SLOT( slotFileModified( const QString& ) ) );
+    connect( m_dirWatch, SIGNAL( watchUserLimitReached() ),
+             this, SLOT( slotInotifyWatchUserLimitReached() ) );
+
+    // recursively watch the whole home dir
+
+    // FIXME: we cannot simply watch the folders that contain annotated files since moving
+    // one of these files out of the watched "area" would mean we "lose" it, i.e. we have no
+    // information about where it is moved.
+    // On the other hand only using the homedir means a lot of restrictions.
+    // One dummy solution would be a hybrid: watch the whole home dir plus all folders that
+    // contain annotated files outside of the home dir and hope for the best
+
+    watchFolder( QDir::homePath() );
+#else
+    connectToKDirWatch();
+#endif
+
+    (new InvalidFileResourceCleaner(this))->start();
 }
 
 
@@ -67,9 +98,15 @@ Nepomuk::FileWatch::~FileWatch()
 }
 
 
-void Nepomuk::FileWatch::moveFileMetadata( const QString& from, const QString& to )
+void Nepomuk::FileWatch::watchFolder( const QString& path )
 {
-    slotFileMoved( from, to );
+    kDebug() << path;
+#ifdef BUILD_KINOTIFY
+    if ( m_dirWatch && !m_dirWatch->watchingPath( path ) )
+        m_dirWatch->addWatch( path,
+                              KInotify::WatchEvents( KInotify::EventMove|KInotify::EventDelete|KInotify::EventDeleteSelf|KInotify::EventCreate ),
+                              KInotify::WatchFlags() );
+#endif
 }
 
 
@@ -93,13 +130,72 @@ void Nepomuk::FileWatch::slotFilesDeleted( const QStringList& paths )
 
     kDebug() << urls;
 
-    m_metadataMover->removeFileMetadata( urls );
+    if(!urls.isEmpty())
+        m_metadataMover->removeFileMetadata( urls );
+}
+
+
+void Nepomuk::FileWatch::slotFileDeleted( const QString& urlString, bool isDir )
+{
+    // Directories must always end with a trailing slash '/'
+    QString url = urlString;
+    if( isDir && url[ url.length() - 1 ] != '/') {
+        url.append('/');
+    }
+    slotFilesDeleted( QStringList( url ) );
+}
+
+
+void Nepomuk::FileWatch::slotFileCreated( const QString& path )
+{
+    updateFolderViaStrigi( path );
+}
+
+
+void Nepomuk::FileWatch::slotFileModified( const QString& path )
+{
+    updateFolderViaStrigi( path );
+}
+
+
+void Nepomuk::FileWatch::slotMovedWithoutData( const QString& path )
+{
+    updateFolderViaStrigi( path );
+}
+
+
+// static
+void Nepomuk::FileWatch::updateFolderViaStrigi( const QString& path )
+{
+    //
+    // Tell Strigi service (if running) to update the newly created
+    // folder or the folder containing the newly created file
+    //
+    org::kde::nepomuk::Strigi strigi( "org.kde.nepomuk.services.nepomukstrigiservice", "/nepomukstrigiservice", QDBusConnection::sessionBus() );
+    if ( strigi.isValid() ) {
+        strigi.updateFolder( path, false /* no forced update */ );
+    }
+}
+
+
+void Nepomuk::FileWatch::connectToKDirWatch()
+{
+    // monitor KIO for changes
+    QDBusConnection::sessionBus().connect( QString(), QString(), "org.kde.KDirNotify", "FileMoved",
+                                           this, SIGNAL( slotFileMoved( const QString&, const QString& ) ) );
+    QDBusConnection::sessionBus().connect( QString(), QString(), "org.kde.KDirNotify", "FilesRemoved",
+                                           this, SIGNAL( slotFilesDeleted( const QStringList& ) ) );
 }
 
 
-void Nepomuk::FileWatch::slotFileDeleted( const QString& urlString )
+#ifdef BUILD_KINOTIFY
+void Nepomuk::FileWatch::slotInotifyWatchUserLimitReached()
 {
-    slotFilesDeleted( QStringList( urlString ) );
+    // we do it the brutal way for now hoping with new kernels and defaults this will never happen
+    delete m_dirWatch;
+    m_dirWatch = 0;
+    connectToKDirWatch();
 }
+#endif
 
 #include "nepomukfilewatch.moc"
diff --git a/nepomuk/services/filewatch/nepomukfilewatch.desktop b/nepomuk/services/filewatch/nepomukfilewatch.desktop
index a1bfe37..9d84e0f 100644
--- a/nepomuk/services/filewatch/nepomukfilewatch.desktop
+++ b/nepomuk/services/filewatch/nepomukfilewatch.desktop
@@ -34,6 +34,7 @@ Name[hne]=नेपोमकफाइलवाच
 Name[hr]=Nepomuk nadgledanje datoteka
 Name[hsb]=NepomukFileWatch
 Name[hu]=NepomukFileWatch
+Name[ia]=NepomukFileWatch
 Name[id]=Pengawas Berkas Nepomuk
 Name[is]=Nepomuk skráavörður
 Name[it]=Sorveglianza dei file di Nepomuk
@@ -61,7 +62,7 @@ Name[pt_BR]=NepomukFileWatch
 Name[ro]=NepomukFileWatch
 Name[ru]=NepomukFileWatch
 Name[si]=NepomukFileWatch
-Name[sk]=Sledovanie súborov pre Nepomuk
+Name[sk]=Sledovanie súborov Nepomuku
 Name[sl]=NepomukFileWatch
 Name[sr]=Непомуков надзор фајлова
 Name[sr@ijekavian]=Непомуков надзор фајлова
@@ -106,6 +107,7 @@ Comment[hne]=फाइल मं बदलाव बर नेपोमक फ
 Comment[hr]=Nepomukova usluga nadgledanja datoteka za otkrivanje promjena nad istima
 Comment[hsb]=Nepomukowe wobkedźbowanje datajow za zwěsćenje změnow
 Comment[hu]=Nepomuk fájlfigyelő szolgáltatás fájlváltozások követéséhez
+Comment[ia]=Servicio de guarda de file Nepomuk pro monitorar variationes de file
 Comment[id]=Layanan pengawas berkas Nepomuk untuk memonitor perubahan pada berkas
 Comment[is]=Nepomuk skráavarslan fylgist með breytingum á skrám
 Comment[it]=Il servizio di sorveglianza di Nepomuk per monitorare i cambiamenti dei file
@@ -140,7 +142,7 @@ Comment[sr@latin]=Nepomukov servis za nadgledanje izmena nad fajlovima
 Comment[sv]=Nepomuks filövervakningstjänst för att bevaka filändringar
 Comment[ta]=The Nepomuk file watch service for monitoring file changes
 Comment[te]=ఫైల్ మార్పులను మానిటరింగ్ చేయుటకొరకు Nepomuk ఫైల్ వాచ్ సేవ
-Comment[tg]=Служба Nepomuk file watch контролирует изменения в файлах
+Comment[tg]=Системаи Nepomuk тағйиротҳоро дар файлҳо муайян мекунад
 Comment[th]=บริการของ Nepomuk สำหรับคอยตรวจจับความเปลี่ยนแปลงของแฟ้ม
 Comment[tr]=Dosya değişikliklerini izlemek için Nepomuk dosya izleme servisi
 Comment[uk]=Служба Nepomuk для спостереження за змінами в файлах
diff --git a/nepomuk/services/filewatch/nepomukfilewatch.h b/nepomuk/services/filewatch/nepomukfilewatch.h
index e12cb6b..3901896 100644
--- a/nepomuk/services/filewatch/nepomukfilewatch.h
+++ b/nepomuk/services/filewatch/nepomukfilewatch.h
@@ -1,5 +1,5 @@
 /* This file is part of the KDE Project
-   Copyright (c) 2007-2008 Sebastian Trueg <trueg@kde.org>
+   Copyright (c) 2007-2010 Sebastian Trueg <trueg@kde.org>
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
@@ -31,9 +31,7 @@ namespace Soprano {
     }
 }
 
-namespace KInotify {
-    class DirWatch;
-}
+class KInotify;
 
 class KUrl;
 
@@ -50,19 +48,32 @@ namespace Nepomuk {
         FileWatch( QObject* parent, const QVariantList& );
         ~FileWatch();
 
+        /**
+         * Tells strigi to update the folder at \p path or the folder
+         * containing \p path in case it is a file.
+         */
+        static void updateFolderViaStrigi( const QString& path );
+
     public Q_SLOTS:
-        Q_SCRIPTABLE void moveFileMetadata( const QString& from, const QString& to );
+        Q_SCRIPTABLE void watchFolder( const QString& path );
 
     private Q_SLOTS:
         void slotFileMoved( const QString& from, const QString& to );
-        void slotFileDeleted( const QString& path );
+        void slotFileDeleted( const QString& path, bool isDir );
         void slotFilesDeleted( const QStringList& path );
+        void slotFileCreated( const QString& );
+        void slotFileModified( const QString& );
+        void slotMovedWithoutData( const QString& );
+        void connectToKDirWatch();
+#ifdef BUILD_KINOTIFY
+        void slotInotifyWatchUserLimitReached();
+#endif
 
     private:
         MetadataMover* m_metadataMover;
 
-#ifndef Q_WS_WIN
-        KInotify::DirWatch* m_dirWatch;
+#ifdef BUILD_KINOTIFY
+        KInotify* m_dirWatch;
 #endif
     };
 }
diff --git a/nepomuk/services/migration1/nepomukmigration1.desktop b/nepomuk/services/migration1/nepomukmigration1.desktop
index ef33b24..94633b2 100644
--- a/nepomuk/services/migration1/nepomukmigration1.desktop
+++ b/nepomuk/services/migration1/nepomukmigration1.desktop
@@ -32,9 +32,11 @@ Comment[hne]=नेपोमक डाटा माइग्रेसन ले
 Comment[hr]=Nepomuk Seoba Podataka Razina 1
 Comment[hsb]=Nepomuk migracija datow runina 1
 Comment[hu]=Nepomuk adatmigráció 1. szint
+Comment[ia]=Migration de Datos de Nepomuk de Nivello 1
 Comment[id]=Migrasi Data Nepomuk Level 1
 Comment[is]=Nepomuk gagnaflutningur, stig 1
 Comment[it]=Migrazione dei dati di Nepomuk di livello 1
+Comment[ja]=Nepomuk データ移行レベル 1
 Comment[kk]=Nepomuk деректерді көшіп ауыстыру - 1-деңгей
 Comment[km]=ការ​ប្ដូរ​ទិន្នន័យ Nepomuk កម្រិត ១
 Comment[kn]=ನೆಪೋಮುಕ್ ದತ್ತ ವಲಸೆ ಸ್ತರ ೧
diff --git a/nepomuk/services/ontologyloader/nepomukontologyloader.desktop b/nepomuk/services/ontologyloader/nepomukontologyloader.desktop
index 18f47ac..39c5035 100644
--- a/nepomuk/services/ontologyloader/nepomukontologyloader.desktop
+++ b/nepomuk/services/ontologyloader/nepomukontologyloader.desktop
@@ -32,6 +32,7 @@ Name[hne]=नेपोमक ओन्टोलोजी लोडर
 Name[hr]=Nepomuk Učitavač Ontologije
 Name[hsb]=Nepomuk začitanje ontologije
 Name[hu]=Nepomuk ontológiabetöltő
+Name[ia]=Cargator de Ontologia de Nepomuk
 Name[id]=Pemuat Ontologi Nepomuk
 Name[is]=Nepomuk verufræðihöndlari (Ontology Loader)
 Name[it]=Caricatore delle ontologie di Nepomuk
@@ -101,6 +102,7 @@ Comment[hne]=नेपोमक सेवा जउन सिस्टम मं
 Comment[hr]=Nepomukova usluga koja održava ontologije instalirane na sustav
 Comment[hsb]=Nepomukowa słužba, kiž so stara wo instalowane ontologije
 Comment[hu]=Nepomuk-szolgáltatás a rendszer ontológiáinak karbantartásához
+Comment[ia]=Servicio de Nepomuk que il mantene le ontologias installate su le systema
 Comment[id]=Layanan Nepomuk yang mengelola ontologi yang terinstal di sistem
 Comment[is]=Nepomuk þjónusta sem viðheldur þeim verufræðitengingum (ontologies) sem uppsettar eru á kerfinu
 Comment[it]=Servizio di Nepomuk che mantiene le ontologie installate sul sistema
diff --git a/nepomuk/services/ontologyloader/ontologyloader.cpp b/nepomuk/services/ontologyloader/ontologyloader.cpp
index 0801b7d..d14458c 100644
--- a/nepomuk/services/ontologyloader/ontologyloader.cpp
+++ b/nepomuk/services/ontologyloader/ontologyloader.cpp
@@ -1,5 +1,5 @@
 /* This file is part of the KDE Project
-   Copyright (c) 2007 Sebastian Trueg <trueg@kde.org>
+   Copyright (c) 2007-2010 Sebastian Trueg <trueg@kde.org>
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
@@ -127,7 +127,7 @@ Nepomuk::OntologyLoader::OntologyLoader( QObject* parent, const QList<QVariant>&
       d( new Private(this) )
 {
     // register ontology resource dir
-    KGlobal::dirs()->addResourceType( "ontology", 0, "share/ontology" );
+    KGlobal::dirs()->addResourceType( "xdgdata-ontology", 0, "ontology" );
 
     ( void )new OntologyManagerAdaptor( this );
 
@@ -144,7 +144,7 @@ Nepomuk::OntologyLoader::OntologyLoader( QObject* parent, const QList<QVariant>&
     connect( dirWatch, SIGNAL( created(QString) ),
              this, SLOT( updateLocalOntologies() ) );
 
-    foreach( const QString& dir, KGlobal::dirs()->resourceDirs( "ontology" ) ) {
+    foreach( const QString& dir, KGlobal::dirs()->resourceDirs( "xdgdata-ontology" ) ) {
         kDebug() << "watching" << dir;
         dirWatch->addDir( dir, KDirWatch::WatchFiles|KDirWatch::WatchSubDirs );
     }
@@ -159,7 +159,9 @@ Nepomuk::OntologyLoader::~OntologyLoader()
 
 void Nepomuk::OntologyLoader::updateLocalOntologies()
 {
-    d->desktopFilesToUpdate = KGlobal::dirs()->findAllResources( "ontology", "*.ontology", KStandardDirs::Recursive|KStandardDirs::NoDuplicates );
+    d->desktopFilesToUpdate = KGlobal::dirs()->findAllResources( "xdgdata-ontology", "*.ontology", KStandardDirs::Recursive|KStandardDirs::NoDuplicates );
+    if(d->desktopFilesToUpdate.isEmpty())
+        kError() << "No ontology files found! Make sure the shared-desktop-ontologies project is installed and XDG_DATA_DIRS is set properly.";
     d->updateTimer.start(0);
 }
 
diff --git a/nepomuk/services/queryservice/folder.h b/nepomuk/services/queryservice/folder.h
index 4bfb0f2..f0bdbdb 100644
--- a/nepomuk/services/queryservice/folder.h
+++ b/nepomuk/services/queryservice/folder.h
@@ -63,6 +63,8 @@ namespace Nepomuk {
 
             QList<FolderConnection*> openConnections() const;
 
+            QString query() const { return m_query; }
+
         public Q_SLOTS:
             void update();
 
diff --git a/nepomuk/services/queryservice/folderconnection.cpp b/nepomuk/services/queryservice/folderconnection.cpp
index 73c6dc5..3ec9c08 100644
--- a/nepomuk/services/queryservice/folderconnection.cpp
+++ b/nepomuk/services/queryservice/folderconnection.cpp
@@ -115,4 +115,16 @@ void Nepomuk::Query::FolderConnection::close()
     deleteLater();
 }
 
+
+bool Nepomuk::Query::FolderConnection::isListingFinished() const
+{
+    return m_folder->initialListingDone();
+}
+
+
+QString Nepomuk::Query::FolderConnection::queryString() const
+{
+    return m_folder->query();
+}
+
 #include "folderconnection.moc"
diff --git a/nepomuk/services/queryservice/folderconnection.h b/nepomuk/services/queryservice/folderconnection.h
index d4cfaae..9175078 100644
--- a/nepomuk/services/queryservice/folderconnection.h
+++ b/nepomuk/services/queryservice/folderconnection.h
@@ -48,6 +48,13 @@ namespace Nepomuk {
             /// close the connection to the folder. Will delete this connection
             void close();
 
+            /// \return \p true if the initial listing has been finished and the finishedListing()
+            /// has been emitted
+            bool isListingFinished() const;
+
+            /// \return the SPARQL query of the folder
+            QString queryString() const;
+
         Q_SIGNALS:
             void newEntries( const QList<Nepomuk::Query::Result>& );
             void entriesRemoved( const QStringList& );
diff --git a/nepomuk/services/queryservice/nepomukqueryservice.desktop b/nepomuk/services/queryservice/nepomukqueryservice.desktop
index e9131ae..6fad93d 100644
--- a/nepomuk/services/queryservice/nepomukqueryservice.desktop
+++ b/nepomuk/services/queryservice/nepomukqueryservice.desktop
@@ -34,6 +34,7 @@ Name[hne]=नेपोमक-क्वेरी-सर्विस
 Name[hr]=Nepomuk Upitna Usluga
 Name[hsb]=NepomukQueryService
 Name[hu]=Nepomuk-lekérdezés
+Name[ia]=NepomukQueryService
 Name[id]=NepomukQueryService
 Name[is]=Nepomuk fyrirspurnamiðlari
 Name[it]=Servizio di interrogazioni di Nepomuk
@@ -80,8 +81,8 @@ Name[zh_TW]=Nepomuk 查詢服務
 Comment=The Nepomuk Query Service provides an interface for persistent query folders
 Comment[ar]=تقدم خدمة استعلام نبومك واجهة لمجلدات الاستعلام الموجودة مسبقا.
 Comment[be@latin]=Słužba zapytaŭ „Nepomuk” absłuhoŭvaje interfejs dla stałych katalohaŭ, jakija biaruć źviestki ad zapytaŭ.
-Comment[ca]=El servei de consultes del Nepomuk  proporciona una interfície per a carpetes persistents de consultes
-Comment[ca@valencia]=El servei de consultes del Nepomuk  proporciona una interfície per a carpetes persistents de consultes
+Comment[ca]=El servei de consultes del Nepomuk proporciona una interfície per a carpetes persistents de consultes
+Comment[ca@valencia]=El servei de consultes del Nepomuk proporciona una interfície per a carpetes persistents de consultes
 Comment[cs]=Dotazovací služba Nepomuku poskytuje rozhraní pro složky trvalých dotazů
 Comment[csb]=Ùsłëżnota Query Nepomuka dôwô interfejs do persistentnegò òdwòłëwaniô kataloga
 Comment[da]=Nepomuk forespørgselstjeneste giver en grænseflade til ensartet forespørgsel af mapper
@@ -89,7 +90,7 @@ Comment[de]=Der Nepomuk-Abfragedienst stellt eine Schnittstelle für persistente
 Comment[el]=Η υπηρεσία ερωτήματος Nepomuk προσφέρει μια διασύνδεση για τη συνεχή αναζήτηση σε φακέλους
 Comment[en_GB]=The Nepomuk Query Service provides an interface for persistent query folders
 Comment[eo]=La Nepomuk ŝerĉmend-Servo provizas interfacon por daŭraj ŝerĉmend-dosierujoj
-Comment[es]=El servicio de consultas de Nepomuk proporviona una interfaz para consultas a carpetas persistentes
+Comment[es]=El servicio de consultas de Nepomuk proporciona una interfaz para consultas a carpetas persistentes
 Comment[et]=Nepomuki päringuteenus tagab püsivate päringukataloogide liidese
 Comment[eu]=Nepomuk kontsulta zerbitzuak kontsulta iraunkorren karpetentzako interfazea hornitzen du
 Comment[fi]=Nepomuk-kyselypalvelu tarjoaa liittymän pysyville kyselykansioille
@@ -98,12 +99,14 @@ Comment[fy]=De Nepomuk Query tsjinst komt mei in ynterface foar it persistint tr
 Comment[ga]=Soláthraíonn Seirbhís Iarratais Nepomuk comhéadan le fillteáin sheasmhacha iarratais
 Comment[gl]=O servizo de procura de Nepomuk fornece unha interface para cartafoles persistente de procuras
 Comment[hi]=नेपोमक क्वैरी सेवा जो परसिस्टैंस क्वैरी फ़ोल्डरों को इंटरफेस प्रदान करता है
-Comment[hr]=Nepomuk Upitna Usluga pruža sučelje za trajne upitne direktorije
+Comment[hr]=Nepomukova usluga upita omogućuje sučelje za trajne upitne direktorije
 Comment[hsb]=Nepomukowa naprašowanska słužba staji intefejs za persistentne naprašowanske zapiski k dispoziciji.
 Comment[hu]=A Nepomuk lekérdező szolgáltatás keresőmappákhoz nyújt felületet
+Comment[ia]=Le Nepomuk Query Service forni un interface pro dossieres persistente de demanda
 Comment[id]=Layanan Tanya Nepomuk menyediakan antarmuka untuk folder pertanyaan yang kukuh
 Comment[is]=Nepomuk fyrirspurnamiðlarinn er viðmót fyrir viðvarandi fyrirspurnamöppur (persistent query folders)
 Comment[it]=Il servizio di interrogazione di Nepomuk fornisce un'interfaccia per cartelle di interrogazione persistenti
+Comment[ja]=Nepomuk クエリサービスは永続クエリフォルダのインターフェースを提供します
 Comment[kk]=Nepomuk сұраныс қызметі тұрақты сұраныс қапшытарына интерфейсті қамтамасыз етеді
 Comment[km]=សេវា​សំណួរ Nepomuk ផ្ដល់​នូវ​ចំណុច​ប្រទាក់​សម្រាប់​ថត​សំណួរ​ជាប់លាប់
 Comment[kn]=ಅವಿಚ್ಛಿನ್ನ ವಿಚಾರಣಾ (ಪರ್ಸಿಸ್ಟೆಂಟ್ ಕ್ವೆರಿ) ಕಡತಕೋಶಗಳಿಗೆ ನೆಪೋಮುಕ್ ವಿಚಾರಣಾ ಸೇವೆ ಒಂದು ಸಂಪರ್ಕತಟವನ್ನು (ಇಂಟರ್ಫೇಸ್) ನೀಡುತ್ತದೆ
diff --git a/nepomuk/services/queryservice/queryservice.cpp b/nepomuk/services/queryservice/queryservice.cpp
index 97e3c20..e778bf1 100644
--- a/nepomuk/services/queryservice/queryservice.cpp
+++ b/nepomuk/services/queryservice/queryservice.cpp
@@ -26,6 +26,7 @@
 #include <QtDBus/QDBusConnectionInterface>
 #include <QtDBus/QDBusObjectPath>
 #include <QtDBus/QDBusMessage>
+#include <QtDBus/QDBusServiceWatcher>
 
 #include <KPluginFactory>
 #include <KUrl>
@@ -50,15 +51,19 @@ Nepomuk::Query::QueryService::QueryService( QObject* parent, const QVariantList&
 
     s_instance = this;
 
-    connect( QDBusConnection::sessionBus().interface(),
-             SIGNAL( serviceOwnerChanged( const QString&, const QString&, const QString& ) ),
-             this,
-             SLOT( slotServiceOwnerChanged( const QString&, const QString&, const QString& ) ) );
+    m_serviceWatcher = new QDBusServiceWatcher( this );
+    m_serviceWatcher->setWatchMode( QDBusServiceWatcher::WatchForUnregistration );
+
+    connect( m_serviceWatcher, SIGNAL( serviceUnregistered(const QString& ) ),
+             this, SLOT( slotServiceUnregistered( const QString& ) ) );
 }
 
 
 Nepomuk::Query::QueryService::~QueryService()
 {
+    // cannot use qDeleteAll since deleting a folder changes m_openQueryFolders
+    while ( !m_openConnections.isEmpty() )
+        delete m_openConnections.begin().value();
 }
 
 
@@ -102,6 +107,7 @@ QDBusObjectPath Nepomuk::Query::QueryService::sparqlQuery( const QString& sparql
     QString dbusClient = msg.service();
     m_openConnections.insert( dbusClient, conn );
     m_connectionDBusServiceHash.insert( conn, dbusClient );
+    m_serviceWatcher->addWatchedService( dbusClient );
 
     return QDBusObjectPath( dbusObjectPath );
 }
@@ -155,18 +161,15 @@ void Nepomuk::Query::QueryService::slotFolderConnectionDestroyed( QObject* o )
 }
 
 
-void Nepomuk::Query::QueryService::slotServiceOwnerChanged( const QString& serviceName,
-                                                            const QString&,
-                                                            const QString& newOwner )
+void Nepomuk::Query::QueryService::slotServiceUnregistered( const QString& serviceName )
 {
-    if ( newOwner.isEmpty() ) {
-        QList<FolderConnection*> conns = m_openConnections.values( serviceName );
-        if ( !conns.isEmpty() ) {
-            kDebug() << "Service" << serviceName << "went down. Removing connections";
-            // hash cleanup will be triggered automatically
-            qDeleteAll( conns );
-        }
+    QList<FolderConnection*> conns = m_openConnections.values( serviceName );
+    if ( !conns.isEmpty() ) {
+        kDebug() << "Service" << serviceName << "went down. Removing connections";
+        // hash cleanup will be triggered automatically
+        qDeleteAll( conns );
     }
+    m_serviceWatcher->removeWatchedService(serviceName);
 }
 
 #include "queryservice.moc"
diff --git a/nepomuk/services/queryservice/queryservice.h b/nepomuk/services/queryservice/queryservice.h
index 84d4db8..54b29c9 100644
--- a/nepomuk/services/queryservice/queryservice.h
+++ b/nepomuk/services/queryservice/queryservice.h
@@ -30,6 +30,7 @@
 
 class QDBusObjectPath;
 class QDBusMessage;
+class QDBusServiceWatcher;
 
 namespace Nepomuk {
     namespace Query {
@@ -62,9 +63,7 @@ namespace Nepomuk {
             Q_SCRIPTABLE QDBusObjectPath sparqlQuery( const QString& query, const RequestPropertyMapDBus& requestProps, const QDBusMessage& msg );
 
         private Q_SLOTS:
-            void slotServiceOwnerChanged( const QString& serviceName,
-                                          const QString&,
-                                          const QString& newOwner );
+            void slotServiceUnregistered( const QString& serviceName );
             void slotFolderDestroyed( QObject* folder );
             void slotFolderConnectionDestroyed( QObject* conn );
 
@@ -82,6 +81,7 @@ namespace Nepomuk {
             QHash<FolderConnection*, QString> m_connectionDBusServiceHash; // maps connections to their using dbus service
 
             int m_folderConnectionCnt; // only used for unique dbus object path generation
+            QDBusServiceWatcher *m_serviceWatcher;
         };
     }
 }
diff --git a/nepomuk/services/queryservice/searchthread.cpp b/nepomuk/services/queryservice/searchthread.cpp
index 3748749..7e77203 100644
--- a/nepomuk/services/queryservice/searchthread.cpp
+++ b/nepomuk/services/queryservice/searchthread.cpp
@@ -46,8 +46,9 @@
 #include <KRandom>
 
 #include <QtCore/QTime>
-#include <QLatin1String>
-#include <QStringList>
+#include <QtCore/QRegExp>
+#include <QtCore/QLatin1String>
+#include <QtCore/QStringList>
 
 
 
@@ -105,19 +106,19 @@ void Nepomuk::Query::SearchThread::run()
     // created via the Nepomuk query API.
     //
     if ( m_sparqlQuery.endsWith( QLatin1String( "}" ) ) ) {
-        sparqlQuery( m_sparqlQuery + QLatin1String( " LIMIT 10" ), 1.0 );
+        sparqlQuery( m_sparqlQuery + QLatin1String( " LIMIT 10" ) );
         if ( !m_canceled && m_resultCnt >= 10 )
-            sparqlQuery( m_sparqlQuery + QLatin1String( " OFFSET 10" ), 1.0 );
+            sparqlQuery( m_sparqlQuery + QLatin1String( " OFFSET 10" ) );
     }
     else {
-        sparqlQuery( m_sparqlQuery, 1.0 );
+        sparqlQuery( m_sparqlQuery );
     }
 
     kDebug() << time.elapsed();
 }
 
 
-void Nepomuk::Query::SearchThread::sparqlQuery( const QString& query, double baseScore )
+void Nepomuk::Query::SearchThread::sparqlQuery( const QString& query )
 {
     kDebug() << query;
 
@@ -128,9 +129,8 @@ void Nepomuk::Query::SearchThread::sparqlQuery( const QString& query, double bas
         ++m_resultCnt;
 
         Result result = extractResult( hits );
-        result.setScore( baseScore );
 
-        kDebug() << "Found result:" << result.resource().resourceUri();
+        kDebug() << "Found result:" << result.resource().resourceUri() << result.score();
 
         emit newResult( result );
     }
@@ -139,14 +139,32 @@ void Nepomuk::Query::SearchThread::sparqlQuery( const QString& query, double bas
 
 Nepomuk::Query::Result Nepomuk::Query::SearchThread::extractResult( const Soprano::QueryResultIterator& it ) const
 {
-    kDebug() << it.binding( 0 ).uri();
-    Result result( it.binding( 0 ).uri() );
+    Result result( Resource::fromResourceUri( it[0].uri() ) );
+
+    // make sure we do not store values twice
+    QStringList names = it.bindingNames();
+    names.removeAll( QLatin1String( "r" ) );
 
     for ( RequestPropertyMap::const_iterator rpIt = m_requestProperties.constBegin();
           rpIt != m_requestProperties.constEnd(); ++rpIt ) {
         result.addRequestProperty( rpIt.value(), it.binding( rpIt.key() ) );
+        names.removeAll( rpIt.key() );
     }
 
+    static const char* s_scoreVarName = "_n_f_t_m_s_";
+
+    Soprano::BindingSet set;
+    int score = 0;
+    Q_FOREACH( const QString& var, names ) {
+        if ( var == QLatin1String( s_scoreVarName ) )
+            score = it[var].literal().toInt();
+        else
+            set.insert( var, it[var] );
+    }
+
+    result.setAdditionalBindings( set );
+    result.setScore( ( double )score );
+
     // score will be set above
     return result;
 }
diff --git a/nepomuk/services/queryservice/searchthread.h b/nepomuk/services/queryservice/searchthread.h
index 003c932..80db55a 100644
--- a/nepomuk/services/queryservice/searchthread.h
+++ b/nepomuk/services/queryservice/searchthread.h
@@ -59,7 +59,7 @@ namespace Nepomuk {
             void run();
 
         private:
-            void sparqlQuery( const QString& query, double baseScore );
+            void sparqlQuery( const QString& query );
             Nepomuk::Query::Result extractResult( const Soprano::QueryResultIterator& it ) const;
 
             QString m_sparqlQuery;
diff --git a/nepomuk/services/removablestorage/CMakeLists.txt b/nepomuk/services/removablestorage/CMakeLists.txt
index 2a646f2..46246f1 100644
--- a/nepomuk/services/removablestorage/CMakeLists.txt
+++ b/nepomuk/services/removablestorage/CMakeLists.txt
@@ -16,6 +16,7 @@ soprano_add_ontology(SRCS ${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nie/nfo.trig "NFO"
 soprano_add_ontology(SRCS ${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nie/nie.trig "NIE" "Nepomuk::Vocabulary" "trig")
 
 qt4_add_dbus_interface(SRCS ../../interfaces/org.kde.nepomuk.Strigi.xml strigiserviceinterface)
+qt4_add_dbus_interface(SRCS ../../interfaces/org.kde.nepomuk.FileWatch.xml filewatchserviceinterface)
 
 kde4_add_plugin(nepomukremovablestorageservice ${SRCS})
 
diff --git a/nepomuk/services/removablestorage/nepomukremovablestorageservice.desktop b/nepomuk/services/removablestorage/nepomukremovablestorageservice.desktop
index 0e7447b..1c1d253 100644
--- a/nepomuk/services/removablestorage/nepomukremovablestorageservice.desktop
+++ b/nepomuk/services/removablestorage/nepomukremovablestorageservice.desktop
@@ -5,6 +5,7 @@ X-KDE-Library=nepomukremovablestorageservice
 X-KDE-Nepomuk-autostart=true
 X-KDE-Nepomuk-start-on-demand=false
 Name=Nepomuk Removable Storage Service
+Name[ar]=خدمة وحدات التخزين القابلة للإزالة لنبومك
 Name[ca]=Servei d'emmagatzematge extraïble del Nepomuk
 Name[ca@valencia]=Servei d'emmagatzematge extraïble del Nepomuk
 Name[csb]=Ùsłëznota Nepomuka dlô przenosnych mediów
@@ -20,8 +21,9 @@ Name[fr]=Service de stockage amovible de Nepomuk
 Name[fy]=Nepomuk opslach tsjinst
 Name[ga]=Seirbhís Stórála Inbhainte Nepomuk
 Name[he]=שירות התקני אחסון נשלפים של Nepomuk
+Name[hi]=नेपोमक हटानेयोग्य भंडार सेवा
 Name[hr]=Nepomukova usluga za uklonjivo skladište
-Name[hu]=Nepomuk eltávolítható tároló szolgáltatás
+Name[ia]=Servicio de Nepomuk de Storage Removibile
 Name[id]=Layanan Penyimpanan Dapat Dilepas Nepomuk
 Name[is]=Nepomuk miðlari fyrir aftengjanlegar gagnageymslur
 Name[it]=Servizio per supporti rimovibili di Nepomuk
@@ -30,7 +32,7 @@ Name[kk]=Ауыстырмалы Nepomuk құрылғыда сақтау қызм
 Name[km]=សេវា​ផ្ទុក​ចល័រ​របស់ Nepomuk
 Name[kn]=ನೆಪೋಮುಕ್ ತೆಗೆದು ಹಾಕಬಹುದಾದ ಶೇಖರಣಾ ಸೇವೆ
 Name[ko]=Nepomuk 이동식 저장소 서비스
-Name[lt]=Nepomuk atjungiamų rinkmenų paslauga
+Name[lt]=Nepomuk atjungiamų laikmenų paslauga
 Name[lv]=Nepomuk noņemamo glabāšanas ierīču serviss
 Name[mk]=Сервис на Непомук за подвижни медиуми
 Name[ml]=നെപ്പോമുക്ക്  സൂക്ഷിപ്പു് സേവനം
@@ -50,14 +52,15 @@ Name[sr@ijekavian]=Непомуков сервис уклоњивих склад
 Name[sr@ijekavianlatin]=Nepomukov servis uklonjivih skladišta
 Name[sr@latin]=Nepomukov servis uklonjivih skladišta
 Name[sv]=Nepomuk-tjänst för flyttbara medier
-Name[tg]=Основная служба хранения данных Nepomuk
+Name[tg]=Хидмати захирагоҳи Nepomuk
 Name[th]=บริการเก็บข้อมูล Nepomuk บนสื่อถอด/เสียบได้
 Name[tr]=Nepomuk Çıkarılabilir Depolama Servisi
 Name[uk]=Служба зберігання на портативних пристроях Nepomuk
 Name[x-test]=xxNepomuk Removable Storage Servicexx
-Name[zh_CN]=Nepomuk 可移动存储服务
+Name[zh_CN]=Nepomuk 移动存储服务
 Name[zh_TW]=Nepomuk 可移除儲存服務
 Comment=The Nepomuk removable storage service, providing access to Nepomuk metadata on removable storage devices.
+Comment[ar]=تقدم خدمة وحدات التخزين القابلة للإزالة وصول إلى بيانات نبومك على أجهزة التخزين القابلة للإزالة.
 Comment[ca]=El servei d'emmagatzematge extraïble del Nepomuk, proporciona accés a les metadades del Nepomuk en dispositius d'emmagatzematge extraïbles.
 Comment[ca@valencia]=El servei d'emmagatzematge extraïble del Nepomuk, proporciona accés a les metadades del Nepomuk en dispositius d'emmagatzematge extraïbles.
 Comment[csb]=Ùsłëznota Nepomuka dlô przenoslnych mediów dôwô przëstãp do pòdôwków meta Nepomùka na wëmienialnych mediach.
@@ -69,17 +72,17 @@ Comment[es]=El servicio de almacenamiento extraíble de Nepomuk, que proporciona
 Comment[et]=Nepomuki eemaldatava salvesti teenus, mis võimaldab kasutada Nepomuki metaandmeid eemaldataval salvestusseadmel.
 Comment[eu]=Nepomuken biltegiratzeko aldagarrien zerbitzua, Nepomuken metadatuei sarbidea ematen die biltegiratzeko gailu aldagarrietan.
 Comment[fi]=Nepomuk-irrotettavien tallennuslaitteiden palvelu tarjoaa pääsyn Nepomuk-metadataan irrotettavilla tallennuslaitteilla.
-Comment[fr]=Le service de stockage amovible de Nepomuk, fournissant les méta-données de Mepomuk sur les périphériques de stockage amovibles.
+Comment[fr]=Le service de stockage amovible de Nepomuk, fournissant les méta-données de Nepomuk sur les périphériques de stockage amovibles.
 Comment[fy]=De Nepomuk útnimber opslach tsjinst, ferskaft troch de Nepomuk metadata op útnimber opslach apparaten.
-Comment[hr]=Nepomukova usluga uklonjivih uređaja za pohranu pruža pristup Nepomukovim metapodacima na uklonjivim uređajima za pohranu.
-Comment[hu]=A Nepomuk cserélhető tároló szolgáltatás, hozzáférést biztosít a Nepumuk metaadatához a cserélhető tároló eszközökön.
+Comment[hr]=Nepomukova usluga uklonjivih uređaja za pohranu omogućuje pristup Nepomukovim metapodacima na uklonjivim uređajima za pohranu.
+Comment[ia]=Le servicio de storage removibile de Nepomuk forni accesso a metadata de Nepomuk su dispositivos de storage removibile.
 Comment[id]=Layanan penyimpanan dapat dilepas Nepomuk, memberikan akses ke metadata Nepomuk di divais penyimpanan dapat dilepas.
 Comment[is]=Nepomuk miðlari fyrir aftengjanlegar gagnageymslur, gerir kleift að nálgast Nepomuk lýsigögn á aftengjanlegum gagnageymslum.
 Comment[it]=Il servizio per supporti rimovibili di Nepomuk, che dà accesso ai dati aggiuntivi di Nepomuk sui supporti rimovibili.
 Comment[ja]=リムーバブルストレージデバイス上の Nepomuk メタデータへのアクセスを提供する Nepomuk サービス
 Comment[kk]=Ауыстырмалы Nepomuk құрылғыда метадеректеріне қатынауды қамтамасыз етіп сақтау қызметі.
 Comment[km]=សេវា​​ឧបករណ៍​ផ្ទុក​ចល័ត​របស់ Nepomuk ដោយ​ផ្ដល់​ការ​ចូលដំណើរការ​ទៅ​កាន់​​ទិន្នន័យ​មេតា​របស់ Nepomuk នៅ​លើ​ឧបករណ៍​ផ្ទុក​ចល័ត ។
-Comment[kn]=ನೆಪೋಮುಕ್ ತೆಗೆದು ಹಾಕಬಹುದಾದ ಸೇವೆ, ಇದು ತೆಗೆದು ಹಾಕಬಹುದಾದ ಶೇಖರಣಾ ಸಾಧನದಲ್ಲಿ ನೆಪೋಮುಕ್ ಮೆಟಾ ದತ್ತಾಂಶಕ್ಕೆ ನಿಲುಕಣೆಯನ್ನು ನೀಡುತ್ತದೆ. 
+Comment[kn]=ತೆಗೆದು ಹಾಕಬಹುದಾದ ಸಾಧನದಲ್ಲಿರುವ ನೆಪೋಮುಕ್ ಮೆಟಾ ದತ್ತಾಂಶಕ್ಕೆ ನೆಪೋಮುಕ್ ತೆಗೆಧು ಹಾಕಬಹುದಾದ ಶೇಖರಣಾ ಸೇವೆ ಪ್ರವೇಶಾಧಿಕಾರ ನೀಡುತ್ತದೆ. 
 Comment[ko]=Nepomuk 이동식 저장소 서비스는 이동식 저장소에 있는 Nepomuk 메타데이터를 사용합니다.
 Comment[lt]=Nepomuk atjungiamų kaupiklių tarnba, leidžianti pasiekti Nepomuk metaduomenis atjungiamuose kaupikliuose.
 Comment[lv]=Nepomuk noņemamo ierīču serviss, nodrošina piekļuvi pie Nepomuk medatatiem failiem uz noņemamajām ierīcēm.
@@ -88,6 +91,7 @@ Comment[nb]=Nepomuk flyttbar lagringstjeneste som gir tilgang til Nepomuk metada
 Comment[nds]=De Nepomuk-Deenst för tuuschbor Loopwarken; stellt Togriep op Nepomuk-Metadaten op tuuschbor Spiekerreedschappen praat.
 Comment[nl]=De Nepomuk verwijderbare opslagservice, levert toegang tot Nepomuk metagegevens over verwijderbare opslagapparaten.
 Comment[nn]=Nepomuk-tenesta for lagringsmedium gjev tilgang til Nepomuk-metadata på flyttbare einingar.
+Comment[pa]=ਨਿਪੋਮੁਕ ਹਟਾਉਣਯੋਗ ਸਟੋਰੇਜ਼ ਸਰਵਿਸ, ਜੋ ਕਿ ਨਿਪੋਮੁਕ ਮੇਟਾਡਾਟਾ ਲਈ ਹਟਾਉਣਯੋਗ ਸਟੋਰੇਜ਼ ਜੰਤਰ ਉੱਤ ਅਸੈੱਸ ਦਿੰਦੀ ਹੈ।
 Comment[pl]=Usługa mediów wymiennych Nepomuka, daje dostęp do danych Nepomuka na wymiennych nośnikach.
 Comment[pt]=O serviço de armazenamento removíveis do Nepomuk, o qual fornece o acesso aos meta-dados do Nepomuk para os dispositivos removíveis de armazenamento.
 Comment[pt_BR]=Serviço de dispositivo de armazenamento removível do Nepomuk, provendo acesso a metadados do Nepomuk nos dispositivos de armazenamento removíveis.
@@ -103,5 +107,5 @@ Comment[th]=บริการเก็บข้อมูล Nepomuk บนส
 Comment[tr]=Nepomuk çıkarılabilir depolama servisi, çıkarılabilir depolama aygıtlarındaki Nepomuk meta verisine erişmeyi sağlar.
 Comment[uk]=Служба зберігання на портативних носіях Nepomuk надає вам доступ до метаданих Nepomuk, що зберігаються на портативних носіях.
 Comment[x-test]=xxThe Nepomuk removable storage service, providing access to Nepomuk metadata on removable storage devices.xx
-Comment[zh_CN]=Nepomuk 可移动存储服务,提供了对可移动存储设备上的 Nepomuk 元数据访问功能。
+Comment[zh_CN]=Nepomuk 移动存储服务,提供了对移动存储设备上的 Nepomuk 元数据访问功能。
 Comment[zh_TW]=Nepomuk 可移除儲存服務,提供存取可移除裝置的 Nepomuk 描述資料。
diff --git a/nepomuk/services/removablestorage/removablestorageservice.cpp b/nepomuk/services/removablestorage/removablestorageservice.cpp
index d182ae3..827af55 100644
--- a/nepomuk/services/removablestorage/removablestorageservice.cpp
+++ b/nepomuk/services/removablestorage/removablestorageservice.cpp
@@ -20,6 +20,7 @@
 #include "nfo.h"
 #include "nie.h"
 #include "strigiserviceinterface.h"
+#include "filewatchserviceinterface.h"
 
 #include <QtDBus/QDBusConnection>
 #include <QtCore/QUuid>
@@ -172,6 +173,26 @@ QString Nepomuk::RemovableStorageService::resourceUriFromLocalFileUrl( const QSt
 }
 
 
+QStringList Nepomuk::RemovableStorageService::currentlyMountedAndIndexed()
+{
+    if( KConfig( "nepomukstrigirc" ).group( "General" ).readEntry( "index newly mounted", false ) ) {
+        QStringList paths;
+        for ( QHash<QString, Entry>::ConstIterator it = m_metadataCache.constBegin();
+              it != m_metadataCache.constEnd(); ++it ) {
+            const Entry& entry = it.value();
+            const Solid::StorageAccess* storage = entry.m_device.as<Solid::StorageAccess>();
+            if ( storage && storage->isAccessible() ) {
+                paths << storage->filePath();
+            }
+        }
+        return paths;
+    }
+    else {
+        return QStringList();
+    }
+}
+
+
 void Nepomuk::RemovableStorageService::initCacheEntries()
 {
     QList<Solid::Device> devices
@@ -248,14 +269,25 @@ void Nepomuk::RemovableStorageService::slotAccessibilityChanged( bool accessible
         //
         entry.m_lastMountPath = entry.m_device.as<Solid::StorageAccess>()->filePath();
 
-        //
-        // tell Strigi to update the newly mounted device
-        //
-        if( KConfig( "nepomukstrigirc" ).group( "General" ).readEntry( "index newly mounted", false ) ) {
-            org::kde::nepomuk::Strigi interface( "org.kde.nepomuk.services.nepomukstrigiservice",
-                                                 "/nepomukstrigiservice",
-                                                 QDBusConnection::sessionBus() );
-            interface.indexFolder( entry.m_lastMountPath, false );
+        if ( entry.hasLastMountPath() ) {
+            //
+            // tell the filewatch service that it should monitor the new medium
+            //
+            org::kde::nepomuk::FileWatch( "org.kde.nepomuk.services.nepomukfilewatch",
+                                          "/nepomukfilewatch",
+                                          QDBusConnection::sessionBus() )
+                .watchFolder( entry.m_lastMountPath );
+
+
+            //
+            // tell Strigi to update the newly mounted device
+            //
+            if( KConfig( "nepomukstrigirc" ).group( "General" ).readEntry( "index newly mounted", false ) ) {
+                org::kde::nepomuk::Strigi( "org.kde.nepomuk.services.nepomukstrigiservice",
+                                           "/nepomukstrigiservice",
+                                           QDBusConnection::sessionBus() )
+                    .indexFolder( entry.m_lastMountPath, false );
+            }
         }
 
         //
@@ -284,7 +316,7 @@ void Nepomuk::RemovableStorageService::slotAccessibilityChanged( bool accessible
             }
         }
     }
-    else {
+    else if ( entry.hasLastMountPath() ) {
         //
         // The first thing we need to do is to inform nepomuk:/ kio slave instances that something has changed
         // so any caches will be cleared. Otherwise KDirModel and friends might try to access the old media URLs
@@ -367,6 +399,13 @@ QString Nepomuk::RemovableStorageService::Entry::constructLocalPath( const KUrl&
     return path;
 }
 
+
+bool Nepomuk::RemovableStorageService::Entry::hasLastMountPath() const
+{
+    return( !m_lastMountPath.isEmpty() &&
+            m_lastMountPath != QLatin1String( "/" ) );
+}
+
 NEPOMUK_EXPORT_SERVICE( Nepomuk::RemovableStorageService, "nepomukremovablestorageservice")
 
 #include "removablestorageservice.moc"
diff --git a/nepomuk/services/removablestorage/removablestorageservice.h b/nepomuk/services/removablestorage/removablestorageservice.h
index 11936e4..687acce 100644
--- a/nepomuk/services/removablestorage/removablestorageservice.h
+++ b/nepomuk/services/removablestorage/removablestorageservice.h
@@ -65,6 +65,8 @@ namespace Nepomuk {
          */
         Q_SCRIPTABLE QString resourceUriFromLocalFileUrl( const QString& url );
 
+        Q_SCRIPTABLE QStringList currentlyMountedAndIndexed();
+
     private Q_SLOTS:
         void slotSolidDeviceAdded( const QString& udi );
         void slotSolidDeviceRemoved( const QString& udi );
@@ -89,6 +91,7 @@ namespace Nepomuk {
 
             KUrl constructRelativeUrl( const QString& path ) const;
             QString constructLocalPath( const KUrl& filexUrl ) const;
+            bool hasLastMountPath() const;
 
             Solid::Device m_device;
             QString m_lastMountPath;
diff --git a/nepomuk/services/storage/nepomukcore.cpp b/nepomuk/services/storage/nepomukcore.cpp
index b28ed01..8ce541d 100644
--- a/nepomuk/services/storage/nepomukcore.cpp
+++ b/nepomuk/services/storage/nepomukcore.cpp
@@ -28,7 +28,7 @@
 
 #include <Soprano/BackendSetting>
 
-static const char* s_repositoryName = "main";
+static const char s_repositoryName[] = "main";
 
 Nepomuk::Core::Core( QObject* parent )
     : Soprano::Server::ServerCore( parent ),
diff --git a/nepomuk/services/storage/nepomukstorage.desktop b/nepomuk/services/storage/nepomukstorage.desktop
index 89fadda..35f5f3d 100644
--- a/nepomuk/services/storage/nepomukstorage.desktop
+++ b/nepomuk/services/storage/nepomukstorage.desktop
@@ -5,7 +5,7 @@ X-KDE-Library=nepomukstorage
 X-KDE-Nepomuk-autostart=true
 X-KDE-Nepomuk-start-on-demand=true
 Name=Nepomuk Data Storage
-Name[ar]=مخزن بيانات  نبومك
+Name[ar]=مخزن بيانات نبومك
 Name[be@latin]=Schovišča dla źviestak „Nepomuk”
 Name[bg]=Хранилище Nepomuk
 Name[bn_IN]=Nepomuk ডাটা সংরক্ষণব্যবস্থা
@@ -33,6 +33,7 @@ Name[hne]=नेपोमक डाटा भंडार
 Name[hr]=Nepomuk Pohrana Podataka
 Name[hsb]=Nepomuk składowanje datow
 Name[hu]=Nepomuk adattároló
+Name[ia]=Nepomuk Storage de Datos
 Name[id]=Penyimpanan Data Nepomuk
 Name[is]=Nepomuk gagnageymsla
 Name[it]=Memorizzazione di dati di Nepomuk
@@ -105,6 +106,7 @@ Comment[hne]=कोर नेपोमक डाटा भंडार सेव
 Comment[hr]=Nepomukova sržna usluga pohrane podataka
 Comment[hsb]=Centralna Nepomukowa słužba za składowanje datow
 Comment[hu]=Nepomuk adattároló alapszolgáltatás
+Comment[ia]=Le servicio de storage de datos  del Corde de Nepomuk
 Comment[id]=Layanan penyimpanan data Inti Nepomuk
 Comment[is]=Kjarni Nepomuk gagnageymslumiðlunar
 Comment[it]=Il servizio principale di memorizzazione dati di Nepomuk
@@ -131,7 +133,7 @@ Comment[pt_BR]=O serviço principal de armazenamento de dados do Nepomuk
 Comment[ro]=Serviciul esențial Nepomuk pentru stocarea datelor
 Comment[ru]=Служба хранилища основных данных Nepomuk
 Comment[si]=මූලික Nepomuදත්ත ගබඩා සේවාව
-Comment[sk]=Hlavná služba Nepomuku pre ukladanie dát 
+Comment[sk]=Hlavná služba Nepomuku pre ukladanie dát
 Comment[sl]=Osnovna storitev hrambe podatkov za Nepomuk
 Comment[sr]=Језгарни сервис Непомука за складиштење података
 Comment[sr@ijekavian]=Језгарни сервис Непомука за складиштење података
@@ -140,7 +142,7 @@ Comment[sr@latin]=Jezgarni servis Nepomuka za skladištenje podataka
 Comment[sv]=Nepomuk-datalagringstjänstens kärna
 Comment[ta]=The Core Nepomuk data storage service
 Comment[te]=ఆధార Nepomuk డాటా నిల్వ సేవ
-Comment[tg]=Основная служба хранения данных Nepomuk
+Comment[tg]=Хидмати асосии захирагоҳи Nepomuk
 Comment[th]=บริการจัดเก็บข้อมูลระดับแกนของ Nepomik
 Comment[tr]=Nepomuk Ana veri depolama servisi
 Comment[uk]=Ядро служби збереження даних Nepomuk
diff --git a/nepomuk/services/storage/nepomukstorage.notifyrc b/nepomuk/services/storage/nepomukstorage.notifyrc
index 310871f..cb90466 100644
--- a/nepomuk/services/storage/nepomukstorage.notifyrc
+++ b/nepomuk/services/storage/nepomukstorage.notifyrc
@@ -1,152 +1,118 @@
 [Global]
 IconName=nepomuk
-Name=Nepomuk Data Storage
-Name[ar]=مخزن بيانات  نبومك
-Name[be@latin]=Schovišča dla źviestak „Nepomuk”
-Name[bg]=Хранилище Nepomuk
-Name[bn_IN]=Nepomuk ডাটা সংরক্ষণব্যবস্থা
-Name[ca]=Emmagatzematge de dades del Nepomuk
-Name[ca@valencia]=Emmagatzematge de dades del Nepomuk
-Name[cs]=Datové úložiště Nepomuku
-Name[csb]=Trzëmanié pòdôwków Nepomuka
-Name[da]=Nepomuk datalagring
-Name[de]=Nepomuk-Datendienst
-Name[el]=Αποθήκη δεδομένων Nepomuk
-Name[en_GB]=Nepomuk Data Storage
-Name[eo]=Nepomuk enmemorigo de datumoj
-Name[es]=Almacenamiento de datos Nepomuk
-Name[et]=Nepomuki andmesalvesti
-Name[eu]=Nepomuken datu biltegiratzea
-Name[fi]=Nepomuk-tietovarasto
-Name[fr]=Stockage de données de Nepomuk
-Name[fy]=Nepomuk Gegevens opslach
-Name[ga]=Stóráil Sonraí Nepomuk
-Name[gl]=Almacén de datos de Nepomuk
-Name[gu]=નેપોમુક માહિતી સંગ્રહ
-Name[he]=שירותי אחסון של Nepomuk
-Name[hi]=नेपोमक डाटा भंडार
-Name[hne]=नेपोमक डाटा भंडार
-Name[hr]=Nepomuk Pohrana Podataka
-Name[hsb]=Nepomuk składowanje datow
-Name[hu]=Nepomuk adattároló
-Name[id]=Penyimpanan Data Nepomuk
-Name[is]=Nepomuk gagnageymsla
-Name[it]=Memorizzazione di dati di Nepomuk
-Name[ja]=Nepomuk データストレージ
-Name[kk]=Nepomuk деректерді сақтау
-Name[km]=ឧបករណ៍​ផ្ទុក​ទិន្នន័យ Nepomuk
-Name[kn]=ನೆಪೋಮುಕ್ ದತ್ತ ಸಂಗ್ರಹ
-Name[ko]=Nepomuk 데이터 저장소
-Name[ku]=Nepomuk Hîser Kirina Dane yan
-Name[lt]=Nepomuk duomenų saugojimas
-Name[lv]=Nepomuk datu glabātuve
-Name[mai]=Nepomuk डाटा भंडारण
-Name[mk]=Складирање на податоци во Непомук
-Name[ml]=നെപ്പോമുക്ക് ഡേറ്റാ സംഭരണം
-Name[mr]=Nepomuk माहिती संचयन
-Name[nb]=Nepomuk datalagring
-Name[nds]=Nepomuk-Datenaflaag
-Name[nl]=Nepomuk-gegevensopslag
-Name[nn]=Nepomuk datalagring
-Name[or]=Nepomuk ତଥ୍ୟ ଭଣ୍ଡାର
-Name[pa]=ਨਿਪੋਮੁਕ ਡਾਟਾ ਸਟੋਰੇਜ਼
-Name[pl]=Przechowywanie danych Nepomuka
-Name[pt]=Armazenamento de Dados do Nepomuk
-Name[pt_BR]=Armazenamento de Dados do Nepomuk
-Name[ro]=Stocare date Nepomuk
-Name[ru]=Хранилище Nepomuk
-Name[si]=Nepomuk දත්ත ගබඩාව
-Name[sk]=Dátové úložisko Nepomuku
-Name[sl]=Hramba podatkov za Nepomuk
-Name[sr]=Непомуково складиште
-Name[sr@ijekavian]=Непомуково складиште
-Name[sr@ijekavianlatin]=Nepomukovo skladište
-Name[sr@latin]=Nepomukovo skladište
-Name[sv]=Nepomuk-datalagring
-Name[ta]=Nepomuk Data Storage
-Name[te]=Nepomuk డాటా నిల్వ
-Name[tg]=Захирагоҳи Nepomuk
-Name[th]=ที่จัดเก็บข้อมูลของ Nepomuk
-Name[tr]=Nepomuk Veri Depolama
-Name[uk]=Збереження даних Nepomuk
-Name[wa]=Wårdaedje di dnêyes Nepomuk
-Name[x-test]=xxNepomuk Data Storagexx
-Name[zh_CN]=Nepomuk 数据存储
-Name[zh_TW]=Nepomuk 資料儲存
-Comment=The Nepomuk Storage Service
-Comment[ar]=خدمة التخزين لنبومك
-Comment[be@latin]=Słužba zachoŭvańnia źviestak „Nepomuk”
-Comment[bg]=Услуга за съхранение Nepomuk
-Comment[bn_IN]=Nepomuk Storage পরিসেবা
-Comment[ca]=Servei d'emmagatzematge del Nepomuk
-Comment[ca@valencia]=Servei d'emmagatzematge del Nepomuk
-Comment[cs]=Služba úložiště Nepomuku
-Comment[csb]=Ùsłëznota Storage Nepomuka
-Comment[da]=Nepomuk lagringstjeneste
-Comment[de]=Nepomuk-Ablagedienst
-Comment[el]=Υπηρεσία αποθήκης του Nepomuk
-Comment[en_GB]=The Nepomuk Storage Service
-Comment[eo]=Servo de Nepomuk-enmemorigo
-Comment[es]=Servicio Nepomuk de almacenamiento
-Comment[et]=Nepomuki salvestiteenus
-Comment[eu]=Nepomuken biltegiratzeko zerbitzua
-Comment[fi]=Nepomuk-tallennuspalvelu
-Comment[fr]=Service de stockage de Nepomuk
-Comment[fy]=De Nepomuk opslachtsjinst
-Comment[ga]=Seirbhís Stórála Nepomuk
-Comment[gl]=O servizo almacenaxe de Nepomuk
-Comment[gu]=નેપોમુક સંગ્રહ સેવા
-Comment[hi]=नेपोमक भंडार सेवा
-Comment[hne]=नेपोमक भंडार सेवा
-Comment[hr]=Nepomuk Usluga Pohrane
-Comment[hsb]=Nepomuk Storage Service
-Comment[hu]=Nepomuk-tároló
-Comment[id]=Layanan Penyimpanan Nepomuk
-Comment[is]=Nepomuk gagnageymslumiðlari
-Comment[it]=Il servizio di memorizzazione di Nepomuk
-Comment[ja]=Nepomuk ストレージサービス
-Comment[kk]=Nepomuk сақтау қызметі
-Comment[km]=សេវា​ផ្ទុក​របស់ Nepomuk
-Comment[kn]=ನೆಪೋಮುಕ್ ಶೇಖರಣೆ ಹಾಗು ಸೇವೆ
-Comment[ko]=Nepomuk 저장소 서비스
-Comment[ku]=Nepomuk Servîsa Hîser Kirinê 
-Comment[lt]=Nepomuk saugojimo tarnyba
-Comment[lv]=Nepomuk glabāšanas serviss
-Comment[mai]=Nepomuk भंडारण सेवा
-Comment[mk]=Сервис за складирање на Непомук
-Comment[ml]=നെപ്പോമുക്ക് സൂക്ഷിപ്പു് സേവനം
-Comment[mr]=Nepomuk संचयन सेवा
-Comment[nb]=Nepomuk lagringstjeneste
-Comment[nds]=De Nepomuk-Wohrdeenst
-Comment[nl]=De Nepomuk-opslagdienst
-Comment[nn]=Lagringstenesta i Nepomuk
-Comment[or]=Nepomuk ଭଣ୍ଡାର ସର୍ଭିସ
-Comment[pa]=ਨਿਪੋਮੁਕ ਸਟੋਰੇਜ਼ ਸਰਵਿਸ
-Comment[pl]=Usługa przechowywania danych Nepomuka
-Comment[pt]=O Serviço de Armazenamento do Nepomuk
-Comment[pt_BR]=O serviço de armazenamento do Nepomuk
-Comment[ro]=Serviciul de stocare Nepomuk
-Comment[ru]=Служба хранилища Nepomuk
-Comment[si]=Nepomuk ගබඩා සේවාව
-Comment[sk]=Služba úložiska Nepomuku
-Comment[sl]=Nepomukova shranjevalna storitev
-Comment[sr]=Непомуков сервис складиштења
-Comment[sr@ijekavian]=Непомуков сервис складиштења
-Comment[sr@ijekavianlatin]=Nepomukov servis skladištenja
-Comment[sr@latin]=Nepomukov servis skladištenja
-Comment[sv]=Nepomuk-lagringstjänst
-Comment[ta]=The Nepomuk Storage Service
-Comment[tg]=Основная служба хранения данных Nepomuk
-Comment[th]=บริการเก็บข้อมูล Nepomuk
-Comment[tr]=Nepomuk Depolama Servisi
-Comment[uk]=Служба зберігання Nepomuk
-Comment[wa]=Li siervice di wårdaedje Nepomuk
-Comment[x-test]=xxThe Nepomuk Storage Servicexx
-Comment[zh_CN]=Nepomuk 存储服务
-Comment[zh_TW]=Nepomuk 儲存服務
+Name=Semantic Data Storage
+Name[ar]=مخزن بيانات دلالي
+Name[bg]=Хранилище за семантични данни
+Name[ca]=Emmagatzematge de dades semàntiques
+Name[ca@valencia]=Emmagatzematge de dades semàntiques
+Name[cs]=Úložistě sémantických dat
+Name[da]=Lagring af semantiske data
+Name[de]=Semantische Datenspeicherung
+Name[el]=Αποθήκη σημασιολογικών δεδομένων
+Name[en_GB]=Semantic Data Storage
+Name[es]=Almacenamiento de datos semánticos
+Name[et]=Semantiline andmesalvesti
+Name[eu]=Datu semantikoen biltegiratzea
+Name[fi]=Semanttinen tietovarasto
+Name[fr]=Stockage de données sémantique
+Name[fy]=Semantic Gegevens opslach
+Name[ga]=Stóráil Sonraí Séimeantacha
+Name[hi]=सेमांटिक डाटा भंडार
+Name[hr]=Semantička pohrana podataka
+Name[hu]=Szemantikus adattároló
+Name[ia]=Storage de Datos Semantic
+Name[id]=Penyimpanan Data Semantik
+Name[is]=Merkingarleg (semantic) gagnageymsla
+Name[it]=Memorizzazione di dati semantici
+Name[ja]=セマンティックデータストレージ
+Name[kk]=Семантикалық деректерді сақтау
+Name[km]=ការ​ផ្ទុក​ទិន្នន័យ​ស៊ីមែនទិក
+Name[kn]=ಸೆಮಾಂಟಿಕ್ ದತ್ತ ಸಂಗ್ರಹ
+Name[ko]=시맨틱 데이터 저장소
+Name[lt]=Semantinių duomenų saugykla
+Name[lv]=Semantisko datu glabātuve
+Name[ml]=സെമാന്റിക്ക് ഡേറ്റാ സംഭരണം
+Name[nb]=Semantisk datalagring
+Name[nds]=Semantsch Datenaflaag
+Name[nl]=Semantische gegevensopslag
+Name[nn]=Semantisk datalagring
+Name[pa]=ਸਿਮਾਂਟਿਕ ਡਾਟਾ ਸਟੋਰੇਜ਼
+Name[pl]=Semantyczne przechowywanie danych
+Name[pt]=Armazenamento de Dados Semânticos
+Name[pt_BR]=Armazenamento de dados semântico
+Name[ru]=Хранилище семантических данных
+Name[sk]=Úložisko sémantických dát
+Name[sl]=Hramba semantičnih podatkov
+Name[sr]=Семантичко складиштење података
+Name[sr@ijekavian]=Семантичко складиштење података
+Name[sr@ijekavianlatin]=Semantičko skladištenje podataka
+Name[sr@latin]=Semantičko skladištenje podataka
+Name[sv]=Semantisk datalagring
+Name[tg]=Захирагоҳи маъноии маълумот
+Name[th]=ที่จัดเก็บข้อมูลของระบบค้นหา
+Name[tr]=Anlamsal Veri Depolama
+Name[uk]=Сховище семантичних даних
+Name[x-test]=xxSemantic Data Storagexx
+Name[zh_CN]=语义学数据存储
+Name[zh_TW]=語意資料儲存
+Comment=Semantic Desktop
+Comment[ar]=سطح المكتب دلالي
+Comment[bg]=Семантичен работен плот
+Comment[ca]=Escriptori semàntic
+Comment[ca@valencia]=Escriptori semàntic
+Comment[cs]=Sémantický desktop
+Comment[da]=Semantisk skrivebordsmiljø
+Comment[de]=Semantischer Desktop
+Comment[el]=Σημασιολογική επιφάνεια εργασίας
+Comment[en_GB]=Semantic Desktop
+Comment[es]=Escritorio semántico
+Comment[et]=Semantiline töölaud
+Comment[eu]=Mahaigain semantikoa
+Comment[fi]=Semanttinen työpöytä
+Comment[fr]=Bureau sémantique
+Comment[fy]=Semantic buroblêd
+Comment[ga]=Deasc Shéimeantach
+Comment[hi]=सेमांटिक डेस्कटॉप
+Comment[hr]=Semantička radna površina
+Comment[ia]=Scriptorio Semantic
+Comment[id]=Desktop Semantik
+Comment[is]=Merkingarlegt (semantic) skjáborð
+Comment[it]=Desktop semantico
+Comment[ja]=セマンティックデスクトップ
+Comment[kk]=Сементикалық үстелі
+Comment[km]=ផ្ទៃតុ​ស៊ីមែនទិក
+Comment[kn]=ಸೆಮಾಂಟಿಕ್ ಗಣಕತೆರೆ
+Comment[ko]=시맨틱 데스크톱
+Comment[lt]=Semantinis darbastalis
+Comment[lv]=Semantiskā darbvirsma
+Comment[ml]=സെമാന്റിക്ക് പണിയിടം
+Comment[nb]=Semantisk skrivebord
+Comment[nds]=Schriefdischbeslöteln
+Comment[nl]=Semantisch bureaublad
+Comment[nn]=Semantisk skrivebord
+Comment[pa]=ਸਿਮਾਂਟਿਕ ਡੈਸਕਟਾਪ
+Comment[pl]=Pulpit semantyczny
+Comment[pt]=Ambiente de Trabalho Semântico
+Comment[pt_BR]=Área de trabalho semântica
+Comment[sk]=Sémantický desktop
+Comment[sl]=Semantično namizje
+Comment[sr]=Семантичка површ
+Comment[sr@ijekavian]=Семантичка површ
+Comment[sr@ijekavianlatin]=Semantička površ
+Comment[sr@latin]=Semantička površ
+Comment[sv]=Semantiskt skrivbord
+Comment[tg]=Мизи кории маъноӣ
+Comment[th]=ระบบค้นหาผ่านพื้นที่ทำงาน
+Comment[tr]=Anlamsal Masaüstü
+Comment[uk]=Семантична стільниця
+Comment[x-test]=xxSemantic Desktopxx
+Comment[zh_CN]=语义学桌面
+Comment[zh_TW]=語意桌面
 
 [Event/failedToStart]
 Name=Failed to start Nepomuk
+Name[ar]=فشل في بدء نبومك
+Name[bg]=Грешка при зареждане на Nepomuk
 Name[ca]=Ha fallat en iniciar el Nepomuk
 Name[ca@valencia]=Ha fallat en iniciar el Nepomuk
 Name[cs]=Nepovedlo se spustit Nepomuk
@@ -165,8 +131,9 @@ Name[fy]=It slagge net om Nepomuk útein te setten
 Name[ga]=Níorbh fhéidir Nepomuk a thosú
 Name[gu]=નેપોમુક શરૂ કરવામાં નિષ્ફળ
 Name[he]=הפעלת Nepomuk נכשלה
+Name[hi]=Nepomuk चालू नही कर पाए
 Name[hr]=Neuspjelo pokretanje Nepomuka.
-Name[hu]=Nem sikerült elindítani a Nepomuk-ot
+Name[ia]=Il falleva a initiar Nepomuk
 Name[id]=Gagal menjalankan Nepomuk
 Name[is]=Tókst ekki að ræsa Nepomuk
 Name[it]=Avvio di Nepomuk non riuscito
@@ -196,6 +163,7 @@ Name[sr@ijekavian]=Неуспјело покретање Непомука
 Name[sr@ijekavianlatin]=Neuspjelo pokretanje Nepomuka
 Name[sr@latin]=Neuspelo pokretanje Nepomuka
 Name[sv]=Misslyckades starta Nepomuk
+Name[tg]=Оғози Nepomuk қатъ шуд
 Name[th]=ล้มเหลวในการเริ่มบริการ Nepomuk
 Name[tr]=Nepomuk başlatılamadı
 Name[uk]=Не вдалося запустити Nepomuk
@@ -203,6 +171,7 @@ Name[x-test]=xxFailed to start Nepomukxx
 Name[zh_CN]=启动 Nepomuk 失败
 Name[zh_TW]=無法啟動 Nepomuk
 Comment=The Nepomuk Semantic Desktop system could not be started
+Comment[ar]=لم يستطع نظام سطح مكتب نبومك الدلالي البدء
 Comment[ca]=El sistema de l'escriptori semàntic del Nepomuk no s'ha pogut engegar
 Comment[ca@valencia]=El sistema de l'escriptori semàntic del Nepomuk no s'ha pogut engegar
 Comment[csb]=Semanticznô systema pùltu Nepomùka nié mòże bëc zrëszonô
@@ -219,7 +188,7 @@ Comment[fy]=De Nepomuk semantic buroblêd systeem koe net úteinsetten wurde
 Comment[ga]=Níorbh fhéidir Deasc Shéimeantach Nepomuk a thosú
 Comment[he]=לא ניתן להפעיל את מערכת שולחן העבודה הסמנטית של Nepomuk 
 Comment[hr]=Sustav semantičke radne površine Nepomuk ne može biti pokrenut
-Comment[hu]=Nem sikerült elindítani a Nepomuk szemantikus asztali rendszert
+Comment[ia]=Le systema de Scriptorio Semantic de Nepomuk non poteva esser initiate
 Comment[id]=Sistem Desktop Semantik Nepomuk tak dapat dijalankan
 Comment[is]=Ekki var hægt að ræsa Merkingarlega Nemopuk (semantic) Skjáborðskerfið
 Comment[it]=Impossibile avviare il sistema del desktop semantico Nepomuk
@@ -236,6 +205,7 @@ Comment[nb]=Nepomuk semantisk skrivebord kunne ikke startes
 Comment[nds]=Dat Schriefdischbeslötel-Systeem Nepomuk lett sik nich starten
 Comment[nl]=Het Nepomuk semantische bureaubladsysteem kon niet worden gestart
 Comment[nn]=Klarte ikkje starta Neopmuk semantisk skrivebord
+Comment[pa]=ਨਿਪੋਮੁਕ ਸਮਿਨਟਿਕ ਡੈਸਕਟਾਪ ਸਿਸਟਮ ਸ਼ੁਰੂ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ
 Comment[pl]=Nie można uruchomić Pulpitu semantycznego Nepomuka
 Comment[pt]=Não foi possível iniciar o sistema do Ambiente Semântico do Nepomuk
 Comment[pt_BR]=O sistema de Área de Trabalho Semântica do Nepomuk não pode ser iniciado
@@ -285,6 +255,7 @@ Name[hne]=नेपोमक डाटा ल बदलत हे
 Name[hr]=Pretvaram Nepomukove podatke
 Name[hsb]=Konwertěruju Nepomukowe daty
 Name[hu]=Indexadatok konvertálása folyik
+Name[ia]=Il converte datos de Nepomuk
 Name[id]=Mengonversi data Nepomuk
 Name[is]=Umbreyti Nepomuk gögnum
 Name[it]=Conversione dei dati di Nepomuk
@@ -355,6 +326,7 @@ Comment[hne]=नवा भंडार बेकएन्ड मं सब्ब
 Comment[hr]=Svi Nepomukovi podaci su pretvoreni u format novog načina pohrane
 Comment[hsb]=Wšě Nepomukowe daty buchu za nowy składowanski backend konwertěrowane
 Comment[hu]=Sikerült átkonvertálni minden adatot az új tárolómodul számára
+Comment[ia]=Tote le datos de Nepomuk es convertite a un nove backend de storage
 Comment[id]=Semua data Nepomuk dikonversi ke ujung belakang penyimpanan baru
 Comment[is]=Öllum Nepomuk er umbreytt fyrir nýja geymslubakendann
 Comment[it]=Tutti i dati di Nepomuk sono convertiti ad un nuovo motore di memorizzazione
@@ -428,6 +400,7 @@ Name[hne]=नेपोमक डाटा ल बदले मं फेल ह
 Name[hr]=Pretvaranje Nepomukovih podataka nije uspjelo.
 Name[hsb]=Konwertěrowanje Nepomukowych datow zwrěšćene
 Name[hu]=Adatkonvertálási hiba történt a Nepomukban
+Name[ia]=Il falleva le conversion de datos de Nepomuk
 Name[id]=Mengonversi data Nepomuk telah gagal
 Name[is]=Umbreyting Nepomuk gagna mistókst
 Name[it]=Conversione dei dati di Nepomuk non riuscita
@@ -454,7 +427,7 @@ Name[pt_BR]=Falha ao converter dados do Nepomuk
 Name[ro]=Conversia datelor Nepomuk a eșuat
 Name[ru]=Ошибка преобразования данных
 Name[si]=Nepomuk දත්ත හැරවීම අසාර්ථකයි
-Name[sk]=Konvertovanie údajov Nepomuku zlyhalo
+Name[sk]=Konvertovanie dát Nepomuku zlyhalo
 Name[sl]=Pretvarjanje Nepomukovih podatkov ni uspelo
 Name[sr]=Пропало претварање Непомукових података
 Name[sr@ijekavian]=Пропало претварање Непомукових података
@@ -498,6 +471,7 @@ Comment[hne]=नेपोमक डाटा ल नवा बेकएंड 
 Comment[hr]=Pretvaranje Nepomukovih podataka u novi format nije uspjelo.
 Comment[hsb]=Konwertěrowanje Nepomukowych datow za nowy backend je zwrěšćiło.
 Comment[hu]=Ne sikerült átkonvertálni Nepomuk-adatokat egy új kezelőmodul számára
+Comment[ia]=Il falleva le conversion de datos de Nepomuk a un nove backend
 Comment[id]=Mengonversi data Nepomuk ke ujung belakang baru gagal
 Comment[is]=Umbreyting Nepomuk gagna fyrir nýjan bakenda mistókst
 Comment[it]=La conversione dei dati di Nepomuk ad un nuovo motore di memorizzazione non è riuscita
@@ -571,6 +545,7 @@ Name[hne]=नेपोमक डाटा बदल दे गिस
 Name[hr]=Pretvarane Nepomukovih podataka je završilo.
 Name[hsb]=Konwertěrowanje Nepomukowych datow zakónčene
 Name[hu]=Nepomuk adatkonverzió befejeződött
+Name[ia]=Facite la conversion de datos de Nepomuk 
 Name[id]=Mengonversi data Nepomuk telah selesai
 Name[is]=Umbreyting Nepomuk gagna er lokið
 Name[it]=Conversione dei dati di Nepomuk completata
@@ -641,6 +616,7 @@ Comment[hne]=नवा बेकएंड मं नेपोमक डाटा
 Comment[hr]=Nepomukovi podaci su uspješno pretvoreni u novi format.
 Comment[hsb]=Konwertěrowanje Nepomukowych datow za nowy backend wuspěšne.
 Comment[hu]=Sikerült átkonvertálni minden Nepomuk-adatot az új tárolómodulhoz 
+Comment[ia]=Il converteva con successo datos de Nepomuk a un nove backend
 Comment[id]=Sukses mengonversi data Nepomuk ke ujung belakang baru
 Comment[is]=Umbreyting Nepomuk gagna fyrir nýjan bakenda tókst
 Comment[it]=Conversione dei dati di Nepomuk ad un nuovo motore riuscita
diff --git a/nepomuk/services/storage/repository.cpp b/nepomuk/services/storage/repository.cpp
index fd4f779..3f9acc1 100644
--- a/nepomuk/services/storage/repository.cpp
+++ b/nepomuk/services/storage/repository.cpp
@@ -206,7 +206,6 @@ void Nepomuk::Repository::open()
                 kDebug() << "Starting model conversion";
 
                 convertingData = true;
-                // No need to use the index filter as it already contains the data
                 m_modelCopyJob = new ModelCopyJob( oldModel, m_model, this );
                 connect( m_modelCopyJob, SIGNAL( result( KJob* ) ), this, SLOT( copyFinished( KJob* ) ) );
                 m_modelCopyJob->start();
@@ -337,6 +336,10 @@ Soprano::BackendSettings Nepomuk::Repository::readVirtuosoSettings() const
     // Always force the start, ie. kill previously started Virtuoso instances
     settings << Soprano::BackendSetting( "forcedstart", true );
 
+    // 100 server threads is hopefully enough - at some point the problem of maximum server threads == max client
+    // needs to be addressed as well
+    settings << Soprano::BackendSetting( "thread", 100 );
+
     return settings;
 }
 
diff --git a/nepomuk/services/strigi/CMakeLists.txt b/nepomuk/services/strigi/CMakeLists.txt
index 564765c..97e7378 100644
--- a/nepomuk/services/strigi/CMakeLists.txt
+++ b/nepomuk/services/strigi/CMakeLists.txt
@@ -28,13 +28,10 @@ set(strigiservice_SRCS
   strigiservice.cpp
   strigiserviceadaptor.cpp
   indexscheduler.cpp
-  priority.cpp
   strigiserviceconfig.cpp
   eventmonitor.cpp
   systray.cpp
   statuswidget.cpp
-  filesystemwatcher.cpp
-  useractivitymonitor.cpp
   )
 
 soprano_add_ontology(strigiservice_SRCS
@@ -48,6 +45,9 @@ soprano_add_ontology(strigiservice_SRCS
   "Nepomuk::Vocabulary"
   "trig")
 
+qt4_add_dbus_interface(strigiservice_SRCS ../../interfaces/org.kde.nepomuk.RemovableStorage.xml removablestorageserviceinterface)
+qt4_add_dbus_interface(strigiservice_SRCS ../../interfaces/org.kde.nepomuk.FileWatch.xml filewatchserviceinterface)
+
 kde4_add_ui_files(strigiservice_SRCS
   statuswidget.ui)
 
@@ -59,7 +59,7 @@ target_link_libraries(nepomukstrigiservice
   ${KDE4_KDEUI_LIBS}
   ${KDE4_KIO_LIBS}
   ${KDE4_SOLID_LIBS}
-  ${KDE4_KUTILS_LIBS}
+  ${KDE4_KUTILS_LIBS}
   ${NEPOMUK_LIBRARIES}
   ${SOPRANO_LIBRARIES}
   )
diff --git a/nepomuk/services/strigi/eventmonitor.cpp b/nepomuk/services/strigi/eventmonitor.cpp
index a073bd3..bc8da0a 100644
--- a/nepomuk/services/strigi/eventmonitor.cpp
+++ b/nepomuk/services/strigi/eventmonitor.cpp
@@ -43,14 +43,9 @@ namespace {
 Nepomuk::EventMonitor::EventMonitor( IndexScheduler* scheduler, QObject* parent )
     : QObject( parent ),
       m_indexScheduler( scheduler ),
-      m_pauseState( NotPaused )
+      m_pauseState( NotPaused ),
+      m_totalIndexingSeconds( 0 )
 {
-    // FileSystemWatcher does not catch changes to files, only new and removed files
-    // thus, we also do periodic updates of the whole index every two hours
-    connect( &m_periodicUpdateTimer, SIGNAL( timeout() ),
-             m_indexScheduler, SLOT( updateAll() ) );
-    m_periodicUpdateTimer.setInterval( 2*60*60*1000 );
-
     // monitor the powermanagement to not drain the battery
     connect( Solid::PowerManagement::notifier(), SIGNAL( appShouldConserveResourcesChanged( bool ) ),
              this, SLOT( slotPowerManagementStatusChanged( bool ) ) );
@@ -63,7 +58,7 @@ Nepomuk::EventMonitor::EventMonitor( IndexScheduler* scheduler, QObject* parent
     if ( StrigiServiceConfig::self()->isInitialRun() ) {
         // TODO: add actions to this notification
 
-        m_initialIndexTime.start();
+        m_indexingStartTime = QDateTime::currentDateTime();
 
         // inform the user about the initial indexing
         sendEvent( "initialIndexingStarted",
@@ -76,9 +71,9 @@ Nepomuk::EventMonitor::EventMonitor( IndexScheduler* scheduler, QObject* parent
         connect( m_indexScheduler, SIGNAL( indexingStopped() ),
                  this, SLOT( slotIndexingStopped() ),
                  Qt::QueuedConnection );
-    }
-    else {
-        m_periodicUpdateTimer.start();
+                 
+        connect( m_indexScheduler, SIGNAL( indexingSuspended(bool) ),
+                 this, SLOT( slotIndexingSuspended(bool) ) );
     }
 
     slotPowerManagementStatusChanged( Solid::PowerManagement::appShouldConserveResources() );
@@ -94,16 +89,14 @@ void Nepomuk::EventMonitor::slotPowerManagementStatusChanged( bool conserveResou
 {
     if ( !conserveResources && m_pauseState == PausedDueToPowerManagement ) {
         kDebug() << "Resuming indexer due to power management";
-        m_pauseState = NotPaused;
-        m_indexScheduler->resume();
+        resumeIndexing();
         sendEvent( "indexingResumed", i18n("Resuming indexing of files for fast searching."), "battery-charging" );
     }
     else if ( conserveResources &&
               m_indexScheduler->isRunning() &&
               !m_indexScheduler->isSuspended() ) {
         kDebug() << "Pausing indexer due to power management";
-        m_pauseState = PausedDueToPowerManagement;
-        m_indexScheduler->suspend();
+        pauseIndexing( PausedDueToPowerManagement );
         sendEvent( "indexingSuspended", i18n("Suspending the indexing of files to preserve resources."), "battery-100" );
     }
 }
@@ -116,8 +109,7 @@ void Nepomuk::EventMonitor::slotCheckAvailableSpace()
         if ( info.available() <= StrigiServiceConfig::self()->minDiskSpace() ) {
             if ( m_indexScheduler->isRunning() &&
                 !m_indexScheduler->isSuspended() ) {
-                m_pauseState = PausedDueToAvailSpace;
-                m_indexScheduler->suspend();
+                pauseIndexing( PausedDueToAvailSpace );
                 sendEvent( "indexingSuspended",
                            i18n("Disk space is running low (%1 left). Suspending indexing of files.",
                                 KIO::convertSize( info.available() ) ),
@@ -126,8 +118,7 @@ void Nepomuk::EventMonitor::slotCheckAvailableSpace()
         }
         else if ( m_pauseState == PausedDueToAvailSpace ) {
             kDebug() << "Resuming indexer due to disk space";
-            m_pauseState = NotPaused;
-            m_indexScheduler->resume();
+            resumeIndexing();
             sendEvent( "indexingResumed", i18n("Resuming indexing of files for fast searching."), "drive-harddisk" );
         }
     }
@@ -142,15 +133,47 @@ void Nepomuk::EventMonitor::slotIndexingStopped()
 {
     // inform the user about the end of initial indexing. This will only be called once
     if ( !m_indexScheduler->isSuspended() ) {
-        kDebug() << "initial indexing took" << m_initialIndexTime.elapsed();
+        m_totalIndexingSeconds += m_indexingStartTime.secsTo( QDateTime::currentDateTime() );
+        const int elapsed = m_totalIndexingSeconds * 1000;
+        
+        kDebug() << "initial indexing took" << elapsed;
         sendEvent( "initialIndexingFinished",
-                   i18nc( "@info %1 is a duration formatted using KLocale::formatDuration",
+                   i18nc( "@info %1 is a duration formatted using KLocale::prettyFormatDuration",
                           "Initial indexing of files for fast searching finished in %1",
-                          KGlobal::locale()->formatDuration( m_initialIndexTime.elapsed() ) ),
+                          KGlobal::locale()->prettyFormatDuration( elapsed ) ),
                    "nepomuk" );
         m_indexScheduler->disconnect( this );
+    }
+}
+
+
+void Nepomuk::EventMonitor::pauseIndexing(int pauseState)
+{
+    m_pauseState = pauseState;
+    m_indexScheduler->suspend();
+
+    m_totalIndexingSeconds += m_indexingStartTime.secsTo( QDateTime::currentDateTime() );
+}
 
-        m_periodicUpdateTimer.start();
+
+void Nepomuk::EventMonitor::resumeIndexing()
+{
+    m_pauseState = NotPaused;
+    m_indexScheduler->resume();
+
+    m_indexingStartTime = QDateTime::currentDateTime();
+}
+
+
+void Nepomuk::EventMonitor::slotIndexingSuspended( bool suspended )
+{
+    if( suspended ) {
+        //The indexing is already paused, this meerly sets the correct state, and adjusts the timing.
+        pauseIndexing( PausedCustom );
+    }
+    else {
+        //Again, used to set the correct state, and adjust the timing.
+        resumeIndexing();
     }
 }
 
diff --git a/nepomuk/services/strigi/eventmonitor.h b/nepomuk/services/strigi/eventmonitor.h
index ce65060..eafd744 100644
--- a/nepomuk/services/strigi/eventmonitor.h
+++ b/nepomuk/services/strigi/eventmonitor.h
@@ -22,7 +22,7 @@
 #include <QtCore/QObject>
 #include <QtCore/QStringList>
 #include <QtCore/QTimer>
-#include <QtCore/QTime>
+#include <QtCore/QDateTime>
 
 class KDiskFreeSpace;
 
@@ -42,12 +42,16 @@ namespace Nepomuk {
         void slotPowerManagementStatusChanged( bool conserveResources );
         void slotCheckAvailableSpace();
         void slotIndexingStopped();
+        void pauseIndexing(int pauseState);
+        void resumeIndexing();
+        void slotIndexingSuspended( bool suspended );
 
     private:
         enum {
             NotPaused,
             PausedDueToPowerManagement,
-            PausedDueToAvailSpace
+            PausedDueToAvailSpace,
+            PausedCustom
         };
 
         IndexScheduler* m_indexScheduler;
@@ -56,9 +60,8 @@ namespace Nepomuk {
         // timer used to periodically check for available space
         QTimer m_availSpaceTimer;
 
-        QTime m_initialIndexTime;
-
-        QTimer m_periodicUpdateTimer;
+        QDateTime m_indexingStartTime;
+        int m_totalIndexingSeconds;
     };
 }
 
diff --git a/nepomuk/services/strigi/indexscheduler.cpp b/nepomuk/services/strigi/indexscheduler.cpp
index f5cf4b4..0545e55 100644
--- a/nepomuk/services/strigi/indexscheduler.cpp
+++ b/nepomuk/services/strigi/indexscheduler.cpp
@@ -32,6 +32,7 @@
 #include <QtCore/QDateTime>
 #include <QtCore/QByteArray>
 #include <QtCore/QUrl>
+#include <QtCore/QTimer>
 
 #include <KDebug>
 #include <KTemporaryFile>
@@ -63,21 +64,39 @@ namespace {
     const int s_reducedSpeedDelay = 500; // ms
     const int s_snailPaceDelay = 3000;   // ms
 
+    bool isResourcePresent( const QString & dir ) {
+        QString query = QString::fromLatin1(" ask { ?r %1 %2. } ")
+                        .arg( Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::url() ),
+                              Soprano::Node::resourceToN3( KUrl( dir ) ) );
+        return Nepomuk::ResourceManager::instance()->mainModel()->executeQuery( query, Soprano::Query::QueryLanguageSparql ).boolValue();
+    }
 
     QHash<QString, QDateTime> getChildren( const QString& dir )
     {
         QHash<QString, QDateTime> children;
+        QString query;
 
-        QString query = QString( "select distinct ?url ?mtime where { "
-                                 "?r %1 ?parent . ?parent %2 %3 . "
-                                 "?r %4 ?mtime . "
-                                 "?r %2 ?url . "
-                                 "}")
-                        .arg( Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::isPartOf() ),
-                              Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::url() ),
-                              Soprano::Node::resourceToN3( KUrl( dir ) ),
-                              Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::lastModified() ) );
-
+        if( !isResourcePresent( dir ) ) {
+            query = QString::fromLatin1( "select distinct ?url ?mtime where { "
+                                         "?r %1 ?url . "
+                                         "FILTER( regex(str(?url), '^file://%2/([^/]*)$') ) . "
+                                         "?r %3 ?mtime ."
+                                         "}" )
+                    .arg( Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::url() ),
+                          dir,
+                          Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::lastModified() ) );
+        }
+        else {
+            query = QString::fromLatin1( "select distinct ?url ?mtime where { "
+                                        "?r %1 ?parent . ?parent %2 %3 . "
+                                        "?r %4 ?mtime . "
+                                        "?r %2 ?url . "
+                                        "}" )
+                    .arg( Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::isPartOf() ),
+                        Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::url() ),
+                        Soprano::Node::resourceToN3( KUrl( dir ) ),
+                        Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::lastModified() ) );
+        }
         //kDebug() << "running getChildren query:" << query;
 
         Soprano::QueryResultIterator result = Nepomuk::ResourceManager::instance()->mainModel()->executeQuery( query, Soprano::Query::QueryLanguageSparql );
@@ -130,6 +149,13 @@ Nepomuk::IndexScheduler::IndexScheduler( Strigi::IndexManager* manager, QObject*
 {
     m_analyzerConfig = new StoppableConfiguration;
 
+    // see updateDir(QString,bool) for details on the timer
+    m_dirsToUpdateWakeupTimer = new QTimer( this );
+    m_dirsToUpdateWakeupTimer->setSingleShot( true );
+    m_dirsToUpdateWakeupTimer->setInterval(1000);
+    connect( m_dirsToUpdateWakeupTimer, SIGNAL( timeout() ),
+             this, SLOT( slotDirsToUpdateWakeupTimeout() ) );
+
     connect( StrigiServiceConfig::self(), SIGNAL( configChanged() ),
              this, SLOT( slotConfigChanged() ) );
 }
@@ -383,7 +409,9 @@ bool Nepomuk::IndexScheduler::updateDir( const QString& dir, Strigi::StreamAnaly
         if ( !waitForContinue() )
             return false;
 
+        m_currentUrl = file.filePath();
         analyzeFile( file, analyzer );
+        m_currentUrl = KUrl();
     }
 
     // recurse into subdirs (we do this in a separate loop to always keep a proper state:
@@ -405,7 +433,6 @@ void Nepomuk::IndexScheduler::analyzeFile( const QFileInfo& file, Strigi::Stream
     //
     // strigi asserts if the file path has a trailing slash
     //
-    m_currentUrl = file.filePath();
     QString filePath = m_currentUrl.toLocalFile( KUrl::RemoveTrailingSlash );
     QString dir = m_currentUrl.directory(KUrl::IgnoreTrailingSlash);
 
@@ -427,9 +454,6 @@ void Nepomuk::IndexScheduler::analyzeFile( const QFileInfo& file, Strigi::Stream
     else {
         analysisresult.index(0);
     }
-
-    // done with this file
-    m_currentUrl = KUrl();
 }
 
 
@@ -453,7 +477,15 @@ void Nepomuk::IndexScheduler::updateDir( const QString& path, bool forceUpdate )
 {
     QMutexLocker lock( &m_dirsToUpdateMutex );
     m_dirsToUpdate << qMakePair( path, UpdateDirFlags( forceUpdate ? ForceUpdate : NoUpdateFlags ) );
-    m_dirsToUpdateWc.wakeAll();
+
+    // sometimes the filewatch service will call this method many times in a row with the same
+    // folder (in case a whole folder is created or modified). In order not to run an update every
+    // time we slightly delay the update process
+    if ( !isSuspended() &&
+         isIndexing() &&
+         !m_dirsToUpdateWakeupTimer->isActive() ) {
+        m_dirsToUpdateWakeupTimer->start();
+    }
 }
 
 
@@ -495,6 +527,12 @@ void Nepomuk::IndexScheduler::slotConfigChanged()
 }
 
 
+void Nepomuk::IndexScheduler::slotDirsToUpdateWakeupTimeout()
+{
+    m_dirsToUpdateWc.wakeAll();
+}
+
+
 namespace {
     class QDataStreamStrigiBufferedStream : public Strigi::BufferedStream<char>
     {
@@ -545,6 +583,14 @@ void Nepomuk::IndexScheduler::analyzeResource( const QUrl& uri, const QDateTime&
 }
 
 
+void Nepomuk::IndexScheduler::analyzeFile( const QString& path )
+{
+    Strigi::StreamAnalyzer analyzer( *m_analyzerConfig );
+    analyzer.setIndexWriter( *m_indexManager->indexWriter() );
+    analyzeFile( path, &analyzer );
+}
+
+
 void Nepomuk::IndexScheduler::deleteEntries( const QStringList& entries )
 {
     // recurse into subdirs
@@ -629,6 +675,8 @@ void Nepomuk::IndexScheduler::removeOldAndUnwantedEntries()
     // be indexed at once.
     //
     QString folderFilter = constructFolderFilter();
+    if( !folderFilter.isEmpty() )
+        folderFilter = QString::fromLatin1("FILTER(%1) .").arg(folderFilter);
 
     //
     // We query all files that should not be in the store
@@ -638,7 +686,7 @@ void Nepomuk::IndexScheduler::removeOldAndUnwantedEntries()
                                          "?r %1 ?url . "
                                          "?g <http://www.strigi.org/fields#indexGraphFor> ?r . "
                                          "FILTER(REGEX(STR(?url),'^file:/')) . "
-                                         "FILTER(%2) . }" )
+                                         "%2 }" )
                     .arg( Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::url() ),
                           folderFilter );
     kDebug() << query;
@@ -660,20 +708,29 @@ void Nepomuk::IndexScheduler::removeOldAndUnwantedEntries()
     //
     // Build filter query for all exclude filters
     //
-    QStringList filters;
+    QStringList fileFilters;
     foreach( const QRegExp& re, Nepomuk::StrigiServiceConfig::self()->excludeFilterRegExps() ) {
-        filters << QString::fromLatin1( "REGEX(STR(?fn),\"/%1$\")" ).arg( re.pattern().replace( '\\',"\\\\" ) );
+        fileFilters << QString::fromLatin1( "REGEX(STR(?fn),\"^%1$\")" ).arg( re.pattern().replace( '\\',"\\\\" ) );
     }
+    QString includeExcludeFilters = constructExcludeIncludeFoldersFilter();
+
+    QString filters;
+    if( !includeExcludeFilters.isEmpty() && !fileFilters.isEmpty() )
+        filters = QString::fromLatin1("FILTER((%1) && (%2)) .").arg( includeExcludeFilters, fileFilters.join(" || ") );
+    else if( !fileFilters.isEmpty() )
+        filters = QString::fromLatin1("FILTER(%1) .").arg( fileFilters.join(" || ") );
+    else if( !includeExcludeFilters.isEmpty() )
+        filters = QString::fromLatin1("FILTER(%1) .").arg( includeExcludeFilters );
+    
     query = QString::fromLatin1( "select distinct ?g ?url where { "
                                  "?r %1 ?url . "
                                  "?r %2 ?fn . "
                                  "?g <http://www.strigi.org/fields#indexGraphFor> ?r . "
-                                 "FILTER(REGEX(STR(?url),'^file:/')) . "
-                                 "FILTER((%3) && (%4)) . }" )
+                                 "FILTER(REGEX(STR(?url),\"^file:/\")) . "
+                                 "%3 }" )
             .arg( Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NIE::url() ),
                   Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NFO::fileName() ),
-                  constructExcludeIncludeFoldersFilter(),
-                  filters.join( " || " ) );
+                  filters );
     kDebug() << query;
     it = ResourceManager::instance()->mainModel()->executeQuery( query, Soprano::Query::QueryLanguageSparql );
     while ( it.next() ) {
diff --git a/nepomuk/services/strigi/indexscheduler.h b/nepomuk/services/strigi/indexscheduler.h
index 1b79a4a..b3aee1b 100644
--- a/nepomuk/services/strigi/indexscheduler.h
+++ b/nepomuk/services/strigi/indexscheduler.h
@@ -37,7 +37,7 @@ namespace Strigi {
 
 class QFileInfo;
 class QByteArray;
-
+class QTimer;
 
 namespace Nepomuk {
     /**
@@ -157,6 +157,11 @@ namespace Nepomuk {
         void updateAll( bool forceUpdate = false );
 
         /**
+         * Analyze the one file without conditions.
+         */
+        void analyzeFile( const QString& path );
+
+        /**
          * Analyze a resource that is not read from the local harddisk.
          *
          * \param uri The resource URI to identify the resource.
@@ -174,6 +179,7 @@ namespace Nepomuk {
 
     private Q_SLOTS:
         void slotConfigChanged();
+        void slotDirsToUpdateWakeupTimeout();
 
     private:
         void run();
@@ -215,6 +221,7 @@ namespace Nepomuk {
 
         QMutex m_dirsToUpdateMutex;
         QWaitCondition m_dirsToUpdateWc;
+        QTimer* m_dirsToUpdateWakeupTimer;
 
         QString m_currentFolder;
         KUrl m_currentUrl;
diff --git a/nepomuk/services/strigi/nepomukstrigiservice.desktop b/nepomuk/services/strigi/nepomukstrigiservice.desktop
index f03167f..cc4fa3f 100644
--- a/nepomuk/services/strigi/nepomukstrigiservice.desktop
+++ b/nepomuk/services/strigi/nepomukstrigiservice.desktop
@@ -35,6 +35,7 @@ Name[hne]=नेपोमक स्ट्रिगि सेवा
 Name[hr]=Uslufa Nepomuk Strigi
 Name[hsb]=Nepomuk Strigi słužba
 Name[hu]=Nepomuk Strigi szolgáltatás
+Name[ia]=Servicio de Strigi de Nepomuk
 Name[id]=Layanan Nepomuk Strigi
 Name[is]=Nepomuk Strigi þjónusta
 Name[it]=Servizio Strigi di Nepomuk
@@ -61,7 +62,7 @@ Name[pt_BR]=Serviço Strigi para o Nepomuk
 Name[ro]=Serviciu Strigi Nepomuk
 Name[ru]=Служба Nepomuk Strigi
 Name[si]=Nepomuk Strigi සේවාව
-Name[sk]=Nepomuk Strigi služba
+Name[sk]=Služba Nepomuk Strigi
 Name[sl]=Storitev Strigi za Nepomuk
 Name[sr]=Непомуков сервис Стригија
 Name[sr@ijekavian]=Непомуков сервис Стригија
@@ -106,6 +107,7 @@ Comment[he]=שירות Nepomuk ששולט בתהליך הרקע strigi, לדוג
 Comment[hr]=Nepomukova usluga koja upravlja strigidaemonom, tj. indeksira datoteke na računalu
 Comment[hsb]=Nepomukowa słužba za strigidemon, to su indeksowe dataje na dźěłowym powjerchu
 Comment[hu]=A Strigi szolgáltatást kezeli, amely fájlok indexelését végzi
+Comment[ia]=Servicio de Nepomuk que controla le strigidaemon, i.e. indicisa le files su le scriptorio
 Comment[id]=Layanan Nepomuk yang mengontrol jurik strigi, misalnya berkas indeks di desktop
 Comment[is]=Nepomuk þjónusta sem stýrir strigidaemon, þ.e. býr til yfirlit um skrár á skjáborði
 Comment[it]=Servizio di Nepomuk che controlla il demone strigi, cioè indicizza i file del desktop
@@ -145,5 +147,5 @@ Comment[tr]=Strigidaemon uygulamasını yöneten Nepomuk servisi, masaüstünüz
 Comment[uk]=Служба Nepomuk, яка контролює фонову службу strigi, тобто, індексує файли на стільниці
 Comment[wa]=Siervice Nepomuk ki controle li démon strigi, ki fwait ls indecses des fitchîs sol sicribanne
 Comment[x-test]=xxNepomuk Service which controls the strigidaemon, i.e. indexes files on the desktopxx
-Comment[zh_CN]=控制 strigidaemon 进程的 Nepomuk 服务,其作用比如对桌面上的文件进行索引
+Comment[zh_CN]=Nepomuk 服务,它控制 strigidaemon, 也就是索引系统中的文件
 Comment[zh_TW]=控制 Strigi 桌面索引守護程式的 Nepomuk 服務
diff --git a/nepomuk/services/strigi/nepomukstrigiservice.notifyrc b/nepomuk/services/strigi/nepomukstrigiservice.notifyrc
index 21b76e0..05d55c0 100644
--- a/nepomuk/services/strigi/nepomukstrigiservice.notifyrc
+++ b/nepomuk/services/strigi/nepomukstrigiservice.notifyrc
@@ -1,59 +1,60 @@
 [Global]
 IconName=nepomuk
-Comment=Search service file indexer
-Comment[ca]=L'indexador de fitxers del servei de cerca
-Comment[ca@valencia]=L'indexador de fitxers del servei de cerca
-Comment[csb]=Indeksownik serwisu szëkbë lopków
-Comment[da]=Filindeksering til søgetjeneste
-Comment[de]=Suchdienst-Dateiindexer
-Comment[el]=Υπηρεσία ευρετηρίου αρχείων
-Comment[en_GB]=Search service file indexer
-Comment[eo]=Indeksado de dosieroj por la ŝerĉ-servo
-Comment[es]=Indexador de archivos del servicio de búsqueda
-Comment[et]=Otsinguteenuse failide indekseerija
-Comment[eu]=Bilaketa zerbitzuaren fitxategi indexatzailea
-Comment[fi]=Etsintäpalvelu tiedostoindeksoija
-Comment[fr]=Service d'indexation de fichier pour les recherches
-Comment[fy]=Syk tsjinst triem yndeksering
-Comment[ga]=Innéacsóir comhad do sheirbhís chuardaigh
-Comment[gl]=Indexador de ficheiros do servizo de procura
-Comment[hr]=Usluga pretrage – indekser datoteka
-Comment[hu]=Szolgáltatói fájl indexelő keresése
-Comment[id]=Layanan pencarian pengindeksan berkas
-Comment[is]=Strigi skráayfirlitsgerð
-Comment[it]=Indicizzatore di file del servizio di ricerca
-Comment[ja]=検索サービスのファイルインデクサ
-Comment[kk]=Іздеу қызметінің файл индекстегіш
-Comment[km]=កម្មវិធី​ដាក់​លិបិក្រម​ឯកសារ​សេវា​ស្វែងរក
-Comment[kn]=ಹುಡುಕು ಸೇವೆ ಕಡತ ಸೂಚಿ (ಇಂಡೆಕ್ಸರ್)
-Comment[ko]=검색 서비스 파일 인덱서
-Comment[lt]=Paieškos tarnybos failų indeksuoklis
-Comment[lv]=Meklēšanas servisa failu indeksētājs
-Comment[mk]=Индексирач на датотеки за сервисот за пребарување
-Comment[ml]=തെരച്ചില്‍ സേവന ഫയല്‍ സ്വാംശീകരണം
-Comment[nb]=Filindeksering for søketjeneste
-Comment[nds]=Söökdeenst-Dateiindizeren
-Comment[nl]=Zoekservice bestandenindexering
-Comment[nn]=Filindeksering for søkjeteneste
-Comment[pa]=ਨਿਪੋਮੁਕ ਸਰਵਿਸ ਫਾਇਲ ਇੰਡੈਕਸਰ
-Comment[pl]=Usługa indeksowania plików dla wyszukiwania
-Comment[pt]=Indexação de ficheiros do serviço de pesquisa
-Comment[pt_BR]=Indexador de arquivos do serviço de pesquisa
-Comment[ro]=Indexator de fișiere pentru serviciul de căutare
-Comment[si]=ගොනු සූචිකාරක සේවාව සොයන්න
-Comment[sk]=Indexovanie súborov pre vyhľadávaciu službu
-Comment[sl]=Indeksirnik datotek za storitev iskanja
-Comment[sr]=Индексар фајлова претраживачког сервиса
-Comment[sr@ijekavian]=Индексар фајлова претраживачког сервиса
-Comment[sr@ijekavianlatin]=Indeksar fajlova pretraživačkog servisa
-Comment[sr@latin]=Indeksar fajlova pretraživačkog servisa
-Comment[sv]=Söktjänst filindexering
-Comment[tg]=Настройка сервера Nepomuk/Strigi
-Comment[tr]=Arama servisi dosya indeksleyici
-Comment[uk]=Індексування файлів служби пошуку
-Comment[x-test]=xxSearch service file indexerxx
-Comment[zh_CN]=搜索服务文件索引器
-Comment[zh_TW]=搜尋服務檔案索引
+Comment=Desktop Search
+Comment[ar]=بحث سطح المكتب
+Comment[bn]=ডেস্কটপ সন্ধান
+Comment[ca]=Cerca a l'escriptori
+Comment[ca@valencia]=Cerca a l'escriptori
+Comment[cs]=Vyhledávací služby
+Comment[da]=Skrivebordssøgning
+Comment[de]=Desktopsuche
+Comment[el]=Αναζήτηση επιφάνειας εργασίας
+Comment[en_GB]=Desktop Search
+Comment[es]=Búsqueda de escritorio
+Comment[et]=Töölauaotsing
+Comment[eu]=Mahaigaineko bilaketa
+Comment[fi]=Työpöytähaku
+Comment[fr]=Recherche sur le bureau
+Comment[fy]=Buroblêd sykaksje
+Comment[ga]=Cuardach Deisce
+Comment[hi]=डेस्कटॉप खोज
+Comment[hr]=Pretraživanje računala
+Comment[hu]=Asztali keresés
+Comment[ia]=Cerca de Scriptorio
+Comment[id]=Pencarian Desktop
+Comment[is]=Skjáborðsleit
+Comment[it]=Ricerca sul desktop
+Comment[ja]=デスクトップ検索
+Comment[kk]=Іздеу
+Comment[km]=ស្វែងរក​ផ្ទៃតុ
+Comment[kn]=ಗಣಕತೆರೆ ಹುಡುಕಾಟ
+Comment[ko]=데스크톱 검색
+Comment[lt]=Darbastalio paieška
+Comment[lv]=Darbvirsmas meklēšana
+Comment[ml]=പണിയിട തിരയല്‍
+Comment[nb]=Skrivebordssøk
+Comment[nds]=Schriefdischsöök
+Comment[nl]=Bureaublad-zoekopdracht
+Comment[nn]=Skrivebordssøk
+Comment[pa]=ਡੈਸਕਟਾਪ ਖੋਜ
+Comment[pl]=Wyszukiwanie na pulpicie
+Comment[pt]=Pesquisa no Ambiente de Trabalho
+Comment[pt_BR]=Pesquisa na área de trabalho
+Comment[ru]=Поиск по меткам и содержимому
+Comment[sk]=Hľadanie na ploche
+Comment[sl]=Namizno iskanje
+Comment[sr]=Претрага површи
+Comment[sr@ijekavian]=Претрага површи
+Comment[sr@ijekavianlatin]=Pretraga površi
+Comment[sr@latin]=Pretraga površi
+Comment[sv]=Skrivbordssökning
+Comment[tg]=Ҷустуҷӯи мизи корӣ
+Comment[th]=ค้นหาผ่านพื้นที่ทำงาน
+Comment[tr]=Masaüstü Araması
+Comment[uk]=Стільничний пошук
+Comment[x-test]=xxDesktop Searchxx
+Comment[zh_CN]=桌面搜索
+Comment[zh_TW]=桌面搜尋
 
 [Event/initialIndexingStarted]
 Name=Initial Indexing started
@@ -85,6 +86,7 @@ Name[hne]=सूची बनाना सुरू हो गे
 Name[hr]=Prvotno indeksiranje je započelo
 Name[hsb]=Prěnje tworjenje indeksa startowane
 Name[hu]=A kezdeti index elkészítése folyik
+Name[ia]=Il initiava le indicisation initial
 Name[id]=Pengindeksan Awal dimulai
 Name[is]=Gerð upphafsyfirlits er hafin
 Name[it]=Indicizzazione iniziale avviata
@@ -108,7 +110,7 @@ Name[or]=ପ୍ରାରମ୍ଭିକ ଅନୁକ୍ରମିକ ଆରମ୍
 Name[pa]=ਸ਼ੁਰੂਆਤੀ ਇੰਡੈਕਸ ਸ਼ੁਰੂ ਕੀਤਾ
 Name[pl]=Rozpoczęto początkowe indeksowanie
 Name[pt]=Início da primeira indexação
-Name[pt_BR]=Iniciada a indexação inicial
+Name[pt_BR]=A indexação inicial foi iniciada
 Name[ro]=Indexarea inițială a început
 Name[ru]=Начато индексирование
 Name[si]=තනි සූචිකරණය ඇරඹිනි
@@ -130,6 +132,7 @@ Name[x-test]=xxInitial Indexing startedxx
 Name[zh_CN]=索引初始化开始
 Name[zh_TW]=初始化索引已開始
 Comment=Indexing of local files for fast searches has started.
+Comment[ar]=بدات فهرسة  الملفات المحلية من أجل البحث السريع
 Comment[ca]=S'ha engegat la indexació dels fitxers locals per a les cerques ràpides.
 Comment[ca@valencia]=S'ha engegat la indexació dels fitxers locals per a les cerques ràpides.
 Comment[csb]=Indeksowanié môlowich lopków dlô chùtczi szëkbë òstôł zrëszony.
@@ -148,7 +151,7 @@ Comment[ga]=Tosaíodh innéacsú de chomhaid logánta a cheadaíonn cuardaigh n
 Comment[gl]=Comezouse a indexación dos ficheiros locais para facer procuras rápidas.
 Comment[he]=אינדוקס של קבצים מקומיים עבור חיפושים מהירים החל
 Comment[hr]=Započelo je indeksiranje lokalnih datoteka za brzu pretragu.
-Comment[hu]=A helyi fájlok indexelése elkezdődött a gyors keresések számára.
+Comment[ia]=Le indicisation de files local pro rapide cercas ha initiate
 Comment[id]=Pengindeksan berkas lokal untuk pencarian desktop secara cepat telah dimulai.
 Comment[is]=Gerð skráayfirlits til að styðja við hraðar skjáborðsleitir er hafin.
 Comment[it]=Indicizzazione dei file locali per le ricerche veloci avviata
@@ -170,6 +173,7 @@ Comment[pl]=Nastąpiło rozpoczęcie indeksowania plików lokalnych w celu przys
 Comment[pt]=A indexação dos ficheiros para pesquisas mais rápidas começou agora.
 Comment[pt_BR]=A indexação dos arquivos para pesquisas rápidas foi iniciada.
 Comment[ro]=A început indexarea fișierelor locale pentru căutări rapide.
+Comment[ru]=Начато индексирование локальных файлов для быстрого поиска данных
 Comment[sk]=Indexovanie lokálnych súbory pre rýchle hľadanie bolo spustené.
 Comment[sl]=Pričelo se je indeksiranje krajevnih datotek za hitro iskanje.
 Comment[sr]=Започето је индексирање локалних фајлова ради брзе претраге.
@@ -215,6 +219,7 @@ Name[hne]=सुरू के सूची बनाए के काम पू
 Name[hr]=Prvotno indeksiranje je završilo
 Name[hsb]=Prěni indeks dotwarjeny
 Name[hu]=A kiindulási index elkészült
+Name[ia]=Le indicisation Initial finiva
 Name[id]=Pengindeksan Awal selesai
 Name[is]=Gerð upphafsyfirlits er lokið
 Name[it]=Indicizzazione iniziale terminata
@@ -238,7 +243,7 @@ Name[or]=ପ୍ରାରମ୍ଭିକ ଅନୁକ୍ରମଣ ସମାପ୍
 Name[pa]=ਸ਼ੁਰੂਆਤੀ ਇੰਡੈਕਸ ਮੁਕੰਮਲ
 Name[pl]=Początkowe indeksowanie zakończone
 Name[pt]=Fim da primeira indexação
-Name[pt_BR]=Concluída a indexação inicial
+Name[pt_BR]=A indexação inicial foi concluída
 Name[ro]=Indexarea inițială s-a încheiat
 Name[ru]=Индексирование закончено
 Name[si]=තනි සූචිකරණය නිමයි
@@ -251,7 +256,7 @@ Name[sr@latin]=Završeno početno indeksiranje
 Name[sv]=Inledande indexering klar
 Name[ta]=Initial Indexing finished
 Name[te]=ప్రాధమిక విషయవర్గీకరణ పూర్తైనది.
-Name[tg]=Создание индекса завершено.
+Name[tg]=Эҷоди индекс ба итмом расид
 Name[th]=เตรียมการการทำดัชนีเสร็จแล้ว
 Name[tr]=Temel İndeksleme tamamlandı
 Name[uk]=Початкове індексування закінчено
@@ -259,6 +264,7 @@ Name[x-test]=xxInitial Indexing finishedxx
 Name[zh_CN]=索引初始化完成
 Name[zh_TW]=初始化索引已完成
 Comment=The initial indexing of local files for fast desktop searches has completed.
+Comment[ar]=اكتملت الفهرسة الأولية للملفات المحلية من أجل البحث السريع
 Comment[ca]=Ha finalitzat la indexació inicial dels fitxers locals per a les cerques ràpides d'escriptori.
 Comment[ca@valencia]=Ha finalitzat la indexació inicial dels fitxers locals per a les cerques ràpides d'escriptori.
 Comment[csb]=Indeksowanié môlowich lopków dlô chùtczi szëkbë pùltu òstôło zakùńczoné.
@@ -277,7 +283,7 @@ Comment[ga]=Tá an chéad innéacsú de chomhaid logánta críochnaithe.
 Comment[gl]=Completouse a indexación inicial dos ficheiros locais para facer procuras rápidas no escritorio.
 Comment[he]=אינדוקס ראשוני של קבצים מקומיים עבור חיפושי שולחן מהירים הסתיים
 Comment[hr]=Završilo je prvotno indeksiranje lokalnih datoteka za brzu pretragu računala.
-Comment[hu]=A helyi fájlok indexelése befejeződöttt a gyors asztali keresések számára.
+Comment[ia]=Le indicisation de files local pro rapide cercas de scriptorio ha completate.
 Comment[id]=Pengindeksan awal berkas lokal untuk pencarian desktop secara cepat telah selesai.
 Comment[is]=Gerð skráayfirlits til að styðja við hraðar skjáborðsleitir er lokið.
 Comment[it]=L'indicizzazione iniziale dei file locali per le ricerche desktop veloci è stata completata.
@@ -294,11 +300,12 @@ Comment[nb]=Den første indekseringen av lokale filer for raskere søk er ferdig
 Comment[nds]=Dat eerste Indizeren vun lokaal Dateien för gau Schriefdisch-Söken is afslaten.
 Comment[nl]=De eerste indexering van lokale bestanden voor snelle desktop-zoekopdrachten is gereed.
 Comment[nn]=Starta førsteindekseringa av lokale filer for snøgge søk.
-Comment[pa]=ਤੇਜ਼ ਡੈਸਕਟਾਪ ਖੋਜ ਲਈ ਲੋਕਲ ਫਾਇਲਾਂ ਵਾਸਤੇ ਇੰਡੈਕਸ ਬਣਾਉਣਾ ਪੂਰਾ ਹੋਇਆ।
+Comment[pa]=ਤੇਜ਼ ਡੈਸਕਟਾਪ ਖੋਜ ਲਈ ਲੋਕਲ ਫਾਇਲਾਂ ਵਾਸਤੇ ਇੰਡੈਕਸ ਬਣਾਉਣਾ ਸ਼ੁਰੂ ਕੀਤਾ
 Comment[pl]=Nastąpiło zakończenie wstępnego indeksowania plików lokalnych w celu przyspieszenia wyszukiwania.
 Comment[pt]=A primeira indexação dos ficheiros para pesquisas mais rápidas terminou.
 Comment[pt_BR]=A indexação inicial de arquivos locais para pesquisas rápidas foi concluída.
 Comment[ro]=Indexarea inițială a fișierelor locale pentru căutări de birou rapide s-a încheiat.
+Comment[ru]=Индексирование локальных файлов для быстрого поиска данных завершено
 Comment[sk]=Počiatočné indexovanie lokálnych súborov pre rýchle hľadanie bolo dokončené.
 Comment[sl]=Začetno indeksiranje krajevnih datotek za hitro namizno iskanje se je zaključilo.
 Comment[sr]=Завршено је почетно индексирање локалних фајлова ради брзе претраге површи.
@@ -344,6 +351,7 @@ Name[hne]=इंडेक्सिंग सस्पेंड हे
 Name[hr]=Indeksiranje je pauzirano
 Name[hsb]=Tworjenje indeksa zastajene
 Name[hu]=Az indexelés felfüggesztve
+Name[ia]=Il suspendeva le indicisation
 Name[id]=Pengindeksan disuspensi
 Name[is]=Hætt við yfirlitsgerð
 Name[it]=Indicizzazione sospesa
@@ -385,9 +393,10 @@ Name[th]=การทำดัชนีถูกหยุดพักไว้
 Name[tr]=İndeksleme beklemeye alındı
 Name[uk]=Пауза індексування
 Name[x-test]=xxIndexing suspendedxx
-Name[zh_CN]=索引已中断
+Name[zh_CN]=索引已被推迟
 Name[zh_TW]=索引暫停
 Comment=File indexing has been suspended by the search service.
+Comment[ar]=أجلت فهرسة الملفات بواسطة خدمة البحث.
 Comment[ca]=El servei de cerca ha suspès la indexació de fitxers.
 Comment[ca@valencia]=El servei de cerca ha suspès la indexació de fitxers.
 Comment[csb]=Indeksowanié òprzestóné przez ùsłëżnotã szëkbë.
@@ -406,7 +415,7 @@ Comment[ga]=Chuir an tseirbhís chuardaigh innéacsú comhad ar fionraí.
 Comment[gl]=O servizo de procuras suspendeu a indexación de ficheiros.
 Comment[he]=אינדוקס קובץ הושהה על-ידי שירות החיפוש
 Comment[hr]=Usluga pretrage je pauzirala indeksiranje datoteka.
-Comment[hu]=A fájl indexelést a kereső szolgáltatás felfüggesztette.
+Comment[ia]=Le indicisation del file ha essite suspendite per le servicio de cerca
 Comment[id]=Pengindeksan berkas telah disuspensi oleh layanan pencarian.
 Comment[is]=Gerð skráayfirlits hefur verið frestað af leitartækinu.
 Comment[it]=L'indicizzazione dei file è stata sospesa dal servizio di ricerca.
@@ -423,11 +432,12 @@ Comment[nb]=Søketjenesten har stoppet filindeksering midlertidig.
 Comment[nds]=De Söökdeenst hett dat Indizeren vun Dateien utsett.
 Comment[nl]=Bestandenindexering is onderbroken door de zoekservice.
 Comment[nn]=Filindekseringa med vart stoppa av søkjetenesta.
-Comment[pa]=ਖੋਜ ਸਰਵਿਸ ਨੇ ਫਾਇਲ ਇੰਡੈਕਸ ਨੂੰ ਸਸਪੈਂਡ ਕੀਤਾ
+Comment[pa]=ਖੋਜ ਸਰਵਿਸ ਵਲੋਂ ਫਾਇਲ ਇੰਡੈਕਸਿੰਗ ਨੂੰ ਸਸਪੈਂਡ ਕੀਤਾ ਗਿਆ ਹੈ।
 Comment[pl]=Indeksowanie plików zostało zawieszone przez usługę wyszukiwania.
 Comment[pt]=A indexação de ficheiros foi suspensa pelo serviço de pesquisa.
 Comment[pt_BR]=A indexação de arquivos foi suspensa pelo serviço de pesquisa.
 Comment[ro]=Indexarea de fișiere a fost suspendată de serviciul de căutare.
+Comment[ru]=Индексирование файлов приостановлено
 Comment[sk]=Indexovanie súborov bolo pozastavené vyhľadávacou službou.
 Comment[sl]=Storitev za iskanje je zaustavila indeksiranje datotek.
 Comment[sr]=Сервис претраге је суспендовао индексирање фајлова.
@@ -439,7 +449,7 @@ Comment[th]=การทำดัชนีถูกหยุดพักชั
 Comment[tr]=Dosya indeksleyici arama servisi tarafından durduruldu.
 Comment[uk]=Індексування файлів було призупинено службою пошуку.
 Comment[x-test]=xxFile indexing has been suspended by the search service.xx
-Comment[zh_CN]=Strigi 文件索引操作已经被搜索服务中断。
+Comment[zh_CN]=Strigi 文件索引操作已经被搜索服务推迟。
 Comment[zh_TW]=檔案索引已被暫停。
 Action=Popup
 
@@ -473,6 +483,7 @@ Name[hne]=इन्डेक्सिंग वापस चालू
 Name[hr]=Indeksiranje nastavljeno
 Name[hsb]=Indeks so dale twari
 Name[hu]=Az indexelés folytatódik
+Name[ia]=Il resumeva le indicisation
 Name[id]=Pengindeksan dilanjutkan
 Name[is]=Yfirlitsgerð er hafin aftur
 Name[it]=Indicizzazione ripresa
@@ -517,6 +528,7 @@ Name[x-test]=xxIndexing resumedxx
 Name[zh_CN]=索引已恢复
 Name[zh_TW]=索引回復
 Comment=File indexing has been resumed by the search service.
+Comment[ar]=استأنفت علمية الفهرسة بواسطة خدمة البحث.
 Comment[ca]=El servei de cerca ha reprès la indexació de fitxers.
 Comment[ca@valencia]=El servei de cerca ha représ la indexació de fitxers.
 Comment[csb]=Dalszé indeksowaniém zrëszoné przez ùsłëżnotã szëkbë.
@@ -535,7 +547,7 @@ Comment[ga]=D'atosaigh an tseirbhís chuardaigh innéacsú comhad.
 Comment[gl]=O servizo de procuras continuou a indexación de ficheiros.
 Comment[he]=אינדוקס קובץ נמשך על-ידי שירות החיפוש
 Comment[hr]=Usluga pretrage je nastavila indeksiranje datoteka.
-Comment[hu]=A fájl indexelést a kereső szolgáltatás folytatta.
+Comment[ia]=Le indicisation de file ha essite resumite per le servicio de cerca
 Comment[id]=Pengindeksan berkas telah dilanjutkan oleh layanan pencarian.
 Comment[is]=Gerð skráayfirlits hefur verið hafin aftur af leitartækinu.
 Comment[it]=L'indicizzazione dei file è stata ripresa dal servizio di ricerca.
@@ -552,11 +564,12 @@ Comment[nb]=Søketjenesten har gjenopptatt filindeksering.
 Comment[nds]=De Söökdeenst maakt mit dat Indizeren vun Dateien wieder.
 Comment[nl]=Bestandenindexering is hervat door de zoekservice.
 Comment[nn]=Filindekseringa vart starta opp att av søkjetenesta.
-Comment[pa]=ਖੋਜ ਸਰਵਿਸ ਵਲੋਂ ਫਾਇਲ ਇੰਡੈਕਸ ਮੁੜ-ਚਲਾਇਆ ਗਿਆ
+Comment[pa]=ਖੋਜ ਸਰਵਿਸ ਵਲੋਂ ਫਾਇਲ ਇੰਡੈਕਸਿੰਗ ਸਰਵਿਸ ਨੂੰ ਮੁੜ-ਚਾਲੂ ਕੀਤਾ ਗਿਆ ਹੈ।
 Comment[pl]=Wznowiono indeksowanie plików.
 Comment[pt]=A indexação de ficheiros foi retomada pelo serviço de pesquisa.
 Comment[pt_BR]=A indexação de arquivos foi retomada pelo serviço de pesquisa.
 Comment[ro]=Indexarea de fișiere a fost reluată de serviciul de căutare.
+Comment[ru]=Индексирование файлов продолжено
 Comment[sk]=Indexovanie súborov bolo obnovené vyhľadávacou službou.
 Comment[sl]=Storitev za iskanje je znova zagnala indeksiranje datotek.
 Comment[sr]=Сервис претраге је наставио индексирање фајлова.
diff --git a/nepomuk/services/strigi/statuswidget.cpp b/nepomuk/services/strigi/statuswidget.cpp
index 9418619..36e1502 100644
--- a/nepomuk/services/strigi/statuswidget.cpp
+++ b/nepomuk/services/strigi/statuswidget.cpp
@@ -1,5 +1,5 @@
 /* This file is part of the KDE Project
-   Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
+   Copyright (c) 2008-2010 Sebastian Trueg <trueg@kde.org>
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
diff --git a/nepomuk/services/strigi/strigiservice.cpp b/nepomuk/services/strigi/strigiservice.cpp
index d122128..c4a5fe7 100644
--- a/nepomuk/services/strigi/strigiservice.cpp
+++ b/nepomuk/services/strigi/strigiservice.cpp
@@ -18,17 +18,16 @@
 
 #include "strigiservice.h"
 #include "strigiserviceadaptor.h"
-#include "priority.h"
 #include "indexscheduler.h"
 #include "eventmonitor.h"
 #include "systray.h"
 #include "strigiserviceconfig.h"
 #include "statuswidget.h"
-#include "filesystemwatcher.h"
-#include "useractivitymonitor.h"
+#include "filewatchserviceinterface.h"
 
 #include <KDebug>
 #include <KDirNotify>
+#include <kidletime.h>
 
 #include <strigi/indexpluginloader.h>
 #include <strigi/indexmanager.h>
@@ -42,20 +41,6 @@ Nepomuk::StrigiService::StrigiService( QObject* parent, const QList<QVariant>& )
     : Service( parent, true ),
       m_indexManager( 0 )
 {
-    // only so ResourceManager won't open yet another connection to the nepomuk server
-    ResourceManager::instance()->setOverrideMainModel( mainModel() );
-
-
-    // lower process priority - we do not want to spoil KDE usage
-    // ==============================================================
-    if ( !lowerPriority() )
-        kDebug() << "Failed to lower priority.";
-    if ( !lowerSchedulingPriority() )
-        kDebug() << "Failed to lower scheduling priority.";
-    if ( !lowerIOPriority() )
-        kDebug() << "Failed to lower io priority.";
-
-
     // setup the actual index scheduler including strigi stuff
     // ==============================================================
     if ( ( m_indexManager = Strigi::IndexPluginLoader::createIndexManager( "nepomukbackend", 0 ) ) ) {
@@ -64,18 +49,6 @@ Nepomuk::StrigiService::StrigiService( QObject* parent, const QList<QVariant>& )
         // monitor all kinds of events
         ( void )new EventMonitor( m_indexScheduler, this );
 
-        // monitor the file system
-        m_fsWatcher = new FileSystemWatcher( this );
-        m_fsWatcher->setWatchRecursively( true );
-        connect( m_fsWatcher, SIGNAL( dirty( QString ) ),
-                 this, SLOT( slotDirDirty( QString ) ) );
-
-        // monitor all KDE-ish changes for quick updates
-        connect( new org::kde::KDirNotify( QString(), QString(), QDBusConnection::sessionBus(), this ),
-                 SIGNAL( FilesAdded( QString ) ),
-                 this, SLOT( slotDirDirty( const QString& ) ) );
-
-
         // update the watches if the config changes
         connect( StrigiServiceConfig::self(), SIGNAL( configChanged() ),
                  this, SLOT( updateWatches() ) );
@@ -98,22 +71,13 @@ Nepomuk::StrigiService::StrigiService( QObject* parent, const QList<QVariant>& )
                  this, SIGNAL( statusStringChanged() ) );
         connect( m_indexScheduler, SIGNAL( indexingSuspended(bool) ),
                  this, SIGNAL( statusStringChanged() ) );
-        connect( m_fsWatcher, SIGNAL( statusChanged(FileSystemWatcher::Status) ),
-                 this, SIGNAL( statusStringChanged() ) );
 
         // setup the indexer to index at snail speed for the first two minutes
         // this is done for KDE startup - to not slow that down too much
         m_indexScheduler->setIndexingSpeed( IndexScheduler::SnailPace );
-        QTimer::singleShot( 2*60*1000, m_indexScheduler, SLOT( setReducedIndexingSpeed() ) );
 
-        // slow down on user activity (start also only after 2 minutes)
-        UserActivityMonitor* userActivityMonitor = new UserActivityMonitor( this );
-        connect( userActivityMonitor, SIGNAL( userActive( bool ) ),
-                 m_indexScheduler, SLOT( setReducedIndexingSpeed( bool ) ) );
-        QTimer::singleShot( 2*60*1000, userActivityMonitor, SLOT( start() ) );
-
-        // start watching the index folders
-        QTimer::singleShot( 2*60*1000, this, SLOT( updateWatches() ) );
+        // delayed init for the rest which uses IO and CPU
+        QTimer::singleShot( 2*60*1000, this, SLOT( finishInitialization() ) );
 
         // start the actual indexing
         m_indexScheduler->start();
@@ -139,46 +103,80 @@ Nepomuk::StrigiService::~StrigiService()
 }
 
 
-void Nepomuk::StrigiService::updateWatches()
+void Nepomuk::StrigiService::finishInitialization()
 {
-    // the hard way since the KDirWatch API is too simple
-    QStringList folders = StrigiServiceConfig::self()->includeFolders();
-    if ( folders != m_fsWatcher->folders() ) {
-        m_fsWatcher->setFolders( StrigiServiceConfig::self()->includeFolders() );
-        m_fsWatcher->setInterval( 2*60 ); // check every 2 minutes
-        m_fsWatcher->start();
-    }
+    // slow down on user activity (start also only after 2 minutes)
+    KIdleTime* idleTime = KIdleTime::instance();
+    idleTime->addIdleTimeout( 1000 * 60 * 2 ); // 2 min
+
+    connect( idleTime, SIGNAL(timeoutReached(int)), this, SLOT(slotIdleTimeoutReached()) );
+    connect( idleTime, SIGNAL(resumingFromIdle()), this, SLOT(slotIdleTimerResume()) );
+
+    // start out with reduced speed until the user is idle for 2 min
+    m_indexScheduler->setIndexingSpeed( IndexScheduler::ReducedSpeed );
+
+    updateWatches();
+}
+
+void Nepomuk::StrigiService::slotIdleTimeoutReached()
+{
+    m_indexScheduler->setIndexingSpeed( IndexScheduler::FullSpeed );
+    KIdleTime::instance()->catchNextResumeEvent();
 }
 
+void Nepomuk::StrigiService::slotIdleTimerResume()
+{
+    m_indexScheduler->setIndexingSpeed( IndexScheduler::ReducedSpeed );
+}
 
-void Nepomuk::StrigiService::slotDirDirty( const QString& path )
+
+void Nepomuk::StrigiService::updateWatches()
 {
-    if ( StrigiServiceConfig::self()->shouldFolderBeIndexed( path ) ) {
-        m_indexScheduler->updateDir( path );
+    org::kde::nepomuk::FileWatch filewatch( "org.kde.nepomuk.services.nepomukfilewatch",
+                                            "/nepomukfilewatch",
+                                            QDBusConnection::sessionBus() );
+    foreach( const QString& folder, StrigiServiceConfig::self()->includeFolders() ) {
+        filewatch.watchFolder( folder );
     }
 }
 
 
 QString Nepomuk::StrigiService::userStatusString() const
 {
+    return userStatusString( false );
+}
+
+
+QString Nepomuk::StrigiService::simpleUserStatusString() const
+{
+    return userStatusString( true );
+}
+
+
+QString Nepomuk::StrigiService::userStatusString( bool simple ) const
+{
     bool indexing = m_indexScheduler->isIndexing();
     bool suspended = m_indexScheduler->isSuspended();
     QString folder = m_indexScheduler->currentFolder();
 
-    if ( suspended )
+    if ( suspended ) {
         return i18nc( "@info:status", "File indexer is suspended" );
-    else if ( indexing )
-        return i18nc( "@info:status", "Strigi is currently indexing files in folder %1", folder );
-    else if ( m_fsWatcher->status() == FileSystemWatcher::Checking )
-        return i18nc( "@info:status", "Checking file system for new files" );
-    else
+    }
+    else if ( indexing ) {
+        if ( folder.isEmpty() || simple )
+            return i18nc( "@info:status", "Strigi is currently indexing files" );
+        else
+            return i18nc( "@info:status", "Strigi is currently indexing files in folder %1", folder );
+    }
+    else {
         return i18nc( "@info:status", "File indexer is idle" );
+    }
 }
 
 
 bool Nepomuk::StrigiService::isIdle() const
 {
-    return ( !m_indexScheduler->isIndexing() && m_fsWatcher->status() == FileSystemWatcher::Idle );
+    return ( !m_indexScheduler->isIndexing() );
 }
 
 
@@ -186,11 +184,9 @@ void Nepomuk::StrigiService::setSuspended( bool suspend )
 {
     if ( suspend ) {
         m_indexScheduler->suspend();
-        m_fsWatcher->suspend();
     }
     else {
         m_indexScheduler->resume();
-        m_fsWatcher->resume();
     }
 }
 
diff --git a/nepomuk/services/strigi/strigiservice.h b/nepomuk/services/strigi/strigiservice.h
index 168d9a3..845cd24 100644
--- a/nepomuk/services/strigi/strigiservice.h
+++ b/nepomuk/services/strigi/strigiservice.h
@@ -26,7 +26,6 @@
 namespace Strigi {
     class IndexManager;
 }
-class FileSystemWatcher;
 
 namespace Nepomuk {
 
@@ -50,24 +49,30 @@ namespace Nepomuk {
 
     public Q_SLOTS:
         /**
-         * \return A user readable status string
+         * \return A user readable status string. Includes the currently indexed folder.
          */
         QString userStatusString() const;
+
+        /**
+         * Simplified status string without details.
+         */
+        QString simpleUserStatusString() const;
         bool isIdle() const;
         void setSuspended( bool );
         bool isSuspended() const;
 
     private Q_SLOTS:
+        void finishInitialization();
         void updateWatches();
-        void slotDirDirty( const QString& );
+        void slotIdleTimeoutReached();
+        void slotIdleTimerResume();
 
     private:
         void updateStrigiConfig();
+        QString userStatusString( bool simple ) const;
 
         Strigi::IndexManager* m_indexManager;
         IndexScheduler* m_indexScheduler;
-
-        FileSystemWatcher* m_fsWatcher;
     };
 }
 
diff --git a/nepomuk/services/strigi/strigiserviceadaptor.cpp b/nepomuk/services/strigi/strigiserviceadaptor.cpp
index 1de350d..55194d2 100644
--- a/nepomuk/services/strigi/strigiserviceadaptor.cpp
+++ b/nepomuk/services/strigi/strigiserviceadaptor.cpp
@@ -27,6 +27,7 @@
 #include <QtCore/QUrl>
 #include <QtCore/QDateTime>
 #include <QtCore/QFile>
+#include <QtCore/QFileInfo>
 #include <QtCore/QDataStream>
 
 #include <KDebug>
@@ -72,6 +73,12 @@ QString Nepomuk::StrigiServiceAdaptor::currentFolder()
 }
 
 
+QString Nepomuk::StrigiServiceAdaptor::currentFile()
+{
+    return m_service->indexScheduler()->currentFile();
+}
+
+
 void Nepomuk::StrigiServiceAdaptor::resume()
 {
     // handle method call org.kde.nepomuk.Strigi.resume
@@ -88,8 +95,17 @@ void Nepomuk::StrigiServiceAdaptor::suspend()
 
 void Nepomuk::StrigiServiceAdaptor::updateFolder( const QString& path, bool forced )
 {
-    if ( StrigiServiceConfig::self()->shouldFolderBeIndexed( path ) )
-        m_service->indexScheduler()->updateDir( path, forced );
+    QFileInfo info( path );
+    if ( info.exists() ) {
+        QString dirPath;
+        if ( info.isDir() )
+            dirPath = info.absoluteFilePath();
+        else
+            dirPath = info.absolutePath();
+
+        if ( StrigiServiceConfig::self()->shouldFolderBeIndexed( dirPath ) )
+            m_service->indexScheduler()->updateDir( dirPath, forced );
+    }
 }
 
 
@@ -101,7 +117,22 @@ void Nepomuk::StrigiServiceAdaptor::updateAllFolders( bool forced )
 
 void Nepomuk::StrigiServiceAdaptor::indexFolder( const QString& path, bool forced )
 {
-    m_service->indexScheduler()->updateDir( path, forced );
+    QFileInfo info( path );
+    if ( info.exists() ) {
+        QString dirPath;
+        if ( info.isDir() )
+            dirPath = info.absoluteFilePath();
+        else
+            dirPath = info.absolutePath();
+
+        m_service->indexScheduler()->updateDir( dirPath, forced );
+    }
+}
+
+
+void Nepomuk::StrigiServiceAdaptor::indexFile( const QString& path )
+{
+    m_service->indexScheduler()->analyzeFile( path );
 }
 
 
diff --git a/nepomuk/services/strigi/strigiserviceadaptor.h b/nepomuk/services/strigi/strigiserviceadaptor.h
index fef98d5..73edc39 100644
--- a/nepomuk/services/strigi/strigiserviceadaptor.h
+++ b/nepomuk/services/strigi/strigiserviceadaptor.h
@@ -43,6 +43,9 @@ namespace Nepomuk {
                     "    <method name=\"currentFolder\">\n"
                     "      <arg direction=\"out\" type=\"s\"/>\n"
                     "    </method>\n"
+                    "    <method name=\"currentFile\">\n"
+                    "      <arg direction=\"out\" type=\"s\"/>\n"
+                    "    </method>\n"
                     "    <method name=\"suspend\"/>\n"
                     "    <method name=\"resume\"/>\n"
                     "    <method name=\"updateFolder\">\n"
@@ -56,6 +59,9 @@ namespace Nepomuk {
                     "      <arg direction=\"in\" type=\"s\" name=\"path\"/>\n"
                     "      <arg direction=\"in\" type=\"b\" name=\"forced\"/>\n"
                     "    </method>\n"
+                    "    <method name=\"indexFile\">\n"
+                    "      <arg direction=\"in\" type=\"s\" name=\"path\"/>\n"
+                    "    </method>\n"
                     "    <method name=\"analyzeResource\">\n"
                     "      <arg direction=\"in\" type=\"s\" name=\"uri\"/>\n"
                     "      <arg direction=\"in\" type=\"u\" name=\"lastModificationDate\"/>\n"
@@ -86,6 +92,7 @@ namespace Nepomuk {
         bool isIndexing();
         bool isSuspended();
         QString currentFolder();
+        QString currentFile();
         void resume();
         void suspend();
 
@@ -104,6 +111,11 @@ namespace Nepomuk {
          */
         void indexFolder( const QString& path, bool forced );
 
+        /**
+         * Index a specific file
+         */
+        void indexFile( const QString& path );
+
         void analyzeResource( const QString& uri, uint mTime, const QByteArray& data );
         void analyzeResourceFromTempFileAndDeleteTempFile( const QString& uri, uint mTime, const QString& tmpFile );
         QString userStatusString() const;
diff --git a/nepomuk/services/strigi/strigiserviceconfig.cpp b/nepomuk/services/strigi/strigiserviceconfig.cpp
index 7c496be..48c9cf7 100644
--- a/nepomuk/services/strigi/strigiserviceconfig.cpp
+++ b/nepomuk/services/strigi/strigiserviceconfig.cpp
@@ -17,6 +17,7 @@
 */
 
 #include "strigiserviceconfig.h"
+#include "removablestorageserviceinterface.h"
 #include "strigiservicedefaults.h"
 
 #include <QtCore/QStringList>
@@ -197,7 +198,7 @@ namespace {
         bool included = false;
         for ( int i = 0; i < folders.count(); ++i ) {
             if ( f != folders[i].first &&
-                 f.startsWith( folders[i].first ) )
+                 f.startsWith( KUrl( folders[i].first ).path( KUrl::AddTrailingSlash ) ) )
                 included = folders[i].second;
         }
         return included == include;
@@ -240,6 +241,11 @@ namespace {
 void Nepomuk::StrigiServiceConfig::buildFolderCache()
 {
     QStringList includeFoldersPlain = m_config.group( "General" ).readPathEntry( "folders", QStringList() << QDir::homePath() );
+    org::kde::nepomuk::RemovableStorage removableStorageService( "org.kde.nepomuk.services.removablestorageservice",
+                                                                 "/removablestorageservice",
+                                                                 QDBusConnection::sessionBus() );
+    if ( removableStorageService.isValid() )
+        includeFoldersPlain << removableStorageService.currentlyMountedAndIndexed();
     QStringList excludeFoldersPlain = m_config.group( "General" ).readPathEntry( "exclude folders", QStringList() );;
 
     m_folderCache.clear();
diff --git a/nepomuk/services/strigi/systray.cpp b/nepomuk/services/strigi/systray.cpp
index 1e2cab9..5baadf3 100644
--- a/nepomuk/services/strigi/systray.cpp
+++ b/nepomuk/services/strigi/systray.cpp
@@ -82,7 +82,7 @@ void Nepomuk::SystemTray::slotUpdateStrigiStatus()
         setStatus( newStatus );
     }
 
-    QString statusString = m_service->userStatusString();
+    QString statusString = m_service->simpleUserStatusString();
     if ( statusString != m_prevStatus ) {
         m_prevStatus = statusString;
         setToolTip("nepomuk", i18n("Search Service"), statusString );
diff --git a/nepomuk/servicestub/CMakeLists.txt b/nepomuk/servicestub/CMakeLists.txt
index b009528..272ab41 100644
--- a/nepomuk/servicestub/CMakeLists.txt
+++ b/nepomuk/servicestub/CMakeLists.txt
@@ -12,6 +12,7 @@ include_directories(
 set(servicestub_SRCS
   main.cpp
   servicecontrol.cpp
+  priority.cpp
 )
 
 qt4_add_dbus_adaptor(servicestub_SRCS
diff --git a/nepomuk/servicestub/main.cpp b/nepomuk/servicestub/main.cpp
index 9be89ac..23b1f74 100644
--- a/nepomuk/servicestub/main.cpp
+++ b/nepomuk/servicestub/main.cpp
@@ -23,6 +23,7 @@
 #include <KService>
 #include <KServiceTypeTrader>
 #include <KDebug>
+#include <KApplication>
 
 #include <QtCore/QTextStream>
 #include <QtCore/QTimer>
@@ -34,6 +35,7 @@
 #include <stdio.h>
 
 #include "servicecontrol.h"
+#include "priority.h"
 
 namespace {
 #ifndef Q_OS_WIN
@@ -80,10 +82,6 @@ int main( int argc, char** argv )
 
     KCmdLineArgs::init( argc, argv, &aboutData );
 
-    QApplication app( argc, argv );
-    installSignalHandler();
-    QApplication::setQuitOnLastWindowClosed( false );
-
     // FIXME: set the proper KConfig rc name using the service name
 
     KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
@@ -100,7 +98,10 @@ int main( int argc, char** argv )
     args->clear();
 
     aboutData.setAppName( serviceName.toLocal8Bit() );
-    KComponentData compData( aboutData );
+    KApplication app( true /* The strigi service actually needs a GUI at the moment */ );
+    app.disableSessionManagement();
+    installSignalHandler();
+    QApplication::setQuitOnLastWindowClosed( false );
 
 
     // check if NepomukServer is running
@@ -140,6 +141,18 @@ int main( int argc, char** argv )
     }
 
 
+    // Lower our priority by default which makes sense for most services since Nepomuk
+    // does not want to get in the way of the user
+    // TODO: make it configurable
+    // ====================================
+    if ( !lowerPriority() )
+        kDebug() << "Failed to lower priority.";
+    if ( !lowerSchedulingPriority() )
+        kDebug() << "Failed to lower scheduling priority.";
+    if ( !lowerIOPriority() )
+        kDebug() << "Failed to lower io priority.";
+
+
     // register the service control
     // ====================================
     Nepomuk::ServiceControl* control = new Nepomuk::ServiceControl( serviceName, service, &app );
diff --git a/nepomuk/servicestub/priority.cpp b/nepomuk/servicestub/priority.cpp
new file mode 100644
index 0000000..1c4e568
--- /dev/null
+++ b/nepomuk/servicestub/priority.cpp
@@ -0,0 +1,105 @@
+/* This file is part of the KDE Project
+   Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
+
+   Parts of this file are based on code from Strigi
+   Copyright (C) 2006-2007 Jos van den Oever <jos@vandenoever.info>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License version 2 as published by the Free Software Foundation.
+
+   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 "priority.h"
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <QtCore/QDebug>
+
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <unistd.h>
+#ifndef _WIN32
+#include <sys/syscall.h>
+#include <errno.h>
+
+#include <sched.h>
+#endif
+
+#ifdef SYS_ioprio_set
+namespace {
+#ifndef IOPRIO_CLASS_IDLE
+    enum {
+        IOPRIO_CLASS_NONE,
+        IOPRIO_CLASS_RT,
+        IOPRIO_CLASS_BE,
+        IOPRIO_CLASS_IDLE
+    };
+#endif
+
+#ifndef IOPRIO_WHO_PROCESS
+    enum {
+        IOPRIO_WHO_PROCESS = 1,
+        IOPRIO_WHO_PGRP,
+        IOPRIO_WHO_USER
+    };
+#endif
+
+#ifndef IOPRIO_CLASS_SHIFT
+    const int IOPRIO_CLASS_SHIFT = 13;
+#endif
+}
+#endif
+
+
+bool lowerIOPriority()
+{
+#ifdef SYS_ioprio_set
+    if ( syscall( SYS_ioprio_set, IOPRIO_WHO_PROCESS, 0, IOPRIO_CLASS_IDLE<<IOPRIO_CLASS_SHIFT ) < 0 ) {
+        qDebug( "cannot set io scheduling to idle (%s). Trying best effort.\n",  strerror( errno ));
+        if ( syscall( SYS_ioprio_set, IOPRIO_WHO_PROCESS, 0, 7|IOPRIO_CLASS_BE<<IOPRIO_CLASS_SHIFT ) < 0 ) {
+            qDebug( "cannot set io scheduling to best effort.\n");
+            return false;
+        }
+    }
+    return true;
+#else
+    return false;
+#endif
+}
+
+
+bool lowerPriority()
+{
+#ifndef Q_OS_WIN
+    return !setpriority( PRIO_PROCESS, 0, 19 );
+#else
+    return false;
+#endif
+}
+
+
+// FIXME: is this really useful? Should we better use SCHED_IDLE?
+bool lowerSchedulingPriority()
+{
+#ifdef SCHED_BATCH
+    struct sched_param param;
+    memset( &param, 0, sizeof(param) );
+    param.sched_priority = 0;
+    return !sched_setscheduler( 0, SCHED_BATCH, &param );
+#else
+    return false;
+#endif
+}
diff --git a/nepomuk/servicestub/priority.h b/nepomuk/servicestub/priority.h
new file mode 100644
index 0000000..2f4ea1d
--- /dev/null
+++ b/nepomuk/servicestub/priority.h
@@ -0,0 +1,26 @@
+/* This file is part of the KDE Project
+   Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License version 2 as published by the Free Software Foundation.
+
+   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_LINUX_PRIORITY_H_
+#define _NEPOMUK_LINUX_PRIORITY_H_
+
+bool lowerIOPriority();
+bool lowerSchedulingPriority();
+bool lowerPriority();
+
+#endif // _NEPOMUK_LINUX_PRIORITY_H_
diff --git a/nepomuk/strigibackend/CMakeLists.txt b/nepomuk/strigibackend/CMakeLists.txt
index a6e74a7..a7fd079 100644
--- a/nepomuk/strigibackend/CMakeLists.txt
+++ b/nepomuk/strigibackend/CMakeLists.txt
@@ -15,6 +15,11 @@ set( strigi_nepomuk_indexer_SRCS
 )
 
 soprano_add_ontology(strigi_nepomuk_indexer_SRCS
+  ${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nepomuk/nrl.trig
+  "NRL"
+  "Nepomuk::Vocabulary"
+  "trig")
+soprano_add_ontology(strigi_nepomuk_indexer_SRCS
   ${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nie/nfo.trig
   "NFO"
   "Nepomuk::Vocabulary"
diff --git a/nepomuk/strigibackend/nepomukindexwriter.cpp b/nepomuk/strigibackend/nepomukindexwriter.cpp
index 6a12162..017d86d 100644
--- a/nepomuk/strigibackend/nepomukindexwriter.cpp
+++ b/nepomuk/strigibackend/nepomukindexwriter.cpp
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2007-2009 Sebastian Trueg <trueg@kde.org>
+  Copyright (C) 2007-2010 Sebastian Trueg <trueg@kde.org>
 
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
@@ -21,6 +21,7 @@
 #include "util.h"
 #include "nfo.h"
 #include "nie.h"
+#include "nrl.h"
 
 #include <Soprano/Soprano>
 #include <Soprano/Vocabulary/RDF>
@@ -127,11 +128,14 @@ namespace {
     class FileMetaData
     {
     public:
-        FileMetaData( const KUrl& url );
+        FileMetaData( const Strigi::AnalysisResult* idx );
 
         /// stores basic data including the nie:url and the nrl:GraphMetadata in \p model
         void storeBasicData( Soprano::Model* model );
 
+        /// map a blank node to a resource
+        QUrl mapNode( const std::string& s );
+
         /// The resource URI
         QUrl resourceUri;
 
@@ -147,8 +151,12 @@ namespace {
         /// a buffer for all plain-text content generated by strigi
         std::string content;
 
+    private:
+        /// The Strigi result
+        const Strigi::AnalysisResult* m_analysisResult;
+
         /// mapping from blank nodes used in addTriplet to our urns
-        QMap<std::string, QUrl> blankNodeMap;
+        QMap<std::string, QUrl> m_blankNodeMap;
     };
 
     class RegisteredFieldData
@@ -170,10 +178,12 @@ namespace {
         bool isRdfType;
     };
 
-    FileMetaData::FileMetaData( const KUrl& url )
-        : fileUrl( url ),
-          fileInfo( url.toLocalFile() )
+    FileMetaData::FileMetaData( const Strigi::AnalysisResult* idx )
+        : m_analysisResult( idx )
     {
+        fileUrl = createFileUrl( idx );
+        fileInfo = fileUrl.toLocalFile();
+
         // determine the resource URI by using Nepomuk::Resource's power
         // this will automatically find previous uses of the file in question
         // with backwards compatibility
@@ -183,6 +193,27 @@ namespace {
         context = Nepomuk::ResourceManager::instance()->generateUniqueUri( "ctx" );
     }
 
+    QUrl FileMetaData::mapNode( const std::string& s )
+    {
+        if ( s[0] == ':' ) {
+            if( m_blankNodeMap.contains( s ) ) {
+                return m_blankNodeMap[s];
+            }
+            else {
+                QUrl urn = Nepomuk::ResourceManager::instance()->generateUniqueUri( QString() );
+                m_blankNodeMap.insert( s, urn );
+                return urn;
+            }
+        }
+        // special case to properly handle nie:isPartOf relations created for containers
+        else if ( s == m_analysisResult->path() ) {
+            return resourceUri;
+        }
+        else {
+            return QUrl::fromEncoded( s.c_str() );
+        }
+    }
+
     void FileMetaData::storeBasicData( Soprano::Model* model )
     {
         model->addStatement( resourceUri, Nepomuk::Vocabulary::NIE::url(), fileUrl, context );
@@ -206,7 +237,7 @@ namespace {
         QUrl metaDataContext = Nepomuk::ResourceManager::instance()->generateUniqueUri( "ctx" );
         model->addStatement( context,
                              Vocabulary::RDF::type(),
-                             Vocabulary::NRL::InstanceBase(),
+                             Nepomuk::Vocabulary::NRL::DiscardableInstanceBase(),
                              metaDataContext );
         model->addStatement( context,
                              Vocabulary::NAO::created(),
@@ -218,10 +249,10 @@ namespace {
                              metaDataContext );
         model->addStatement( metaDataContext,
                              Vocabulary::RDF::type(),
-                             Vocabulary::NRL::GraphMetadata(),
+                             Nepomuk::Vocabulary::NRL::GraphMetadata(),
                              metaDataContext );
         model->addStatement( metaDataContext,
-                             Vocabulary::NRL::coreGraphMetadataFor(),
+                             Nepomuk::Vocabulary::NRL::coreGraphMetadataFor(),
                              context,
                              metaDataContext );
     }
@@ -272,22 +303,6 @@ public:
         }
     }
 
-    QUrl mapNode( FileMetaData* fmd, const std::string& s ) {
-        if ( s[0] == ':' ) {
-            if( fmd->blankNodeMap.contains( s ) ) {
-                return fmd->blankNodeMap[s];
-            }
-            else {
-                QUrl urn = Nepomuk::ResourceManager::instance()->generateUniqueUri( QString() );
-                fmd->blankNodeMap.insert( s, urn );
-                return urn;
-            }
-        }
-        else {
-            return QUrl::fromEncoded( s.c_str() );
-        }
-    }
-
     Soprano::Model* repository;
 
     //
@@ -355,7 +370,7 @@ void Strigi::NepomukIndexWriter::startAnalysis( const AnalysisResult* idx )
     }
 
     // create the file data used during the analysis
-    FileMetaData* data = new FileMetaData( createFileUrl( idx ) );
+    FileMetaData* data = new FileMetaData( idx );
 
     // remove previously indexed data
     removeIndexedData( data->resourceUri, data->fileUrl );
@@ -449,7 +464,7 @@ void Strigi::NepomukIndexWriter::addValue( const AnalysisResult* idx,
             if ( value[0] == ':' ) {
                 Nepomuk::Types::Property property( rfd->property );
                 if ( property.range().isValid() ) {
-                    statement.setObject( d->mapNode( md, value ) );
+                    statement.setObject( md->mapNode( value ) );
                 }
             }
         }
@@ -545,11 +560,11 @@ void Strigi::NepomukIndexWriter::addTriplet( const std::string& s,
 
     FileMetaData* md = fileDataForResult( d->currentResultStack.top() );
 
-    QUrl subject = d->mapNode( md, s );
-    Nepomuk::Types::Property property( d->mapNode( md, p ) );
+    QUrl subject = md->mapNode( s );
+    Nepomuk::Types::Property property( md->mapNode( p ) );
     Soprano::Node object;
     if ( property.range().isValid() )
-        object = d->mapNode( md, o );
+        object = md->mapNode( o );
     else
         object = Soprano::LiteralValue::fromString( QString::fromUtf8( o.c_str() ), property.literalRangeType().dataTypeUri() );
 
-- 
1.7.3.4