diff -Naur nepomuk/CMakeLists.txt nepomuk/CMakeLists.txt --- nepomuk/CMakeLists.txt 2008-06-10 13:41:01.000000000 +0200 +++ nepomuk/CMakeLists.txt 2008-09-01 14:33:17.000000000 +0200 @@ -16,7 +16,6 @@ endif(CLucene_FOUND AND SopranoIndex_FOUND) # ----------------------------- -add_subdirectory(common) add_subdirectory(server) add_subdirectory(kcm) add_subdirectory(services) diff -Naur nepomuk/common/CMakeLists.txt nepomuk/common/CMakeLists.txt --- nepomuk/common/CMakeLists.txt 2008-04-02 14:18:19.000000000 +0200 +++ nepomuk/common/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,4 +0,0 @@ -project(nepomukcommon) - -configure_file(nepomukstrigi-config.h.cmake - ${CMAKE_CURRENT_BINARY_DIR}/nepomukstrigi-config.h) diff -Naur nepomuk/common/nepomukstrigi-config.h.cmake nepomuk/common/nepomukstrigi-config.h.cmake --- nepomuk/common/nepomukstrigi-config.h.cmake 2008-04-02 14:18:19.000000000 +0200 +++ nepomuk/common/nepomukstrigi-config.h.cmake 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -#cmakedefine HAVE_STRIGI_SOPRANO_BACKEND diff -Naur nepomuk/common/strigiconfigfile.cpp nepomuk/common/strigiconfigfile.cpp --- nepomuk/common/strigiconfigfile.cpp 2008-05-07 11:05:22.000000000 +0200 +++ nepomuk/common/strigiconfigfile.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,380 +0,0 @@ -/* - * This file is part of the Nepomuk KDE project. - * Copyright (C) 2006-2007 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 "strigiconfigfile.h" -#include "nepomukstrigi-config.h" - -#include <QtCore/QFile> -#include <QtCore/QTextStream> -#include <QtCore/QDir> -#include <QtXml/QDomDocument> -#include <QtXml/QDomElement> - -#include <KDebug> -#include <KStandardDirs> - - -namespace { - bool convertBooleanXsdValue( const QString& value ) { - return( value.toLower() == QLatin1String( "true" ) || - value.toLower() == QLatin1String( "1" ) ); - } -} - - -Nepomuk::StrigiConfigFile::StrigiConfigFile() -{ - reset(); -} - - -Nepomuk::StrigiConfigFile::StrigiConfigFile( const QString& filename ) -{ - reset(); - setFilename( filename ); -} - - -Nepomuk::StrigiConfigFile::~StrigiConfigFile() -{ -} - - -void Nepomuk::StrigiConfigFile::setFilename( const QString& filename ) -{ - m_filename = filename; -} - - -void Nepomuk::StrigiConfigFile::reset() -{ - m_useDBus = true; - m_repositories.clear(); - m_excludeFilters.clear(); - m_includeFilters.clear(); -} - - -bool Nepomuk::StrigiConfigFile::load() -{ - kDebug() << m_filename; - - QFile file( m_filename ); - if ( file.open( QIODevice::ReadOnly ) ) { - QDomDocument doc; - if ( doc.setContent( &file ) ) { - return readConfig( doc.documentElement() ); - } - else { - kDebug() << "Failed to parse" << m_filename; - return false; - } - } - else { - kDebug() << "Could not open file" << m_filename; - return false; - } -} - - -bool Nepomuk::StrigiConfigFile::readConfig( const QDomElement& rootElement ) -{ - if ( rootElement.tagName() != "strigiDaemonConfiguration" ) { - kDebug() << "Invalid configuration root tag:" << rootElement.tagName(); - return false; - } - - m_useDBus = convertBooleanXsdValue( rootElement.attribute( "useDBus", QLatin1String( "1" ) ) ); - - // read repository - QDomElement repoElem = rootElement.firstChildElement( "repository" ); - while ( !repoElem.isNull() ) { - Repository repo = readRepositoryConfig( repoElem ); - if ( repo.isValid() ) - addRepository( repo ); - repoElem = repoElem.nextSiblingElement( "repository" ); - } - - // read filters - return readFilterConfig( rootElement.firstChildElement( "filters" ) ); -} - - -Nepomuk::StrigiConfigFile::Repository Nepomuk::StrigiConfigFile::readRepositoryConfig( const QDomElement& repositoryElement ) -{ - Repository repo; - - QDomNamedNodeMap attributes = repositoryElement.attributes(); - - // read repository configuration - for ( int i = 0; i < attributes.size(); ++i ) { - QDomNode attributeNode = attributes.item( i ); - QString attributeName = attributeNode.nodeName(); - QString attributeValue = attributeNode.nodeValue(); - if ( attributeName == "type" ) { - repo.setType( attributeValue ); - } - else if ( attributeName == "name" ) { - repo.setName( attributeValue ); - } - else if ( attributeName == "indexdir" ) { - repo.setIndexDir( attributeValue ); - } - else if ( attributeName == "writeable" ) { - repo.setWriteable( convertBooleanXsdValue( attributeValue ) ); - } - else if ( attributeName == "urlbase" ) { - repo.setUrlBase( attributeValue ); - } - else if ( attributeName == "pollingInterval" ) { - repo.setPollingInterval( attributeValue.toInt() ); - } - else { - kDebug() << "Unknown config entry" << attributeName; - } - } - - // read indexed dirs - QDomElement pathElement = repositoryElement.firstChildElement( "path" ); - while ( !pathElement.isNull() ) { - QString path = pathElement.attribute( "path" ); - if ( !path.isEmpty() ) - repo.addIndexedDirectory( path ); - pathElement = pathElement.nextSiblingElement( "path" ); - } - - return repo; -} - - -bool Nepomuk::StrigiConfigFile::readFilterConfig( const QDomElement& filtersElement ) -{ - QDomElement filterElement = filtersElement.firstChildElement( "filter" ); - - while ( !filterElement.isNull() ) { - QString pattern = filterElement.attribute( "pattern" ); - QString inExclude = filterElement.attribute( "include" ); - if ( !pattern.isEmpty() && !inExclude.isEmpty() ) { - if ( convertBooleanXsdValue( inExclude ) ) - m_includeFilters << pattern; - else - m_excludeFilters << pattern; - } - else { - kDebug() << "Invalid filter rule."; - return false; - } - - filterElement = filterElement.nextSiblingElement( "filter" ); - } - - return true; -} - - -bool Nepomuk::StrigiConfigFile::save() -{ - kDebug() << m_filename; - - QDomDocument doc; - QDomElement rootElement = doc.createElement( "strigiDaemonConfiguration" ); - rootElement.setAttribute( "useDBus", useDBus() ? QLatin1String( "1" ) : QLatin1String( "0" ) ); - doc.appendChild( rootElement ); - - // save repositories - foreach( const Repository &repo, m_repositories ) { - QDomElement repoElem = doc.createElement( "repository" ); - repoElem.setAttribute( "name", repo.name() ); - repoElem.setAttribute( "type", repo.type() ); - repoElem.setAttribute( "indexdir", repo.indexDir() ); - repoElem.setAttribute( "writeable", repo.writeable() ? QLatin1String( "1" ) : QLatin1String( "0" ) ); - repoElem.setAttribute( "urlbase", repo.urlBase() ); - repoElem.setAttribute( "pollingInterval", QString::number( repo.pollingInterval() ) ); - - // add paths - foreach( const QString &path, repo.indexedDirectories() ) { - QDomElement pathElem = doc.createElement( "path" ); - pathElem.setAttribute( "path", path ); - repoElem.appendChild( pathElem ); - } - - rootElement.appendChild( repoElem ); - } - - // save filters - QDomElement filtersElem = doc.createElement( "filters" ); - rootElement.appendChild( filtersElem ); - foreach( const QString &filter, m_includeFilters ) { - QDomElement filterElem = doc.createElement( "filter" ); - filterElem.setAttribute( "pattern", filter ); - filterElem.setAttribute( "include", "1" ); - filtersElem.appendChild( filterElem ); - } - foreach( const QString &filter, m_excludeFilters ) { - QDomElement filterElem = doc.createElement( "filter" ); - filterElem.setAttribute( "pattern", filter ); - filterElem.setAttribute( "include", "0" ); - filtersElem.appendChild( filterElem ); - } - - // save to file - KStandardDirs::makeDir( m_filename.section( '/', 0, -2 ) ); - QFile f( m_filename ); - if ( f.open( QIODevice::WriteOnly ) ) { - QTextStream s( &f ); - s << doc; - return true; - } - else { - kDebug() << "Could not open" << m_filename << "for writing"; - return false; - } -} - - -bool Nepomuk::StrigiConfigFile::useDBus() const -{ - return m_useDBus; -} - - -QStringList Nepomuk::StrigiConfigFile::excludeFilters() const -{ - return m_excludeFilters; -} - - -QStringList Nepomuk::StrigiConfigFile::includeFilters() const -{ - return m_includeFilters; -} - - -QList<Nepomuk::StrigiConfigFile::Repository> Nepomuk::StrigiConfigFile::repositories() const -{ - return m_repositories; -} - - -Nepomuk::StrigiConfigFile::Repository& Nepomuk::StrigiConfigFile::defaultRepository() -{ - if ( m_repositories.isEmpty() ) { - Repository repo; - repo.setName( "localhost" ); // the default repository - repo.setWriteable( true ); - repo.setPollingInterval( 180 ); // default value copied from Strigi sources -#ifdef HAVE_STRIGI_SOPRANO_BACKEND - repo.setType( "sopranobackend" ); // our default -#else - repo.setType( "clucene" ); - repo.setIndexDir( QDir::homePath() + "/.strigi/clucene" ); -#endif - repo.addIndexedDirectory( QDir::homePath() ); - repo.addIndexedDirectory( QDir::homePath() + "/.kde" ); - addRepository( repo ); - - // in case there are no repositories and no filters we also create - // default filters - if ( m_includeFilters.isEmpty() && m_excludeFilters.isEmpty() ) { - // exclude hidden dirs and files - m_excludeFilters << ".*/" << ".*" << "*~" << "*.part"; - } - } - - return m_repositories.first(); -} - - -const Nepomuk::StrigiConfigFile::Repository& Nepomuk::StrigiConfigFile::defaultRepository() const -{ - return const_cast<StrigiConfigFile*>( this )->defaultRepository(); -} - - -void Nepomuk::StrigiConfigFile::setUseDBus( bool b ) -{ - m_useDBus = b; -} - -void Nepomuk::StrigiConfigFile::setExcludeFilters( const QStringList& filters ) -{ - m_excludeFilters = filters; -} - - -void Nepomuk::StrigiConfigFile::addExcludeFilter( const QString& filter ) -{ - m_excludeFilters << filter; -} - - -void Nepomuk::StrigiConfigFile::setIncludeFilters( const QStringList& filters ) -{ - m_includeFilters = filters; -} - - -void Nepomuk::StrigiConfigFile::addInludeFilter( const QString& filter ) -{ - m_includeFilters << filter; -} - -void Nepomuk::StrigiConfigFile::setRepositories( const QList<Repository>& repos ) -{ - m_repositories = repos; -} - - -void Nepomuk::StrigiConfigFile::addRepository( const Repository& repo ) -{ - m_repositories << repo; -} - - -QString Nepomuk::StrigiConfigFile::defaultStrigiConfigFilePath() -{ - return QDir::homePath() + "/.strigi/daemon.conf"; -} - - -QTextStream& operator<<( QTextStream& s, const Nepomuk::StrigiConfigFile& scf ) -{ - s << "useDBus: " << scf.useDBus() << endl - << "repositories:" << endl; - foreach( const Nepomuk::StrigiConfigFile::Repository &repo, scf.repositories() ) { - s << " " << repo.name() << ":" << endl - << " " << "type: " << repo.type() << endl - << " " << "indexdir: " << repo.indexDir() << endl - << " " << "writeable: " << repo.writeable() << endl - << " " << "urlbase: " << repo.urlBase() << endl - << " " << "paths: " << repo.indexedDirectories().join( ":" ) << endl; - } - s << "include filters:" << endl; - foreach( const QString &filter, scf.includeFilters() ) { - s << " " << filter << endl; - } - s << "exclude filters:" << endl; - foreach( const QString &filter, scf.excludeFilters() ) { - s << " " << filter << endl; - } - return s; -} - -#include "strigiconfigfile.moc" diff -Naur nepomuk/common/strigiconfigfile.h nepomuk/common/strigiconfigfile.h --- nepomuk/common/strigiconfigfile.h 2008-04-02 14:18:19.000000000 +0200 +++ nepomuk/common/strigiconfigfile.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,135 +0,0 @@ -/* - * This file is part of the Nepomuk KDE project. - * Copyright (C) 2006-2007 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 _NEPOMUK_STRIGI_CONFIG_H_ -#define _NEPOMUK_STRIGI_CONFIG_H_ - -#include <QtCore/QObject> -#include <QtCore/QStringList> - -class QDomElement; -class QTextStream; - -namespace Nepomuk { - /** - * Parser and writer class for Strigidaemon config - * files. - * - * The default Strigi config file can be found at - * ~/.strigi/daemon.conf. - */ - class StrigiConfigFile : public QObject - { - Q_OBJECT - - public: - StrigiConfigFile(); - StrigiConfigFile( const QString& filename ); - ~StrigiConfigFile(); - - void setFilename( const QString& filename ); - - bool load(); - bool save(); - - /** - * A Strigi repository. Normally there is only one. - */ - class Repository { - public: - QString name() const { return m_name; } - QString type() const { return m_type; } - QString indexDir() const { return m_indexDir; } - bool writeable() const { return m_writeable; } - QString urlBase() const { return m_urlBase; } - QStringList indexedDirectories() const { return m_indexedDirectories; } - int pollingInterval() const { return m_pollingInterval; } - - bool isValid() const { return !m_type.isEmpty(); } - - void setType( const QString& type ) { m_type = type; } - void setName( const QString& name ) { m_name = name; } - void setIndexDir( const QString& dir ) { m_indexDir = dir; } - void setWriteable( bool writeable ) { m_writeable = writeable; } - void setUrlBase( const QString& urlBase ) { m_urlBase = urlBase; } - void addIndexedDirectory( const QString& dir ) { m_indexedDirectories << dir; } - void setIndexedDirectories( const QStringList& dirs ) { m_indexedDirectories = dirs; } - void setPollingInterval( int pollingInterval ) { m_pollingInterval = pollingInterval; } - - private: - QString m_name; - QString m_type; - QString m_indexDir; - bool m_writeable; - QString m_urlBase; - QStringList m_indexedDirectories; - int m_pollingInterval; - }; - - bool useDBus() const; - QStringList excludeFilters() const; - QStringList includeFilters() const; - QList<Repository> repositories() const; - - /** - * In most cases (or even always) there is only - * one repository. This method will return the - * first repository in the list or create a default - * one and insert it if the list is empty. - * - * This will also create default filters if none are - * specified AND no repository is configured. - */ - Repository& defaultRepository(); - const Repository& defaultRepository() const; - - /** - * ~/.strigi/daemon.conf - */ - static QString defaultStrigiConfigFilePath(); - - public Q_SLOTS: - void reset(); - - void setUseDBus( bool b ); - void setExcludeFilters( const QStringList& filters ); - void addExcludeFilter( const QString& filter ); - void setIncludeFilters( const QStringList& filters ); - void addInludeFilter( const QString& filter ); - void setRepositories( const QList<Repository>& repos ); - void addRepository( const Repository& repo ); - - private: - bool readConfig( const QDomElement& ); - Repository readRepositoryConfig( const QDomElement& ); - bool readFilterConfig( const QDomElement& filterElement ); - - QString m_filename; - - bool m_useDBus; - QStringList m_excludeFilters; - QStringList m_includeFilters; - QList<Repository> m_repositories; - }; -} - -QTextStream& operator<<( QTextStream& s, const Nepomuk::StrigiConfigFile& scf ); - -#endif diff -Naur nepomuk/interfaces/CMakeLists.txt nepomuk/interfaces/CMakeLists.txt --- nepomuk/interfaces/CMakeLists.txt 2008-04-02 14:18:19.000000000 +0200 +++ nepomuk/interfaces/CMakeLists.txt 2008-09-01 14:33:17.000000000 +0200 @@ -2,5 +2,8 @@ org.kde.NepomukServer.xml org.kde.nepomuk.ServiceControl.xml org.kde.nepomuk.ServiceManager.xml + org.kde.nepomuk.Strigi.xml + org.kde.nepomuk.OntologyManager.xml + org.kde.nepomuk.Storage.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR} ) diff -Naur nepomuk/interfaces/org.kde.nepomuk.OntologyManager.xml nepomuk/interfaces/org.kde.nepomuk.OntologyManager.xml --- nepomuk/interfaces/org.kde.nepomuk.OntologyManager.xml 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/interfaces/org.kde.nepomuk.OntologyManager.xml 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,21 @@ +<!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.OntologyManager"> + <method name="findOntologyContext"> + <arg name="uri" type="s" direction="in" /> + <arg type="s" direction="out" /> + </method> + <method name="importOntology"> + <arg name="uri" type="s" direction="in" /> + </method> + <method name="updateLocalOntologies" /> + <signal name="ontologyUpdated"> + <arg name="uri" type="s" /> + </signal> + <signal name="ontologyUpdateFailed"> + <arg name="uri" type="s" /> + <arg name="errorString" type="s" /> + </signal> + </interface> +</node> diff -Naur nepomuk/interfaces/org.kde.nepomuk.Storage.xml nepomuk/interfaces/org.kde.nepomuk.Storage.xml --- nepomuk/interfaces/org.kde.nepomuk.Storage.xml 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/interfaces/org.kde.nepomuk.Storage.xml 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,12 @@ +<!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.Storage"> + <method name="optimize"> + <arg name="repoName" type="s" direction="in" /> + </method> + <method name="usedSopranoBackend"> + <arg name="backendName" type="s" direction="out" /> + </method> + </interface> +</node> diff -Naur nepomuk/interfaces/org.kde.nepomuk.Strigi.xml nepomuk/interfaces/org.kde.nepomuk.Strigi.xml --- nepomuk/interfaces/org.kde.nepomuk.Strigi.xml 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/interfaces/org.kde.nepomuk.Strigi.xml 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,32 @@ +<!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.Strigi"> + <method name="isIndexing"> + <arg type="b" direction="out" /> + </method> + <method name="isSuspended"> + <arg type="b" direction="out" /> + </method> + <method name="currentFolder"> + <arg type="s" direction="out" /> + </method> + <method name="suspend" /> + <method name="resume" /> + <method name="analyzeResource" > + <arg name="uri" direction="in" type="s" /> + <arg name="lastModificationDate" direction="in" type="u" /> + <arg name="data" direction="in" type="ay" /> + </method> + <method name="analyzeResourceFromTempFileAndDeleteTempFile" > + <arg name="uri" direction="in" type="s" /> + <arg name="lastModificationDate" direction="in" type="u" /> + <arg name="tmpFileName" direction="in" type="s" /> + </method> + <signal name="indexingStarted" /> + <signal name="indexingStopped" /> + <signal name="indexingFolder"> + <arg name="path" type="s" /> + </method> + </interface> +</node> diff -Naur nepomuk/kcm/CMakeLists.txt nepomuk/kcm/CMakeLists.txt --- nepomuk/kcm/CMakeLists.txt 2008-05-21 10:33:02.000000000 +0200 +++ nepomuk/kcm/CMakeLists.txt 2008-09-01 14:33:17.000000000 +0200 @@ -6,15 +6,15 @@ ${SOPRANO_INCLUDE_DIR} ${CMAKE_SOURCE_DIR} ${NEPOMUK_INCLUDE_DIR} - ${nepomukcommon_BINARY_DIR} ) set(kcmnepomuk_SRCS - ../common/strigiconfigfile.cpp nepomukserverkcm.cpp + folderselectionmodel.cpp ) qt4_add_dbus_interface(kcmnepomuk_SRCS ../interfaces/org.kde.NepomukServer.xml nepomukserverinterface) +qt4_add_dbus_interface(kcmnepomuk_SRCS ../interfaces/org.kde.nepomuk.Strigi.xml strigiserviceinterface) kde4_add_ui_files(kcmnepomuk_SRCS nepomukconfigwidget.ui) @@ -22,9 +22,9 @@ kde4_add_plugin(kcm_nepomuk ${kcmnepomuk_SRCS}) target_link_libraries(kcm_nepomuk - ${STRIGI_STRIGIQTDBUSCLIENT_LIBRARY} ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} + ${SOPRANO_LIBRARIES} ) # ----------------------------- diff -Naur nepomuk/kcm/folderselectionmodel.cpp nepomuk/kcm/folderselectionmodel.cpp --- nepomuk/kcm/folderselectionmodel.cpp 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/kcm/folderselectionmodel.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,156 @@ +/* This file is part of the KDE Project + Copyright (c) 2008 Sebastian Trueg <trueg@kde.org> + + Based on CollectionSetup.cpp from the Amarok project + (C) 2003 Scott Wheeler <wheeler@kde.org> + (C) 2004 Max Howell <max.howell@methylblue.com> + (C) 2004 Mark Kretschmann <markey@web.de> + (C) 2008 Seb Ruiz <ruiz@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 "folderselectionmodel.h" + +#include <QtCore/QDir> + + +FolderSelectionModel::FolderSelectionModel( QObject* parent ) + : QFileSystemModel( parent ), + m_recursive( true ) +{ + setFilter( QDir::AllDirs | QDir::NoDotAndDotDot ); +} + + +FolderSelectionModel::~FolderSelectionModel() +{ +} + + +Qt::ItemFlags FolderSelectionModel::flags( const QModelIndex &index ) const +{ + Qt::ItemFlags flags = QFileSystemModel::flags( index ); + const QString path = filePath( index ); + if( ( recursive() && ancestorChecked( path ) ) || isForbiddenPath( path ) ) + flags ^= Qt::ItemIsEnabled; //disabled! + + flags |= Qt::ItemIsUserCheckable; + + return flags; +} + + +QVariant FolderSelectionModel::data( const QModelIndex& index, int role ) const +{ + if( index.isValid() && index.column() == 0 && role == Qt::CheckStateRole ) + { + const QString path = filePath( index ); + if( recursive() && ancestorChecked( path ) ) + return Qt::Checked; // always set children of recursively checked parents to checked + if( isForbiddenPath( path ) ) + return Qt::Unchecked; // forbidden paths can never be checked + if ( !m_checked.contains( path ) && descendantChecked( path ) ) + return Qt::PartiallyChecked; + return m_checked.contains( path ) ? Qt::Checked : Qt::Unchecked; + } + return QFileSystemModel::data( index, role ); +} + + +bool FolderSelectionModel::setData( const QModelIndex& index, const QVariant& value, int role ) +{ + if( index.isValid() && index.column() == 0 && role == Qt::CheckStateRole ) + { + QString path = filePath( index ); + // store checked paths, remove unchecked paths + if( value.toInt() == Qt::Checked ) + m_checked.insert( path ); + else + m_checked.remove( path ); + return true; + } + return QFileSystemModel::setData( index, value, role ); +} + + +void FolderSelectionModel::setFolders( const QStringList &dirs ) +{ + m_checked.clear(); + foreach( const QString& dir, dirs ) { + m_checked.insert( dir ); + } +} + + +QStringList FolderSelectionModel::folders() const +{ + QStringList dirs = m_checked.toList(); + + qSort( dirs.begin(), dirs.end() ); + + // we need to remove any children of selected items as + // they are redundant when recursive mode is chosen + if( recursive() ) { + foreach( const QString& dir, dirs ) { + if( ancestorChecked( dir ) ) + dirs.removeAll( dir ); + } + } + + return dirs; +} + + +inline bool FolderSelectionModel::isForbiddenPath( const QString& path ) const +{ + // we need the trailing slash otherwise we could forbid "/dev-music" for example + QString _path = path.endsWith( "/" ) ? path : path + "/"; + return _path.startsWith( "/proc/" ) || _path.startsWith( "/dev/" ) || _path.startsWith( "/sys/" ); +} + + +bool FolderSelectionModel::ancestorChecked( const QString& path ) const +{ + foreach( const QString& element, m_checked ) { + if( path.startsWith( element ) && element != path ) + return true; + } + return false; +} + + +bool FolderSelectionModel::descendantChecked( const QString& path ) const +{ + foreach( const QString& element, m_checked ) { + if ( element.startsWith( path ) && element != path ) + return true; + } + return false; +} + + +bool FolderSelectionModel::recursive() const +{ + return m_recursive; +} + + +void FolderSelectionModel::setRecursive( bool r ) +{ + m_recursive = r; +} + +#include "folderselectionmodel.moc" diff -Naur nepomuk/kcm/folderselectionmodel.h nepomuk/kcm/folderselectionmodel.h --- nepomuk/kcm/folderselectionmodel.h 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/kcm/folderselectionmodel.h 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,61 @@ +/* This file is part of the KDE Project + Copyright (c) 2008 Sebastian Trueg <trueg@kde.org> + + Based on CollectionSetup.h from the Amarok project + (C) 2003 Scott Wheeler <wheeler@kde.org> + (C) 2004 Max Howell <max.howell@methylblue.com> + (C) 2004 Mark Kretschmann <markey@web.de> + (C) 2008 Seb Ruiz <ruiz@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 _FOLDER_SELECTION_MODEL_H_ +#define _FOLDER_SELECTION_MODEL_H_ + +#include <QtGui/QFileSystemModel> +#include <QtCore/QSet> + + +class FolderSelectionModel : public QFileSystemModel +{ + Q_OBJECT + +public: + FolderSelectionModel( QObject* parent = 0 ); + virtual ~FolderSelectionModel(); + + Qt::ItemFlags flags( const QModelIndex &index ) const; + QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const; + bool setData( const QModelIndex& index, const QVariant& value, int role = Qt::EditRole ); + + void setFolders( const QStringList &dirs ); // will clear m_checked before inserting new directories + QStringList folders() const; + + int columnCount( const QModelIndex& ) const { return 1; } + + bool recursive() const; + void setRecursive( bool r ); + +private: + bool ancestorChecked( const QString& path ) const; + bool descendantChecked( const QString& path ) const; + bool isForbiddenPath( const QString& path ) const; + + QSet<QString> m_checked; + bool m_recursive; +}; + +#endif diff -Naur nepomuk/kcm/kcm_nepomuk.desktop nepomuk/kcm/kcm_nepomuk.desktop --- nepomuk/kcm/kcm_nepomuk.desktop 2008-08-28 10:07:16.000000000 +0200 +++ nepomuk/kcm/kcm_nepomuk.desktop 2008-09-01 14:33:17.000000000 +0200 @@ -8,16 +8,27 @@ X-KDE-ParentApp=kcontrol X-KDE-System-Settings-Parent-Category=advanced-user-settings -Name=Nepomuk -Name[ar]=مشروع Nepomuk -Name[gu]=નેપોમુક -Name[ml]=നെപ്പോമുക് -Name[pa]=ਨਿਪੋਮੁਕ -Name[sr]=Непомук -Name[x-test]=xxNepomukxx +Name=Desktop Search +Name[et]=Töölauaotsing +Name[ga]=Cuardach Deisce +Name[gl]=Procura do escritorio +Name[gu]=ડેસ્કટોપ શોધ +Name[hr]=Pager na radnoj površini +Name[ja]=デスクトップ検索 +Name[km]=ស្វែងរកផ្ទៃតុ +Name[nb]=Skrivebordssøk +Name[nds]=Schriefdischsöök +Name[nn]=Skrivebordsøk +Name[pt]=Pesquisa no Ambiente de Trabalho +Name[pt_BR]=Pesquisa no Ambiente de Trabalho +Name[sl]=Namizno iskanje +Name[sv]=Skrivbordssökning +Name[te]=డెస్క్ టాప్ శోధన +Name[tr]=Masaüstü Araması +Name[uk]=Стільничний пошук +Name[zh_TW]=桌面搜尋 Comment=Nepomuk/Strigi Server Configuration Comment[af]=Nepomuk/Strigi bedienerkonfigurasie -Comment[ar]=اعداد خدمة Nepomuk/Strigi Comment[bg]=Настройване на Nepomuk/Strigi Comment[bn_IN]=Nepomuk/Strigi সার্ভার কনফিগারেশন Comment[ca]=Configuració del servidor Nepomuk/Strigi @@ -63,6 +74,7 @@ Comment[sr]=Постава сервера Непомука/Стригија Comment[sr@latin]=Postava servera Nepomuka/Strigija Comment[sv]=Tjänstinställning av Nepomuk- och Strigiserver +Comment[te]=Nepomuk/Strigi సేవిక ఆకృతీకరణ Comment[tg]=Танзимоти хидматгоҳи Nepomuk/Strigi Comment[th]=ปรับแต่งเซิร์ฟเวอร์ Nepomuk/Strigi Comment[tr]=Nepomuk/Strigi Sunucu Yapılandırması diff -Naur nepomuk/kcm/nepomukconfigwidget.ui nepomuk/kcm/nepomukconfigwidget.ui --- nepomuk/kcm/nepomukconfigwidget.ui 2008-04-23 17:51:26.000000000 +0200 +++ nepomuk/kcm/nepomukconfigwidget.ui 2008-09-01 14:33:17.000000000 +0200 @@ -2,14 +2,6 @@ <author>Sebastian Trueg</author> <class>NepomukConfigWidget</class> <widget class="QWidget" name="NepomukConfigWidget" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>366</width> - <height>300</height> - </rect> - </property> <layout class="QVBoxLayout" > <item> <widget class="QTabWidget" name="tabWidget" > @@ -20,7 +12,7 @@ <attribute name="title" > <string>Basic Settings</string> </attribute> - <layout class="QVBoxLayout" > + <layout class="QVBoxLayout" name="verticalLayout_2" > <item> <widget class="QGroupBox" name="groupBox_2" > <property name="title" > @@ -30,7 +22,7 @@ <item> <widget class="QLabel" name="label_3" > <property name="text" > - <string>Nepomuk Semantic Desktop enables tagging and rating of files integrated with the Strigi Desktop Search.</string> + <string>Nepomuk Semantic Desktop enables tagging and rating of files integrated with the Desktop Search.</string> </property> <property name="wordWrap" > <bool>true</bool> @@ -50,9 +42,9 @@ <item> <widget class="QGroupBox" name="groupBox" > <property name="title" > - <string>Strigi Desktop Search</string> + <string>Strigi Desktop File Indexer</string> </property> - <layout class="QVBoxLayout" > + <layout class="QVBoxLayout" name="verticalLayout" > <item> <widget class="QLabel" name="label_2" > <property name="text" > @@ -64,46 +56,49 @@ </widget> </item> <item> - <layout class="QHBoxLayout" > - <item> - <widget class="QCheckBox" name="m_checkEnableStrigi" > - <property name="text" > - <string>Enable Strigi Desktop Search</string> - </property> - </widget> - </item> + <widget class="QCheckBox" name="m_checkEnableStrigi" > + <property name="text" > + <string>Enable Strigi Desktop File Indexer</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout" > <item> - <spacer> + <spacer name="horizontalSpacer" > <property name="orientation" > <enum>Qt::Horizontal</enum> </property> - <property name="sizeHint" > + <property name="sizeType" > + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0" > <size> - <width>20</width> - <height>40</height> + <width>40</width> + <height>1</height> </size> </property> </spacer> </item> <item> - <layout class="QHBoxLayout" > - <item> - <widget class="KLed" native="1" name="m_strigiStatus" /> - </item> - <item> - <widget class="QLabel" name="m_strigiStatusLabel" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text" > - <string>Strigi not running</string> - </property> - </widget> - </item> - </layout> + <widget class="KSqueezedTextLabel" name="m_labelStrigiStatus" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Fixed" hsizetype="Expanding" > + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font" > + <font> + <weight>75</weight> + <italic>true</italic> + <bold>true</bold> + </font> + </property> + <property name="text" > + <string>KSqueezedTextLabel</string> + </property> + </widget> </item> </layout> </item> @@ -115,7 +110,7 @@ <property name="orientation" > <enum>Qt::Vertical</enum> </property> - <property name="sizeHint" > + <property name="sizeHint" stdset="0" > <size> <width>20</width> <height>40</height> @@ -129,21 +124,27 @@ <attribute name="title" > <string>Advanced Settings</string> </attribute> - <layout class="QVBoxLayout" > + <layout class="QHBoxLayout" name="horizontalLayout_2" > <item> - <widget class="KEditListBox" name="m_editStrigiFolders" > - <property name="toolTip" > - <string>The folders Strigi scans for indexable files</string> - </property> - <property name="whatsThis" > - <string><html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Select the folders that Strigi should scan for files to index. The files in these folders will be searchable through Strigi Desktop Search.</p></body></html></string> - </property> + <widget class="QGroupBox" name="groupBox_3" > <property name="title" > <string>Strigi Index Folders</string> </property> + <layout class="QVBoxLayout" name="verticalLayout_3" > + <item> + <widget class="QLabel" name="label" > + <property name="text" > + <string>Select the local folders that contain files to be indexed for fast desktop searches</string> + </property> + <property name="wordWrap" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QTreeView" name="m_viewIndexFolders" /> + </item> + </layout> </widget> </item> <item> @@ -159,19 +160,6 @@ </property> </widget> </item> - <item> - <spacer> - <property name="orientation" > - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" > - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> </layout> </widget> </widget> @@ -186,15 +174,14 @@ <container>1</container> </customwidget> <customwidget> - <class>KLed</class> - <extends>QWidget</extends> - <header>kled.h</header> + <class>KSqueezedTextLabel</class> + <extends>QLabel</extends> + <header>ksqueezedtextlabel.h</header> </customwidget> </customwidgets> <tabstops> <tabstop>tabWidget</tabstop> <tabstop>m_checkEnableNepomuk</tabstop> - <tabstop>m_checkEnableStrigi</tabstop> </tabstops> <resources/> <connections> diff -Naur nepomuk/kcm/nepomukserverkcm.cpp nepomuk/kcm/nepomukserverkcm.cpp --- nepomuk/kcm/nepomukserverkcm.cpp 2008-06-10 13:41:01.000000000 +0200 +++ nepomuk/kcm/nepomukserverkcm.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -18,7 +18,7 @@ #include "nepomukserverkcm.h" #include "nepomukserverinterface.h" -#include "../common/strigiconfigfile.h" +#include "folderselectionmodel.h" #include <KPluginFactory> #include <KPluginLoader> @@ -26,18 +26,31 @@ #include <KSharedConfig> #include <KLed> #include <KMessageBox> -#include <KUrlRequester> -#include <strigi/qtdbus/strigiclient.h> +#include <QtGui/QTreeView> + +#include <Soprano/PluginManager> K_PLUGIN_FACTORY( NepomukConfigModuleFactory, registerPlugin<Nepomuk::ServerConfigModule>(); ) K_EXPORT_PLUGIN( NepomukConfigModuleFactory("kcm_nepomuk", "nepomuk") ) +namespace { + QStringList defaultFolders() { + return QStringList() << QDir::homePath(); + } + + QStringList defaultExcludeFilters() { + return QStringList() << ".*/" << ".*" << "*~" << "*.part"; + } +} + + Nepomuk::ServerConfigModule::ServerConfigModule( QWidget* parent, const QVariantList& args ) : KCModule( NepomukConfigModuleFactory::componentData(), parent, args ), - m_serverInterface( "org.kde.NepomukServer", "/nepomukserver", QDBusConnection::sessionBus() ) + m_serverInterface( "org.kde.NepomukServer", "/nepomukserver", QDBusConnection::sessionBus() ), + m_strigiInterface( "org.kde.nepomuk.services.nepomukstrigiservice", "/nepomukstrigiservice", QDBusConnection::sessionBus() ) { KAboutData *about = new KAboutData( "kcm_nepomuk", 0, ki18n("Nepomuk Configuration Module"), @@ -48,20 +61,29 @@ setButtons(Apply|Default); setupUi( this ); - KUrlRequester* urlReq = new KUrlRequester( m_editStrigiFolders ); - urlReq->setMode( KFile::Directory|KFile::LocalOnly|KFile::ExistingOnly ); - KEditListBox::CustomEditor ce( urlReq, urlReq->lineEdit() ); - m_editStrigiFolders->setCustomEditor( ce ); + m_folderModel = new FolderSelectionModel( m_viewIndexFolders ); + m_viewIndexFolders->setModel( m_folderModel ); + m_viewIndexFolders->setHeaderHidden( true ); + m_viewIndexFolders->setRootIsDecorated( true ); + m_viewIndexFolders->setAnimated( true ); + m_viewIndexFolders->setRootIndex( m_folderModel->setRootPath( QDir::rootPath() ) ); connect( m_checkEnableStrigi, SIGNAL( toggled(bool) ), this, SLOT( changed() ) ); connect( m_checkEnableNepomuk, SIGNAL( toggled(bool) ), this, SLOT( changed() ) ); - connect( m_editStrigiFolders, SIGNAL( changed() ), + connect( m_folderModel, SIGNAL( dataChanged(const QModelIndex&, const QModelIndex&) ), this, SLOT( changed() ) ); connect( m_editStrigiExcludeFilters, SIGNAL( changed() ), this, SLOT( changed() ) ); + connect( &m_strigiInterface, SIGNAL( indexingStarted() ), + this, SLOT( slotUpdateStrigiStatus() ) ); + connect( &m_strigiInterface, SIGNAL( indexingStopped() ), + this, SLOT( slotUpdateStrigiStatus() ) ); + connect( &m_strigiInterface, SIGNAL( indexingFolder(QString) ), + this, SLOT( slotUpdateStrigiStatus() ) ); + load(); } @@ -73,7 +95,16 @@ void Nepomuk::ServerConfigModule::load() { - if ( m_serverInterface.isValid() ) { + bool sopranoBackendAvailable = !Soprano::PluginManager::instance()->allBackends().isEmpty(); + + m_checkEnableNepomuk->setEnabled( sopranoBackendAvailable ); + + if ( !sopranoBackendAvailable ) { + KMessageBox::sorry( this, + i18n( "No Soprano Database backend available. Please check your installation." ), + i18n( "Nepomuk cannot be started" ) ); + } + else if ( m_serverInterface.isValid() ) { m_checkEnableStrigi->setChecked( m_serverInterface.isStrigiEnabled().value() ); m_checkEnableNepomuk->setChecked( m_serverInterface.isNepomukEnabled().value() ); } @@ -85,30 +116,20 @@ KConfig config( "nepomukserverrc" ); m_checkEnableNepomuk->setChecked( config.group( "Basic Settings" ).readEntry( "Start Nepomuk", true ) ); - m_checkEnableStrigi->setChecked( config.group( "Service-nepomukstrigiservice" ).readEntry( "autostart", false ) ); + m_checkEnableStrigi->setChecked( config.group( "Service-nepomukstrigiservice" ).readEntry( "autostart", true ) ); } - if ( isStrigiRunning() ) { - StrigiClient strigiClient; - m_editStrigiFolders->setItems( strigiClient.getIndexedDirectories() ); - QList<QPair<bool, QString> > filters = strigiClient.getFilters(); - m_editStrigiExcludeFilters->clear(); - for( QList<QPair<bool, QString> >::const_iterator it = filters.constBegin(); - it != filters.constEnd(); ++it ) { - if ( !it->first ) { - m_editStrigiExcludeFilters->insertItem( it->second ); - } - // else: we simply drop include filters for now - } - } - else { - StrigiConfigFile strigiConfig( StrigiConfigFile::defaultStrigiConfigFilePath() ); - strigiConfig.load(); - m_editStrigiFolders->setItems( strigiConfig.defaultRepository().indexedDirectories() ); - m_editStrigiExcludeFilters->setItems( strigiConfig.excludeFilters() ); + KConfig strigiConfig( "nepomukstrigirc" ); + m_folderModel->setFolders( strigiConfig.group( "General" ).readPathEntry( "folders", defaultFolders() ) ); + m_editStrigiExcludeFilters->setItems( strigiConfig.group( "General" ).readEntry( "exclude filters", defaultExcludeFilters() ) ); + + // make sure that the tree is expanded to show all selected items + foreach( const QString& dir, m_folderModel->folders() ) { + QModelIndex index = m_folderModel->index( dir ); + m_viewIndexFolders->scrollTo( index, QAbstractItemView::EnsureVisible ); } - updateStrigiStatus(); + slotUpdateStrigiStatus(); } @@ -121,17 +142,9 @@ // 2. update Strigi config - StrigiConfigFile strigiConfig( StrigiConfigFile::defaultStrigiConfigFilePath() ); - strigiConfig.load(); - if ( m_checkEnableNepomuk->isChecked() ) { - strigiConfig.defaultRepository().setType( "sopranobackend" ); - } - else { - strigiConfig.defaultRepository().setType( "clucene" ); - } - strigiConfig.defaultRepository().setIndexedDirectories( m_editStrigiFolders->items() ); - strigiConfig.setExcludeFilters( m_editStrigiExcludeFilters->items() ); - strigiConfig.save(); + KConfig strigiConfig( "nepomukstrigirc" ); + strigiConfig.group( "General" ).writePathEntry( "folders", m_folderModel->folders() ); + strigiConfig.group( "General" ).writeEntry( "exclude filters", m_editStrigiExcludeFilters->items() ); // 3. update the current state of the nepomuk server @@ -146,66 +159,36 @@ i18n( "Nepomuk server not running" ) ); } - - // 4. update values in the running Strigi instance - // TODO: there should be a dbus method to re-read the config - // ----------------------------- - if ( m_checkEnableStrigi->isChecked() ) { - // give strigi some time to start - QTimer::singleShot( 2000, this, SLOT( updateStrigiSettingsInRunningInstance() ) ); - } - - // give strigi some time to start - QTimer::singleShot( 2000, this, SLOT( updateStrigiStatus() ) ); + slotUpdateStrigiStatus(); } void Nepomuk::ServerConfigModule::defaults() { - m_checkEnableStrigi->setChecked( false ); + m_checkEnableStrigi->setChecked( true ); m_checkEnableNepomuk->setChecked( true ); - // create Strigi default config - StrigiConfigFile defaultConfig; - m_editStrigiFolders->setItems( defaultConfig.defaultRepository().indexedDirectories() ); - m_editStrigiExcludeFilters->setItems( defaultConfig.excludeFilters() ); + m_editStrigiExcludeFilters->setItems( defaultExcludeFilters() ); + m_folderModel->setFolders( defaultFolders() ); } -void Nepomuk::ServerConfigModule::updateStrigiStatus() +void Nepomuk::ServerConfigModule::slotUpdateStrigiStatus() { - if ( isStrigiRunning() ) { - m_strigiStatus->on(); - m_strigiStatusLabel->setText( i18n( "Strigi is running" ) ); + if ( m_strigiInterface.isValid() ) { + bool indexing = m_strigiInterface.isIndexing(); + bool suspended = m_strigiInterface.isSuspended(); + QString folder = m_strigiInterface.currentFolder(); + + if ( suspended ) + m_labelStrigiStatus->setText( i18n( "File indexer is suspended" ) ); + else if ( indexing ) + m_labelStrigiStatus->setText( i18n( "Strigi is currently indexing files in folder %1", folder ) ); + else + m_labelStrigiStatus->setText( i18n( "File indexer is idle" ) ); } else { - m_strigiStatus->off(); - m_strigiStatusLabel->setText( i18n( "Strigi not running" ) ); + m_labelStrigiStatus->setText( i18n( "Strigi service not running." ) ); } } - -void Nepomuk::ServerConfigModule::updateStrigiSettingsInRunningInstance() -{ - if ( isStrigiRunning() ) { - StrigiClient strigiClient; - strigiClient.setIndexedDirectories( m_editStrigiFolders->items() ); - - // FIXME: there should be a rereadConfig method in strigi - StrigiConfigFile strigiConfig( StrigiConfigFile::defaultStrigiConfigFilePath() ); - strigiConfig.load(); - - QList<QPair<bool, QString> > filters; - foreach( const QString &filter, strigiConfig.excludeFilters() ) { - filters.append( qMakePair( false, filter ) ); - } - strigiClient.setFilters( filters ); - } -} - - -bool Nepomuk::ServerConfigModule::isStrigiRunning() -{ - return QDBusConnection::sessionBus().interface()->isServiceRegistered( "vandenoever.strigi" ).value(); -} - #include "nepomukserverkcm.moc" diff -Naur nepomuk/kcm/nepomukserverkcm.h nepomuk/kcm/nepomukserverkcm.h --- nepomuk/kcm/nepomukserverkcm.h 2008-04-02 14:18:20.000000000 +0200 +++ nepomuk/kcm/nepomukserverkcm.h 2008-09-01 14:33:17.000000000 +0200 @@ -22,6 +22,9 @@ #include <KCModule> #include "ui_nepomukconfigwidget.h" #include "nepomukserverinterface.h" +#include "strigiserviceinterface.h" + +class FolderSelectionModel; namespace Nepomuk { class ServerConfigModule : public KCModule, private Ui::NepomukConfigWidget @@ -38,13 +41,13 @@ void defaults(); private Q_SLOTS: - void updateStrigiStatus(); - void updateStrigiSettingsInRunningInstance(); + void slotUpdateStrigiStatus(); private: - bool isStrigiRunning(); - org::kde::NepomukServer m_serverInterface; + org::kde::nepomuk::Strigi m_strigiInterface; + + FolderSelectionModel* m_folderModel; }; } diff -Naur nepomuk/server/main.cpp nepomuk/server/main.cpp --- nepomuk/server/main.cpp 2008-07-03 07:05:21.000000000 +0200 +++ nepomuk/server/main.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -38,6 +38,7 @@ switch( signal ) { case SIGHUP: case SIGQUIT: + case SIGTERM: case SIGINT: if ( qApp ) { qApp->quit(); @@ -54,6 +55,7 @@ sigaction( SIGHUP, &sa, 0 ); sigaction( SIGINT, &sa, 0 ); sigaction( SIGQUIT, &sa, 0 ); + sigaction( SIGTERM, &sa, 0 ); #endif } } diff -Naur nepomuk/server/nepomukserver.desktop nepomuk/server/nepomukserver.desktop --- nepomuk/server/nepomukserver.desktop 2008-08-28 10:07:16.000000000 +0200 +++ nepomuk/server/nepomukserver.desktop 2008-09-01 14:33:17.000000000 +0200 @@ -5,7 +5,6 @@ OnlyShowIn=KDE; X-KDE-autostart-phase=0 Name=Nepomuk Server -Name[ar]=خادم Nepomuk Name[bg]=Сървър Nepomuk Name[bn_IN]=Nepomuk সার্ভার Name[ca]=Servidor Nepomuk @@ -24,6 +23,7 @@ Name[ga]=Freastalaí Nepomuk Name[gl]=Servidor Nepomuk Name[gu]=નેપોમુક સર્વર +Name[he]=שרת Nepomuk Name[hr]=Poslužitelj Nepomuk Name[hu]=Nepomuk szolgáltatás Name[is]=Nepomuk miðlari @@ -52,6 +52,7 @@ Name[sr]=Сервер Непомука Name[sr@latin]=Server Nepomuka Name[sv]=Nepomuk-server +Name[te]=Nepomuk సేవిక Name[tg]=Хидматгоҳи Nepomuk Name[th]=เซิร์ฟเวอร์ Nepomuk Name[tr]=Nepomuk Sunucu @@ -63,7 +64,6 @@ Name[zh_CN]=Nepomuk 服务器 Name[zh_TW]=Nepomuk 伺服器 Comment=The Nepomuk Server providing Storage services and strigi controlling -Comment[ar]=Nepomuk مزود اقوى الخدمات وادوات التحكم Comment[bg]=Сървърът Nepomuk предлага контрол на strigi и съхранение Comment[ca]=El servidor Nepomuk proporciona serveis d'emmagatzematge i de control de l'Strigi Comment[csb]=Serwer Nepomuk dôwô kòntrolã nad strigi ë zôpisowné ùsłëżnotë @@ -103,6 +103,7 @@ Comment[sr]=Сервер Непомука даје уређаје за складиштење и контролу Стригија Comment[sr@latin]=Server Nepomuka daje uređaje za skladištenje i kontrolu Strigija Comment[sv]=Nepomuk-server som tillhandahåller lagringstjänster och styrning av Strigi +Comment[te]=Nepomuk సేవిక నిల్వ సేవలను మరియు strigi నింయత్రణను అందిస్తుంది Comment[th]=เซิร์ฟเวอร์ Nepomuk จะให้บริการจัดเก็บและการควบคุม strigi Comment[tr]=Nepomuk Sunucusu Depolama servislerini ve Strigi uygulamasının kontrolünü sağlar Comment[uk]=Сервер Nepomuk надає служби збереження і керування strigi diff -Naur nepomuk/server/nepomukservice.desktop nepomuk/server/nepomukservice.desktop --- nepomuk/server/nepomukservice.desktop 2008-08-28 10:07:16.000000000 +0200 +++ nepomuk/server/nepomukservice.desktop 2008-09-01 14:33:17.000000000 +0200 @@ -3,7 +3,6 @@ X-KDE-ServiceType=NepomukService Comment=Nepomuk Service Comment[af]=Nepomuk diens -Comment[ar]=خادم Nepomuk Comment[bg]=Услуга Nepomuk Comment[bn_IN]=Nepomuk পরিসেবা Comment[ca]=Servei Nepomuk @@ -45,6 +44,7 @@ Comment[sr]=Сервис Непомука Comment[sr@latin]=Servis Nepomuka Comment[sv]=Nepomuk-tjänst +Comment[te]=Nepomuk సేవ Comment[tg]=Хидматҳои Nepomuk Comment[th]=บริการ Neomuk Comment[tr]=Nepomuk Servisi diff -Naur nepomuk/server/servicecontroller.cpp nepomuk/server/servicecontroller.cpp --- nepomuk/server/servicecontroller.cpp 2008-08-28 10:07:16.000000000 +0200 +++ nepomuk/server/servicecontroller.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -42,8 +42,9 @@ Private() : processControl( 0 ), serviceControlInterface( 0 ), - attached(false), - initialized( false ) { + attached( false ), + initialized( false ), + failedToInitialize( false ) { } KService::Ptr service; @@ -59,6 +60,7 @@ bool attached; bool initialized; + bool failedToInitialize; // list of loops waiting for the service to become initialized QList<QEventLoop*> loops; @@ -154,6 +156,7 @@ } d->initialized = false; + d->failedToInitialize = false; // 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 @@ -195,7 +198,9 @@ d->processControl->setCrashPolicy( ProcessControl::StopOnCrash ); } - if ( waitForInitialized( 2000 ) ) { + if ( d->serviceControlInterface || + ( !QCoreApplication::closingDown() && + waitForInitialized( 2000 ) ) ) { d->serviceControlInterface->shutdown(); } @@ -230,7 +235,7 @@ return false; } - if( !d->initialized ) { + if( !d->initialized && !d->failedToInitialize ) { QEventLoop loop; d->loops.append( &loop ); if ( timeout > 0 ) { @@ -300,14 +305,21 @@ void Nepomuk::ServiceController::slotServiceInitialized( bool success ) { if ( !d->initialized ) { - kDebug() << "Service" << name() << "initialized:" << success; - d->initialized = true; - emit serviceInitialized( this ); - - if ( runOnce() ) { - // we have been run once. Do not autostart next time - KConfigGroup cg( Server::self()->config(), QString("Service-%1").arg(name()) ); - cg.writeEntry( "autostart", false ); + if ( success ) { + kDebug() << "Service" << name() << "initialized"; + d->initialized = true; + emit serviceInitialized( this ); + + if ( runOnce() ) { + // we have been run once. Do not autostart next time + KConfigGroup cg( Server::self()->config(), QString("Service-%1").arg(name()) ); + cg.writeEntry( "autostart", false ); + } + } + else { + d->failedToInitialize = true; + kDebug() << "Failed to initialize service" << name(); + stop(); } } diff -Naur nepomuk/services/filewatch/nepomukfilewatch.desktop nepomuk/services/filewatch/nepomukfilewatch.desktop --- nepomuk/services/filewatch/nepomukfilewatch.desktop 2008-08-28 10:07:16.000000000 +0200 +++ nepomuk/services/filewatch/nepomukfilewatch.desktop 2008-09-01 14:33:17.000000000 +0200 @@ -5,7 +5,6 @@ X-KDE-Nepomuk-autostart=true X-KDE-Nepomuk-start-on-demand=false Name=NepomukFileWatch -Name[ar]=البحث في ملفات Nepomuk Name[de]=NepomukDateiMonitor Name[es]=MonitorDeArchivosNepomuk Name[et]=Nepomuki failijälgija @@ -18,11 +17,10 @@ Name[sr]=Непомуков надзор фајлова Name[sr@latin]=Nepomukov nadzor fajlova Name[sv]=Nepomuk-filövervakning -Name[x-test]=xxNepomukFileWatchxx +Name[te]=Nepomukఫైల్ వాచ్ Name[zh_CN]=Nepomuk 文件监视 Name[zh_TW]=Nepomuk 檔案監控 Comment=The Nepomuk file watch service for monitoring file changes -Comment[ar]=مراقب تغير ملفات Nepomuk Comment[bg]=Услугата NepomukFileWatch следи за промяна във файловете Comment[ca]=El servei de control de fitxers del Nepomuk per fer un seguiment dels canvis en fitxers Comment[csb]=Ùsłëżnota Nepomùka mònitorëjącô zjinaczi lopków @@ -40,10 +38,8 @@ Comment[ja]=ファイルの変更を監視する Nepomuk サービス Comment[km]=ឯកសាររបស់ Nepomuk មើលសេវាសម្រាប់ត្រួតពិនិត្យការផ្លាស់ប្ដូរឯកសារ Comment[ko]=파일 변화를 감시하는 Nepumuk 파일 감시 서비스 -Comment[lv]=Nepomuk failu novērošanas serviss, kas novēro izmaiņas failos Comment[nb]=Nepomuk filovervåkning for å detektere filendringer Comment[nds]=Nepomuk sien Dateibeluurdeenst, de Ännern an Dateien vermeldt -Comment[nl]=NepomukFileWatch volgt uw systeem op bestandswijzigingen Comment[nn]=Filovervakingstenesta Nepomuk tilbyr overvaking av endringar i filer Comment[pl]=Usługa Nepomuka do monitorowania zmian w plikach Comment[pt]=O serviço de vigilância de ficheiros para vigiar as alterações dos ficheiros @@ -52,8 +48,9 @@ Comment[sr]=Непомуков сервис за надгледање измена над фајловима Comment[sr@latin]=Nepomukov servis za nadgledanje izmena nad fajlovima Comment[sv]=Nepomuks filövervakningstjänst för att bevaka filändringar +Comment[te]=ఫైల్ మార్పులను మానిటరింగ్ చేయుటకొరకు Nepomuk ఫైల్ వాచ్ సేవ Comment[th]=บริการของ Nepomuk สำหรับคอยตรวจจับความเปลี่ยนแปลงของแฟ้ม +Comment[tr]=Dosya değişikliklerini izlemek için Nepomuk dosya izleme servisi Comment[uk]=Служба Nepomuk для спостереження за змінами в файлах -Comment[x-test]=xxThe Nepomuk file watch service for monitoring file changesxx Comment[zh_CN]=用于监视文件变更的 Nepomuk 服务 Comment[zh_TW]=Nepomuk 檔案監控服務,監視檔案變化 diff -Naur nepomuk/services/migration1/nepomukmigration1.desktop nepomuk/services/migration1/nepomukmigration1.desktop --- nepomuk/services/migration1/nepomukmigration1.desktop 2008-08-28 10:07:16.000000000 +0200 +++ nepomuk/services/migration1/nepomukmigration1.desktop 2008-09-01 14:33:17.000000000 +0200 @@ -6,7 +6,6 @@ X-KDE-Nepomuk-start-on-demand=false X-KDE-Nepomuk-run-once=true Comment=Nepomuk Data Migration Level 1 -Comment[ar]=معلومات هجرة Nepomuk المرحلة 1 Comment[ca]=Nivell 1 de migració de dades del Nepomuk Comment[csb]=Migracëjô pòdôwków Nepomuk, równiô 1 Comment[da]=Nepomuk datamigrering niveau 1 @@ -37,6 +36,7 @@ Comment[sr]=Непомукова миграција података нивоа 1 Comment[sr@latin]=Nepomukova migracija podataka nivoa 1 Comment[sv]=Nepomuk-datamigration nivå 1 +Comment[te]=Nepomuk డాటా వలస స్థాయి 1 Comment[th]=ตัวปรับรุ่นข้อมูลระดับ 1 ของ Nepomuk Comment[tr]=Nepomuk Veri Taşıma Seviyesi 1 Comment[uk]=Міграція даних Nepomuk - рівень 1 diff -Naur nepomuk/services/ontologyloader/CMakeLists.txt nepomuk/services/ontologyloader/CMakeLists.txt --- nepomuk/services/ontologyloader/CMakeLists.txt 2008-05-21 10:33:02.000000000 +0200 +++ nepomuk/services/ontologyloader/CMakeLists.txt 2008-09-01 14:33:17.000000000 +0200 @@ -9,13 +9,20 @@ set(ontologyloader_SRCS ontologyloader.cpp ontologymanagermodel.cpp + graphretriever.cpp ) +qt4_add_dbus_adaptor(ontologyloader_SRCS + ../../interfaces/org.kde.nepomuk.OntologyManager.xml + ontologyloader.h + Nepomuk::OntologyLoader) + kde4_add_plugin(nepomukontologyloader ${ontologyloader_SRCS}) target_link_libraries(nepomukontologyloader ${SOPRANO_LIBRARIES} ${KDE4_KDECORE_LIBS} + ${KDE4_KIO_LIBS} ${NEPOMUK_LIBRARIES} ) diff -Naur nepomuk/services/ontologyloader/graphretriever.cpp nepomuk/services/ontologyloader/graphretriever.cpp --- nepomuk/services/ontologyloader/graphretriever.cpp 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/ontologyloader/graphretriever.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,173 @@ +/* This file is part of the KDE semantic clipboard + Copyright (C) 2008 Tobias Wolf <twolf@access.unizh.ch> + 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 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 "graphretriever.h" + +#include <QtCore/QByteArray> +#include <QtCore/QEventLoop> +#include <QtCore/QHash> +#include <QtCore/QPair> +#include <QtCore/QString> +#include <QtCore/QTextStream> +#include <QtCore/QUrl> + +#include <Soprano/Model> +#include <Soprano/Global> +#include <Soprano/Parser> +#include <Soprano/PluginManager> +#include <Soprano/StatementIterator> + +#include <KDebug> +#include <KLocale> +#include <kio/job.h> + + +class Nepomuk::GraphRetriever::Private +{ +public: + Private( Nepomuk::GraphRetriever* qq ); + + void get( const QUrl& url ); + + Nepomuk::GraphRetriever* q; + + QUrl url; + QHash<int, QByteArray> m_data; + unsigned int m_idleCount; + unsigned int m_timeoutThreshold; +}; + + +Nepomuk::GraphRetriever::Private::Private( Nepomuk::GraphRetriever* qq ) + : q(qq), + m_idleCount( 0 ) +{ +} + + +void Nepomuk::GraphRetriever::Private::get( const QUrl& url ) +{ + KIO::StoredTransferJob* job = KIO::storedGet( url, KIO::Reload, KIO::HideProgressInfo ); + job->addMetaData( "accept", + QString( "%1;q=0.2, %2" ) + .arg( Soprano::serializationMimeType( Soprano::SerializationRdfXml ) ) + .arg( Soprano::serializationMimeType( Soprano::SerializationTrig ) ) ); + job->addMetaData( "Charsets", "utf-8" ); + + connect( job, SIGNAL(result(KJob*)), + q, SLOT(httpRequestFinished(KJob*))); +} + + +Nepomuk::GraphRetriever::GraphRetriever( QObject* parent ) + : KJob( parent ), + d( new Private(this) ) +{ +} + + +Nepomuk::GraphRetriever::~GraphRetriever() +{ + delete d; +} + + +void Nepomuk::GraphRetriever::setUrl( const QUrl& url ) +{ + d->url = url; +} + + +QUrl Nepomuk::GraphRetriever::url() const +{ + return d->url; +} + + +void Nepomuk::GraphRetriever::start() +{ + d->get( d->url ); +} + + +Soprano::Model* Nepomuk::GraphRetriever::model() const +{ + Soprano::Model* result = Soprano::createModel(); + Soprano::StatementIterator it = statements(); + while ( it.next() ) { + result->addStatement( *it ); + } + return result; +} + + +Soprano::StatementIterator Nepomuk::GraphRetriever::statements() const +{ + QByteArray data; + Soprano::RdfSerialization serialization = Soprano::SerializationRdfXml; + if ( d->m_data.contains( ( int )Soprano::SerializationTrig ) ) { + serialization = Soprano::SerializationTrig; + data = d->m_data[( int )Soprano::SerializationTrig]; + } + else { + serialization = Soprano::SerializationRdfXml; + data = d->m_data[( int )Soprano::SerializationRdfXml]; + } + + QTextStream stream( data ); + if ( const Soprano::Parser* parser = + Soprano::PluginManager::instance()->discoverParserForSerialization( serialization ) ) { + return parser->parseStream( stream, d->url, serialization ); + } + else { + return Soprano::StatementIterator(); + } +} + + +void Nepomuk::GraphRetriever::httpRequestFinished( KJob* job ) +{ + KIO::StoredTransferJob* tj = static_cast<KIO::StoredTransferJob*>( job ); + + // reset idle counter every time a request is finished + d->m_idleCount = 0; + + QString mimetype = tj->mimetype(); + Soprano::RdfSerialization serialization = Soprano::mimeTypeToSerialization( mimetype ); + if ( serialization == Soprano::SerializationUser && + mimetype.contains( "xml", Qt::CaseInsensitive ) ) { + serialization = Soprano::SerializationRdfXml; + } + if ( serialization != Soprano::SerializationUser ) + d->m_data[( int )serialization] = tj->data(); + + emitResult(); +} + + +Nepomuk::GraphRetriever* Nepomuk::GraphRetriever::retrieve( const QUrl& uri ) +{ + GraphRetriever* gr = new GraphRetriever(); + gr->setUrl( uri ); + gr->start(); + return gr; +} + +#include "graphretriever.moc" diff -Naur nepomuk/services/ontologyloader/graphretriever.h nepomuk/services/ontologyloader/graphretriever.h --- nepomuk/services/ontologyloader/graphretriever.h 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/ontologyloader/graphretriever.h 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,108 @@ +/* This file is part of the KDE semantic clipboard + Copyright (C) 2008 Tobias Wolf <twolf@access.unizh.ch> + 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 as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _NEPOMUK_GRAPHRETRIEVER_H_ +#define _NEPOMUK_GRAPHRETRIEVER_H_ + +#include <KJob> + +class QString; +class QUrl; + +namespace Soprano { + class Model; + class StatementIterator; +} +namespace KIO { + class Job; +} + +namespace Nepomuk +{ + + /** + * \class GraphRetriever graphretriever.h <nepomuk/graphretriever.h> + * + * \brief Utility class for retrieving RDF graphs from Web locations. + * + * GraphRetriever allows retrieval of multiple RDF graph fragments from + * the Web using HTTP GET. Target HTTP servers should support the RDF+XML + * request MIME type for this to work. + * + * Clients can queue multiple get requests and must follow the last get + * request with a call to either model() or serialization(). + * + * \author Tobias Wolf <twolf@access.unizh.ch> + */ + class GraphRetriever : public KJob + { + Q_OBJECT + + public: + /** + * Custom and default constructor. + * + * @param parent The parent QObject. + */ + GraphRetriever( QObject* parent = 0 ); + + /** + * Default destructor. + */ + ~GraphRetriever(); + + static GraphRetriever* retrieve( const QUrl& uri ); + + void setUrl( const QUrl& url ); + + QUrl url() const; + + /** + * Adds a get request for the given URL. + * + * @param url An URL specifying the location of a graph fragment to get. + * @return True if the get request was accepted, false otherwise. + */ + void start(); + + /** + * Returns a new Soprano model constructed from the retrieved graph fragments. The + * client takes over ownership of the returned model. + * + * @return A new Soprano model constructed from the merged fragments. + */ + Soprano::Model* model() const; + + Soprano::StatementIterator statements() const; + + private Q_SLOTS: + /** + * @internal + */ + void httpRequestFinished( KJob* ); + + private: + class Private; + Private* const d; + }; + +} + +#endif diff -Naur nepomuk/services/ontologyloader/nepomukontologyloader.desktop nepomuk/services/ontologyloader/nepomukontologyloader.desktop --- nepomuk/services/ontologyloader/nepomukontologyloader.desktop 2008-08-28 10:07:16.000000000 +0200 +++ nepomuk/services/ontologyloader/nepomukontologyloader.desktop 2008-09-01 14:33:17.000000000 +0200 @@ -6,7 +6,6 @@ X-KDE-Nepomuk-start-on-demand=false X-KDE-Nepomuk-dependencies=nepomukstorage Name=Nepomuk Ontology Loader -Name[ar]=محمل معلومات الانشاء Nepomuk Name[ca]=Carregador d'ontologies del Nepomuk Name[csb]=Ladowanié òntogiji Nepomuka Name[da]=Nepomuk ontologi-indlæser @@ -38,6 +37,7 @@ Name[sr]=Непомуков учитавач онтологија Name[sr@latin]=Nepomukov učitavač ontologija Name[sv]=Nepomuk-ontologiladdning +Name[te]=Nepomuk ఆన్టోలజి లోడర్ Name[th]=ตัวโหลด Ontology ของ Nepomuk Name[tr]=Nepomuk Ontoloji Yükleyici Name[uk]=Завантажувач онтології Nepomuk @@ -46,7 +46,6 @@ Name[zh_CN]=Nepomuk 本体装载器 Name[zh_TW]=Nepomuk Ontology 載入器 Comment=Nepomuk Service which maintains the ontologies installed on the system -Comment[ar]=Nepomuk المحافظة على معلومات الانشاء المثبتة علىالنظام Comment[bg]=Услуга, която поддържа инсталираните на компютъра онтологии Comment[ca]=Servei del Nepomuk que manté les ontologies instal·lades en el sistema Comment[csb]=Ùsłëżnota Nepomuka, jakô sprôwiô òntologijama winstalowónëmi w systemie @@ -79,6 +78,7 @@ Comment[sr]=Сервис Непомука за одржавање онтологија присутних на систему Comment[sr@latin]=Servis Nepomuka za održavanje ontologija prisutnih na sistemu Comment[sv]=Nepomuk-tjänst som hanterar ontologier installerade i systemet +Comment[te]=సిస్టమ్ నందు సంస్థాపించిన ఆన్టాలజీస్ను నిర్వహించే Nepomuk సేవ Comment[th]=บริการของ Nepomuk สำหรับดูแล ontologies ที่ติดตั้งไว้บนระบบ Comment[tr]=Sistemde yüklü olan ontolojileri yürüten Nepomuk servisi Comment[uk]=Служба Nepomuk, яка здійснює супровід всіх онтологій встановлених у системі diff -Naur nepomuk/services/ontologyloader/ontologyloader.cpp nepomuk/services/ontologyloader/ontologyloader.cpp --- nepomuk/services/ontologyloader/ontologyloader.cpp 2008-04-02 14:18:19.000000000 +0200 +++ nepomuk/services/ontologyloader/ontologyloader.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -18,6 +18,8 @@ #include "ontologyloader.h" #include "ontologymanagermodel.h" +#include "ontologymanageradaptor.h" +#include "graphretriever.h" #include <Soprano/Global> #include <Soprano/Node> @@ -31,6 +33,8 @@ #include <KDebug> #include <KGlobal> #include <KStandardDirs> +#include <KLocale> +#include <KDirWatch> #include <QtCore/QFileInfo> #include <QtCore/QTimer> @@ -47,12 +51,14 @@ { public: Private( OntologyLoader* p ) - : q( p ) { + : forceOntologyUpdate( false ), + q( p ) { } OntologyManagerModel* model; QTimer updateTimer; + bool forceOntologyUpdate; QStringList desktopFilesToUpdate; void updateOntology( const QString& filename ); @@ -62,16 +68,81 @@ }; +void Nepomuk::OntologyLoader::Private::updateOntology( const QString& filename ) +{ + KDesktopFile df( filename ); + + // only update if the modification date of the ontology file changed (not the desktop file). + // ------------------------------------ + QFileInfo ontoFileInf( df.readPath() ); + QDateTime ontoLastModified = model->ontoModificationDate( df.readUrl() ); + bool update = false; + + if ( ontoLastModified < ontoFileInf.lastModified() ) { + kDebug() << "Ontology" << df.readUrl() << "needs updating."; + update = true; + } + else { + kDebug() << "Ontology" << df.readUrl() << "up to date."; + } + + if( !update && forceOntologyUpdate ) { + kDebug() << "Ontology update forced."; + update = true; + } + + if( update ) { + QString mimeType = df.desktopGroup().readEntry( "MimeType", QString() ); + + const Soprano::Parser* parser + = Soprano::PluginManager::instance()->discoverParserForSerialization( Soprano::mimeTypeToSerialization( mimeType ), + mimeType ); + if ( !parser ) { + kDebug() << "No parser to handle" << df.readName() << "(" << mimeType << ")"; + return; + } + + kDebug() << "Parsing" << df.readPath(); + + Soprano::StatementIterator it = parser->parseFile( df.readPath(), + df.readUrl(), + Soprano::mimeTypeToSerialization( mimeType ), + mimeType ); + if ( !parser->lastError() ) { + model->updateOntology( it, df.readUrl() ); + emit q->ontologyUpdated( df.readUrl() ); + } + else { + emit q->ontologyUpdateFailed( df.readUrl(), i18n( "Parsing of file %1 failed (%2)", df.readPath(), parser->lastError().message() ) ); + } + } +} + + + Nepomuk::OntologyLoader::OntologyLoader( QObject* parent, const QList<QVariant>& ) : Service( parent ), d( new Private(this) ) { + ( void )new OntologyManagerAdaptor( this ); + d->model = new OntologyManagerModel( mainModel(), this ); connect( &d->updateTimer, SIGNAL(timeout()), this, SLOT(updateNextOntology()) ); - updateAllOntologies(); - // FIXME: install watches for changed or newly installed ontologies -// QStringList dirs = KGlobal::dirs()->findDirs( "data", "nepomuk/ontologies" ); + // only update changed ontologies + updateLocalOntologies(); + + // watch both the global and local ontology folder for changes + KDirWatch* dirWatch = KDirWatch::self(); + connect( dirWatch, SIGNAL( dirty(QString) ), + this, SLOT( updateLocalOntologies() ) ); + connect( dirWatch, SIGNAL( created(QString) ), + this, SLOT( updateLocalOntologies() ) ); + foreach( const QString& dir, KGlobal::dirs()->findDirs( "data", QString() ) ) { + // we only add the suffix here to make sure to also watch the non-existing local dir + kDebug() << "watching" << ( dir + "nepomuk/ontologies/" ); + dirWatch->addDir( dir + "nepomuk/ontologies/", KDirWatch::WatchFiles ); + } } @@ -81,62 +152,60 @@ } -void Nepomuk::OntologyLoader::updateAllOntologies() +void Nepomuk::OntologyLoader::updateLocalOntologies() { - if ( !d->model ) { - kDebug() << "No Nepomuk Model. Cannot update ontologies."; - return; - } - - // update all installed ontologies d->desktopFilesToUpdate = KGlobal::dirs()->findAllResources( "data", "nepomuk/ontologies/*.desktop" ); d->updateTimer.start(0); } +void Nepomuk::OntologyLoader::updateAllLocalOntologies() +{ + d->forceOntologyUpdate = true; + updateLocalOntologies(); +} + + void Nepomuk::OntologyLoader::updateNextOntology() { if( !d->desktopFilesToUpdate.isEmpty() ) { d->updateOntology( d->desktopFilesToUpdate.takeFirst() ); } else { + d->forceOntologyUpdate = false; d->updateTimer.stop(); } } -void Nepomuk::OntologyLoader::Private::updateOntology( const QString& filename ) +QString Nepomuk::OntologyLoader::findOntologyContext( const QString& uri ) { - KDesktopFile df( filename ); - - // only update if the modification date of the ontology file changed (not the desktop file). - // ------------------------------------ - QFileInfo ontoFileInf( df.readPath() ); - QDateTime ontoLastModified = model->ontoModificationDate( df.readUrl() ); - if ( ontoLastModified < ontoFileInf.lastModified() ) { + return QString::fromAscii( d->model->findOntologyContext( QUrl::fromEncoded( uri.toAscii() ) ).toEncoded() ); +} - kDebug() << "Ontology" << df.readUrl() << "needs updating."; - QString mimeType = df.desktopGroup().readEntry( "MimeType", QString() ); - - const Soprano::Parser* parser - = Soprano::PluginManager::instance()->discoverParserForSerialization( Soprano::mimeTypeToSerialization( mimeType ), - mimeType ); - if ( !parser ) { - kDebug() << "No parser to handle" << df.readName() << "(" << mimeType << ")"; - return; - } +void Nepomuk::OntologyLoader::importOntology( const QString& url ) +{ + connect( GraphRetriever::retrieve( url ), SIGNAL( result( KJob* ) ), + this, SLOT( slotGraphRetrieverResult( KJob* ) ) ); +} - kDebug() << "Parsing" << df.readPath(); - model->updateOntology( parser->parseFile( df.readPath(), - df.readUrl(), - Soprano::mimeTypeToSerialization( mimeType ), - mimeType ), - df.readUrl() ); +void Nepomuk::OntologyLoader::slotGraphRetrieverResult( KJob* job ) +{ + GraphRetriever* graphRetriever = static_cast<GraphRetriever*>( job ); + if ( job->error() ) { + emit ontologyUpdateFailed( QString::fromAscii( graphRetriever->url().toEncoded() ), graphRetriever->errorString() ); } else { - kDebug() << "Ontology" << df.readUrl() << "up to date."; + // TODO: find a way to check if the imported version of the ontology + // is newer than the already installed one + if ( d->model->updateOntology( graphRetriever->statements(), graphRetriever->url() ) ) { + emit ontologyUpdated( QString::fromAscii( graphRetriever->url().toEncoded() ) ); + } + else { + emit ontologyUpdateFailed( QString::fromAscii( graphRetriever->url().toEncoded() ), d->model->lastError().message() ); + } } } diff -Naur nepomuk/services/ontologyloader/ontologyloader.h nepomuk/services/ontologyloader/ontologyloader.h --- nepomuk/services/ontologyloader/ontologyloader.h 2008-04-02 14:18:19.000000000 +0200 +++ nepomuk/services/ontologyloader/ontologyloader.h 2008-09-01 14:33:17.000000000 +0200 @@ -26,12 +26,14 @@ class Model; } +class KJob; + +// Hint: Using QString instead of QUrl for URIs since this API will be exported via DBus and not used otherwise namespace Nepomuk { class OntologyLoader : public Nepomuk::Service { Q_OBJECT - Q_CLASSINFO( "D-Bus Interface", "org.kde.nepomuk.OntologyManager" ) public: OntologyLoader( QObject* parent = 0, const QList<QVariant>& args = QList<QVariant>() ); @@ -39,19 +41,49 @@ public Q_SLOTS: /** - * Update all installed ontologies and install dir watches - * to monitor newly installed and changed ontologies. - * - * This should also be called for initialization + * Tries to find the ontology \p uri in the local Nepomuk store. + * \return The context (named graph) storing the ontology's statements + * or an invalid URI if the ontology could not be found. + */ + QString findOntologyContext( const QString& uri ); + + /** + * Update all installed ontologies that changed since the last update. */ - Q_SCRIPTABLE void updateAllOntologies(); + void updateLocalOntologies(); - // FIXME: add methods (exported on DBus) like: - // void importOntology( const QUrl& url... ) + /** + * Update all installed ontologies, independant of their status. + */ + void updateAllLocalOntologies(); + + /** + * Try to retrieve an ontology from the web. + * On success ontologyUpdated will be emitted. If the + * retrieval failed, ontologyUpdateFailed will be + * emitted. + */ + void importOntology( const QString& url ); + + Q_SIGNALS: + /** + * Emitted once an ontology has been updated. This holds for both + * locally installed ontology files (which are read automaticall) + * and those retrieved from the web via importOntology + */ + void ontologyUpdated( const QString& uri ); + + /** + * Emitted if updating an ontology failed. This holds for both + * locally installed ontology files (parsing may fail) and for + * those imported via importOntology. + */ + void ontologyUpdateFailed( const QString& uri, const QString& error ); private Q_SLOTS: // a little async updating void updateNextOntology(); + void slotGraphRetrieverResult( KJob* job ); private: class Private; diff -Naur nepomuk/services/ontologyloader/ontologymanagermodel.cpp nepomuk/services/ontologyloader/ontologymanagermodel.cpp --- nepomuk/services/ontologyloader/ontologymanagermodel.cpp 2008-04-02 14:18:19.000000000 +0200 +++ nepomuk/services/ontologyloader/ontologymanagermodel.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -193,10 +193,19 @@ } +void Nepomuk::OntologyManagerModel::setParentModel( Soprano::Model* parentModel ) +{ + FilterModel::setParentModel( parentModel ); +} + + bool Nepomuk::OntologyManagerModel::updateOntology( Soprano::StatementIterator data, const QUrl& ns ) { clearError(); + QTime timer; + timer.start(); + // Create temp memory model // ------------------------------------ const Soprano::Backend* backend = Soprano::PluginManager::instance()->discoverBackendByFeatures( Soprano::BackendFeatureStorageMemory ); @@ -290,7 +299,7 @@ } } - kDebug() << "Successfully updated ontology" << ontoUri; + kDebug() << "Successfully updated ontology" << ontoUri << QString("(%1ms)").arg(timer.elapsed()); return true; } else { @@ -340,4 +349,16 @@ } } + +QUrl Nepomuk::OntologyManagerModel::findOntologyContext( const QUrl& uri ) +{ + QUrl dataGraphUri, metaDataGraphUri; + if ( findGraphUris( parentModel(), uri, dataGraphUri, metaDataGraphUri ) ) { + return dataGraphUri; + } + else { + return QUrl(); + } +} + #include "ontologymanagermodel.moc" diff -Naur nepomuk/services/ontologyloader/ontologymanagermodel.h nepomuk/services/ontologyloader/ontologymanagermodel.h --- nepomuk/services/ontologyloader/ontologymanagermodel.h 2008-04-02 14:18:19.000000000 +0200 +++ nepomuk/services/ontologyloader/ontologymanagermodel.h 2008-09-01 14:33:17.000000000 +0200 @@ -46,6 +46,11 @@ * Destructor */ ~OntologyManagerModel(); + + /** + * Reimplemented from FilterModel. The API is not affected. + */ + void setParentModel( Soprano::Model* parentModel ); /** * Update an ontology. @@ -83,6 +88,13 @@ */ QDateTime ontoModificationDate( const QUrl& uri ); + /** + * Tries to find the ontology \p uri in the local Nepomuk store. + * \return The context (named graph) storing the ontology's statements + * or an invalid URI if the ontology could not be found. + */ + QUrl findOntologyContext( const QUrl& uri ); + private: class Private; Private* const d; diff -Naur nepomuk/services/storage/nepomukcore.cpp nepomuk/services/storage/nepomukcore.cpp --- nepomuk/services/storage/nepomukcore.cpp 2008-07-08 11:26:02.000000000 +0200 +++ nepomuk/services/storage/nepomukcore.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -127,4 +127,11 @@ } } + +void Nepomuk::Core::optimize( const QString& name ) +{ + if ( m_repositories.contains( name ) ) + m_repositories[name]->optimize(); +} + #include "nepomukcore.moc" diff -Naur nepomuk/services/storage/nepomukcore.h nepomuk/services/storage/nepomukcore.h --- nepomuk/services/storage/nepomukcore.h 2008-04-10 11:30:07.000000000 +0200 +++ nepomuk/services/storage/nepomukcore.h 2008-09-01 14:33:17.000000000 +0200 @@ -51,6 +51,9 @@ */ bool initialized() const; + public Q_SLOTS: + void optimize( const QString& repoName ); + Q_SIGNALS: void initializationDone( bool success ); diff -Naur nepomuk/services/storage/nepomukstorage.desktop nepomuk/services/storage/nepomukstorage.desktop --- nepomuk/services/storage/nepomukstorage.desktop 2008-08-28 10:07:16.000000000 +0200 +++ nepomuk/services/storage/nepomukstorage.desktop 2008-09-01 14:33:17.000000000 +0200 @@ -5,7 +5,6 @@ X-KDE-Nepomuk-autostart=true X-KDE-Nepomuk-start-on-demand=true Name=Nepomuk Data Storage -Name[ar]=مخزن بياناتNepomuk Name[bg]=Хранилище Nepomuk Name[bn_IN]=Nepomuk ডাটা সংরক্ষণব্যবস্থা Name[ca]=Emmagatzematge de dades del Nepomuk @@ -44,6 +43,7 @@ Name[sr]=Непомуково складиште Name[sr@latin]=Nepomukovo skladište Name[sv]=Nepomuk-datalagring +Name[te]=Nepomuk డాటా నిల్వ Name[tg]=Захирагоҳи Nepomuk Name[th]=ที่จัดเก็บข้อมูลของ Nepomuk Name[tr]=Nepomuk Veri Depolama @@ -53,7 +53,6 @@ Name[zh_CN]=Nepomuk 数据存储 Name[zh_TW]=Nepomuk 資料儲存 Comment=The Core Nepomuk data storage service -Comment[ar]=مخزن Nepomuk الاساسي للخدمات والبيانات Comment[bg]=Основното място, където се съхраняват данните на Nepomuk Comment[ca]=El servei d'emmagatzematge de dades del nucli del Nepomuk Comment[csb]=Spòdlowô ùsłëżnota Nepomuka do trzëmaniô pòdôwków @@ -88,6 +87,7 @@ Comment[sr]=Језгарни сервис Непомука за складиштење података Comment[sr@latin]=Jezgarni servis Nepomuka za skladištenje podataka Comment[sv]=Nepomuk-datalagringstjänstens kärna +Comment[te]=ఆధార Nepomuk డాటా నిల్వ సేవ Comment[th]=บริการจัดเก็บข้อมูล Core Nepomik Comment[tr]=Nepomuk Ana veri depolama servisi Comment[uk]=Ядро служби збереження даних Nepomuk diff -Naur nepomuk/services/storage/repository.cpp nepomuk/services/storage/repository.cpp --- nepomuk/services/storage/repository.cpp 2008-08-28 10:07:16.000000000 +0200 +++ nepomuk/services/storage/repository.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -26,6 +26,7 @@ #include <Soprano/StorageModel> #include <Soprano/Error/Error> #include <Soprano/Vocabulary/Xesam> +#include <Soprano/Vocabulary/RDF> #ifdef HAVE_SOPRANO_INDEX #include <Soprano/Index/IndexFilterModel> @@ -38,6 +39,8 @@ #include <KSharedConfig> #include <KLocale> +#include <QtCore/QTimer> + namespace { QString createStoragePath( const QString& repositoryId ) @@ -273,6 +276,22 @@ } +void Nepomuk::Repository::optimize() +{ + QTimer::singleShot( 0, this, SLOT( slotDoOptimize() ) ); +} + + +void Nepomuk::Repository::slotDoOptimize() +{ +#ifdef HAVE_SOPRANO_INDEX +#if SOPRANO_IS_VERSION(2,1,60) + m_index->optimize(); +#endif +#endif +} + + const Soprano::Backend* Nepomuk::Repository::activeSopranoBackend() { QString backendName = KSharedConfig::openConfig( "nepomukserverrc" )->group( "Basic Settings" ).readEntry( "Soprano Backend", "sesame2" ); diff -Naur nepomuk/services/storage/repository.h nepomuk/services/storage/repository.h --- nepomuk/services/storage/repository.h 2008-05-15 20:37:14.000000000 +0200 +++ nepomuk/services/storage/repository.h 2008-09-01 14:33:17.000000000 +0200 @@ -18,17 +18,7 @@ #include <QtCore/QString> #include <QtCore/QMap> -#include <soprano/version.h> - -#ifndef SOPRANO_IS_VERSION -#define SOPRANO_IS_VERSION(a,b,c) false -#endif - -#if SOPRANO_IS_VERSION(2,0,90) #include <Soprano/Util/SignalCacheModel> -#else -#include <Soprano/FilterModel> -#endif namespace Soprano { @@ -46,12 +36,7 @@ class CLuceneAnalyzer; - class Repository : public -#if SOPRANO_IS_VERSION(2,0,90) - Soprano::Util::SignalCacheModel -#else - Soprano::FilterModel -#endif + class Repository : public Soprano::Util::SignalCacheModel { Q_OBJECT @@ -79,11 +64,17 @@ void close(); + /** + * Calls slotDoOptimize via timer for instant return. + */ + void optimize(); + Q_SIGNALS: void opened( Repository*, bool success ); private Q_SLOTS: void copyFinished( KJob* job ); + void slotDoOptimize(); private: QString m_name; diff -Naur nepomuk/services/storage/storage.cpp nepomuk/services/storage/storage.cpp --- nepomuk/services/storage/storage.cpp 2008-04-02 14:18:19.000000000 +0200 +++ nepomuk/services/storage/storage.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -26,6 +26,8 @@ #include <KGlobal> #include <KStandardDirs> +#include <Soprano/Backend> + #include <kpluginfactory.h> #include <kpluginloader.h> @@ -70,4 +72,18 @@ setServiceInitialized( success ); } + +void Nepomuk::Storage::optimize( const QString& repo ) +{ + m_core->optimize( repo ); +} + + +QString Nepomuk::Storage::usedSopranoBackend() const +{ + // FIXME: this is only partly true. It is perfectly possible to change the backend only + // for the main repo in the config file + return Repository::activeSopranoBackend()->pluginName(); +} + #include "storage.moc" diff -Naur nepomuk/services/storage/storage.h nepomuk/services/storage/storage.h --- nepomuk/services/storage/storage.h 2008-04-02 14:18:19.000000000 +0200 +++ nepomuk/services/storage/storage.h 2008-09-01 14:33:17.000000000 +0200 @@ -28,12 +28,16 @@ class Storage : public Service { Q_OBJECT -// Q_CLASSINFO( "D-Bus Interface", "org.kde.nepomuk.Storage" ) + Q_CLASSINFO( "D-Bus Interface", "org.kde.nepomuk.Storage" ) public: Storage( QObject* parent, const QList<QVariant>& args = QList<QVariant>() ); ~Storage(); + public Q_SLOTS: + Q_SCRIPTABLE void optimize( const QString& repo ); + Q_SCRIPTABLE QString usedSopranoBackend() const; + private Q_SLOTS: void slotNepomukCoreInitialized( bool success ); diff -Naur nepomuk/services/strigi/CMakeLists.txt nepomuk/services/strigi/CMakeLists.txt --- nepomuk/services/strigi/CMakeLists.txt 2008-06-26 03:33:08.000000000 +0200 +++ nepomuk/services/strigi/CMakeLists.txt 2008-09-01 14:33:17.000000000 +0200 @@ -1,25 +1,41 @@ -project(strigiservice) +project(nepomukstrigiservice) include_directories( ${SOPRANO_INCLUDE_DIR} ${CMAKE_SOURCE_DIR} ${NEPOMUK_INCLUDE_DIR} - ${nepomukcommon_BINARY_DIR} + ${STRIGI_INCLUDE_DIR} + ${nepomukstrigiservice_BUILD_DIR} ) set(strigiservice_SRCS strigiservice.cpp - strigicontroller.cpp - ../../common/strigiconfigfile.cpp + strigiserviceadaptor.cpp + indexscheduler.cpp + priority.cpp + config.cpp + eventmonitor.cpp + systray.cpp + statuswidget.cpp + filesystemwatcher.cpp ) +qt4_add_dbus_interface(strigiservice_SRCS ../../interfaces/org.kde.nepomuk.Storage.xml nepomukstorageinterface) + +kde4_add_ui_files(strigiservice_SRCS + statuswidget.ui) + kde4_add_plugin(nepomukstrigiservice ${strigiservice_SRCS}) target_link_libraries(nepomukstrigiservice - ${STRIGI_STRIGIQTDBUSCLIENT_LIBRARY} + ${STRIGI_STREAMANALYZER_LIBRARY} + ${STRIGI_STREAMS_LIBRARY} ${KDE4_KDEUI_LIBS} + ${KDE4_KIO_LIBS} + ${KDE4_SOLID_LIBS} + ${KDE4_KUTILS_LIBS} ${NEPOMUK_LIBRARIES} - ${QT_QTXML_LIBRARY} + ${SOPRANO_LIBRARIES} ) install( @@ -27,6 +43,10 @@ DESTINATION ${SERVICES_INSTALL_DIR}) install( + FILES nepomukstrigiservice.notifyrc + DESTINATION ${DATA_INSTALL_DIR}/nepomukstrigiservice) + +install( TARGETS nepomukstrigiservice DESTINATION ${PLUGIN_INSTALL_DIR}) # ----------------------------- diff -Naur nepomuk/services/strigi/config.cpp nepomuk/services/strigi/config.cpp --- nepomuk/services/strigi/config.cpp 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/config.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,110 @@ +/* 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. +*/ + +#include "config.h" + +#include <QtCore/QStringList> +#include <QtCore/QDir> + +#include <kdirwatch.h> +#include <kstandarddirs.h> +#include <kconfiggroup.h> + + +Nepomuk::Config::Config() + : QObject(), + m_config( "nepomukstrigirc" ) +{ + KDirWatch* dirWatch = KDirWatch::self(); + connect( dirWatch, SIGNAL( dirty( const QString& ) ), + this, SLOT( slotConfigDirty() ) ); + connect( dirWatch, SIGNAL( created( const QString& ) ), + this, SLOT( slotConfigDirty() ) ); + dirWatch->addFile( KStandardDirs::locateLocal( "config", m_config.name() ) ); +} + + +Nepomuk::Config::~Config() +{ + m_config.group( "General" ).writeEntry( "first run", false ); +} + + +Nepomuk::Config* Nepomuk::Config::self() +{ + K_GLOBAL_STATIC( Config, _self ); + return _self; +} + + +QStringList Nepomuk::Config::folders() const +{ + return m_config.group( "General" ).readPathEntry( "folders", QStringList() << QDir::homePath() ); +} + + +bool Nepomuk::Config::recursive() const +{ + return m_config.group( "General" ).readEntry( "recursive", true ); +} + + +QStringList Nepomuk::Config::excludeFilters() const +{ + return m_config.group( "General" ).readEntry( "exclude filters", QStringList() << ".*/" << ".*" << "*~" << "*.part" ); +} + + +QStringList Nepomuk::Config::includeFilters() const +{ + return m_config.group( "General" ).readEntry( "include filters", QStringList() ); +} + + +KIO::filesize_t Nepomuk::Config::minDiskSpace() const +{ + // default: 200 MB + return m_config.group( "General" ).readEntry( "min disk space", KIO::filesize_t( 200*1024*1024 ) ); +} + + +void Nepomuk::Config::slotConfigDirty() +{ + m_config.reparseConfiguration(); + emit configChanged(); +} + + +bool Nepomuk::Config::showGui() const +{ + return m_config.group( "General" ).readEntry( "show gui", true ); +} + + +void Nepomuk::Config::setShowGui( bool showGui ) +{ + m_config.group( "General" ).writeEntry( "show gui", showGui ); +} + + +bool Nepomuk::Config::isInitialRun() const +{ + return m_config.group( "General" ).readEntry( "first run", true ); +} + +#include "config.moc" diff -Naur nepomuk/services/strigi/config.h nepomuk/services/strigi/config.h --- nepomuk/services/strigi/config.h 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/config.h 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,82 @@ +/* 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_STRIGI_CONFIG_H_ +#define _NEPOMUK_STRIGI_CONFIG_H_ + +#include <QtCore/QObject> + +#include <kconfig.h> +#include <kio/global.h> + + +namespace Nepomuk { + /** + * Active config class which emits signals if the config + * was changed, for example if the KCM saved the config file. + */ + class Config : public QObject + { + Q_OBJECT + + public: + ~Config(); + static Config* self(); + + /** + * The folders to search for files to analyse + */ + QStringList folders() const; + + /** + * Recurse into subdirs + */ + bool recursive() const; + + QStringList excludeFilters() const; + QStringList includeFilters() const; + + bool showGui() const; + void setShowGui( bool showGui ); + + /** + * The minimal available disk space. If it drops below + * indexing will be suspended. + */ + KIO::filesize_t minDiskSpace() const; + + /** + * true the first time the service is run (or after manually + * tampering with the config. + */ + bool isInitialRun() const; + + Q_SIGNALS: + void configChanged(); + + private Q_SLOTS: + void slotConfigDirty(); + + private: + Config(); + + KConfig m_config; + }; +} + +#endif diff -Naur nepomuk/services/strigi/eventmonitor.cpp nepomuk/services/strigi/eventmonitor.cpp --- nepomuk/services/strigi/eventmonitor.cpp 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/eventmonitor.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,178 @@ +/* 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. +*/ + +#include "eventmonitor.h" +#include "config.h" +#include "indexscheduler.h" +#include "filesystemwatcher.h" + +#include <KDebug> +#include <KPassivePopup> +#include <KLocale> +#include <KDiskFreeSpaceInfo> +#include <KStandardDirs> +#include <KNotification> +#include <KIcon> + +#include <Solid/PowerManagement> + +#include <QtDBus/QDBusInterface> + + +namespace { + void sendEvent( const QString& event, const QString& text, const QString& iconName ) { + KNotification::event( event, text, KIcon( iconName ).pixmap( 32, 32 ) ); + } +} + + +Nepomuk::EventMonitor::EventMonitor( IndexScheduler* scheduler, QObject* parent ) + : QObject( parent ), + m_indexScheduler( scheduler ), + m_pauseState( NotPaused ) +{ + // monitor the file system + m_fsWatcher = new FileSystemWatcher( this ); + connect( m_fsWatcher, SIGNAL( dirty( QString ) ), + m_indexScheduler, SLOT( updateDir( QString ) ) ); + + // update the watches if the config changes + connect( Config::self(), SIGNAL( configChanged() ), + this, SLOT( updateWatches() ) ); + + // start watching the index folders + updateWatches(); + + // FileSystemWatcher does not catch changes to files, only new and removed files + // thus, we also do periodic updates of the whole index every half hour + connect( &m_periodicUpdateTimer, SIGNAL( timeout() ), + m_indexScheduler, SLOT( updateAll() ) ); + m_periodicUpdateTimer.setInterval( 30*60*1000 ); + + // monitor the powermanagement to not drain the battery + connect( Solid::PowerManagement::notifier(), SIGNAL( appShouldConserveResourcesChanged( bool ) ), + this, SLOT( slotPowerManagementStatusChanged( bool ) ) ); + + // setup the avail disk usage monitor + connect( &m_availSpaceTimer, SIGNAL( timeout() ), + this, SLOT( slotCheckAvailableSpace() ) ); + m_availSpaceTimer.start( 20*1000 ); // every 20 seconds should be enough + + if ( Config::self()->isInitialRun() ) { + // TODO: add actions to this notification + + m_initialIndexTime.start(); + + // inform the user about the initial indexing + sendEvent( "initialIndexingStarted", + i18n( "Strigi file indexing started. Indexing all files for fast desktop searches may take a while." ), + "nepomuk" ); + + // connect to get the end of initial indexing + connect( m_indexScheduler, SIGNAL( indexingStopped() ), + this, SLOT( slotIndexingStopped() ) ); + } + else { + m_periodicUpdateTimer.start(); + } +} + + +Nepomuk::EventMonitor::~EventMonitor() +{ +} + + +void Nepomuk::EventMonitor::updateWatches() +{ + // the hard way since the KDirWatch API is too simple + QStringList folders = Config::self()->folders(); + if ( folders != m_fsWatcher->folders() || + Config::self()->recursive() != m_fsWatcher->watchRecursively() ) { + m_fsWatcher->setFolders( Config::self()->folders() ); + m_fsWatcher->setWatchRecursively( Config::self()->recursive() ); + m_fsWatcher->setInterval( 2*60 ); // check every 2 minutes + m_fsWatcher->start(); + } +} + + +void Nepomuk::EventMonitor::slotPowerManagementStatusChanged( bool conserveResources ) +{ + if ( !conserveResources && m_pauseState == PausedDueToPowerManagement ) { + kDebug() << "Resuming indexer due to power management"; + m_pauseState = NotPaused; + m_indexScheduler->resume(); + sendEvent( "indexingResumed", i18n("Resuming Strigi file indexing."), "solid" ); + } + else if ( m_indexScheduler->isRunning() && + !m_indexScheduler->isSuspended() ) { + kDebug() << "Pausing indexer due to power management"; + m_pauseState = PausedDueToPowerManagement; + m_indexScheduler->suspend(); + sendEvent( "indexingSuspended", i18n("Suspending Strigi file indexing to preserve resources."), "solid" ); + } +} + + +void Nepomuk::EventMonitor::slotCheckAvailableSpace() +{ + KDiskFreeSpaceInfo info = KDiskFreeSpaceInfo::freeSpaceInfo( KStandardDirs::locateLocal( "data", "nepomuk/repository/", false ) ); + if ( info.isValid() ) { + if ( info.available() <= Config::self()->minDiskSpace() ) { + if ( m_indexScheduler->isRunning() && + !m_indexScheduler->isSuspended() ) { + m_pauseState = PausedDueToAvailSpace; + m_indexScheduler->suspend(); + sendEvent( "indexingSuspended", + i18n("Local disk space is running low (%1 left). Suspending Strigi file indexing.", + KIO::convertSize( info.available() ) ), + "drive-harddisk" ); + } + } + else if ( m_pauseState == PausedDueToAvailSpace ) { + kDebug() << "Resuming indexer due to disk space"; + m_pauseState = NotPaused; + m_indexScheduler->resume(); + sendEvent( "indexingResumed", i18n("Resuming Strigi file indexing."), "drive-harddisk" ); + } + } + else { + // if it does not work once, it will probably never work + m_availSpaceTimer.stop(); + } +} + + +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(); + sendEvent( "initialIndexingFinished", i18n( "Strigi file indexing finished. Elapsed time: %1", m_initialIndexTime.toString() ), "nepomuk" ); + m_indexScheduler->disconnect( this ); + + // after this much index work, it makes sense to optimize the full text index in the main model + QDBusInterface( "org.kde.nepomuk.services.nepomukstorage", "/nepomukstorage", "org.kde.nepomuk.Storage" ).call( "optimize", "main" ); + + + m_periodicUpdateTimer.start(); + } +} + +#include "eventmonitor.moc" diff -Naur nepomuk/services/strigi/eventmonitor.h nepomuk/services/strigi/eventmonitor.h --- nepomuk/services/strigi/eventmonitor.h 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/eventmonitor.h 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,69 @@ +/* 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_STRIGI_EVENT_MONITOR_H_ +#define _NEPOMUK_STRIGI_EVENT_MONITOR_H_ + +#include <QtCore/QObject> +#include <QtCore/QStringList> +#include <QtCore/QTimer> +#include <QtCore/QTime> + +class KDiskFreeSpace; +class FileSystemWatcher; + +namespace Nepomuk { + + class IndexScheduler; + + class EventMonitor : public QObject + { + Q_OBJECT + + public: + EventMonitor( IndexScheduler* scheduler, QObject* parent ); + ~EventMonitor(); + + private Q_SLOTS: + void slotPowerManagementStatusChanged( bool conserveResources ); + void updateWatches(); + void slotCheckAvailableSpace(); + void slotIndexingStopped(); + + private: + enum { + NotPaused, + PausedDueToPowerManagement, + PausedDueToAvailSpace + }; + + IndexScheduler* m_indexScheduler; + int m_pauseState; + + FileSystemWatcher* m_fsWatcher; + + // timer used to periodically check for available space + QTimer m_availSpaceTimer; + + QTime m_initialIndexTime; + + QTimer m_periodicUpdateTimer; + }; +} + +#endif diff -Naur nepomuk/services/strigi/filesystemwatcher.cpp nepomuk/services/strigi/filesystemwatcher.cpp --- nepomuk/services/strigi/filesystemwatcher.cpp 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/filesystemwatcher.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,212 @@ +/* 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. +*/ + +#include "filesystemwatcher.h" + +#include <QtCore/QTimer> +#include <QtCore/QHash> +#include <QtCore/QDateTime> +#include <QtCore/QStringList> +#include <QtCore/QDirIterator> +#include <QtCore/QFileInfo> + +#include <KDebug> + + +namespace { + // small class to keep mem usage low + class FolderEntry + { + public: + FolderEntry() { + } + + FolderEntry( int m ) + : mTime( m ) { + } + + uint mTime; + QHash<QString, FolderEntry> children; + }; +} + +class FileSystemWatcher::Private +{ +public: + Private( FileSystemWatcher* parent ) + : recursive( true ), + interval( 10*60 ), + q( parent ) { + } + + QStringList folders; + QHash<QString, FolderEntry> cache; + bool recursive; + int interval; + + QTimer timer; + + void buildFolderCache( uint mTime ); + void checkFolders(); + +private: + void updateChildrenCache( const QString& parentPath, FolderEntry& parentEntry, bool signalNewEntries ); + void checkFolder( const QString& path, FolderEntry& folder ); + + FileSystemWatcher* q; +}; + + +void FileSystemWatcher::Private::buildFolderCache( uint mTime ) +{ + cache.clear(); + + foreach( QString folder, folders ) { + if ( folder.endsWith( '/' ) ) + folder.truncate( folder.length()-1 ); + FolderEntry entry( mTime ); + if ( recursive ) { + updateChildrenCache( folder, entry, false ); + } + cache.insert( folder, entry ); + } +} + + +void FileSystemWatcher::Private::updateChildrenCache( const QString& parentPath, FolderEntry& parentEntry, bool signalNewEntries ) +{ + QDirIterator dirIt( parentPath, QDir::NoDotAndDotDot|QDir::Readable|QDir::Dirs|QDir::NoSymLinks ); + while ( dirIt.hasNext() ) { + dirIt.next(); + if ( !parentEntry.children.contains( dirIt.fileName() ) ) { + FolderEntry entry( parentEntry.mTime ); + parentEntry.children.insert( dirIt.fileName(), entry ); + if ( signalNewEntries ) { + emit q->dirty( dirIt.filePath() ); + } + } + } + + for( QHash<QString, FolderEntry>::iterator it = parentEntry.children.begin(); + it != parentEntry.children.end(); ++it ) { + updateChildrenCache( parentPath + '/' + it.key(), it.value(), signalNewEntries ); + } +} + + +void FileSystemWatcher::Private::checkFolders() +{ + for( QHash<QString, FolderEntry>::iterator it = cache.begin(); + it != cache.end(); ++it ) { + checkFolder( it.key(), it.value() ); + } +} + + +void FileSystemWatcher::Private::checkFolder( const QString& path, FolderEntry& entry ) +{ + QFileInfo info( path ); + if ( info.exists() ) { + // check if anything changed in the folder + bool dirty = false; + if ( info.lastModified().toTime_t() > entry.mTime ) { + entry.mTime = info.lastModified().toTime_t(); + emit q->dirty( path ); + dirty = true; + } + + // check if any subfolder changed + for( QHash<QString, FolderEntry>::iterator it = entry.children.begin(); + it != entry.children.end(); ++it ) { + checkFolder( path + '/' + it.key(), it.value() ); + } + + // update in case folders have been created + if ( dirty ) { + updateChildrenCache( path, entry, true ); + } + } + // else -> FIXME: do we need to signal this or is it handled by the parent folder +} + + +FileSystemWatcher::FileSystemWatcher( QObject* parent ) + : QObject( parent ), + d( new Private( this ) ) +{ + connect( &d->timer, SIGNAL( timeout() ), + this, SLOT( checkFolders() ) ); +} + + +FileSystemWatcher::~FileSystemWatcher() +{ + delete d; +} + + +void FileSystemWatcher::start( const QDateTime& startTime ) +{ + stop(); + d->buildFolderCache( startTime.toTime_t() ); + d->timer.start( d->interval*1000 ); +} + + +void FileSystemWatcher::stop() +{ + d->timer.stop(); +} + + +QStringList FileSystemWatcher::folders() const +{ + return d->folders; +} + + +bool FileSystemWatcher::watchRecursively() const +{ + return d->recursive; +} + + +int FileSystemWatcher::interval() const +{ + return d->interval; +} + + +void FileSystemWatcher::setFolders( const QStringList& folders ) +{ + d->folders = folders; +} + + +void FileSystemWatcher::setWatchRecursively( bool r ) +{ + d->recursive = r; +} + + +void FileSystemWatcher::setInterval( int seconds ) +{ + d->interval = seconds; +} + +#include "filesystemwatcher.moc" diff -Naur nepomuk/services/strigi/filesystemwatcher.h nepomuk/services/strigi/filesystemwatcher.h --- nepomuk/services/strigi/filesystemwatcher.h 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/filesystemwatcher.h 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,78 @@ +/* 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 _FILE_SYSTEM_WATCHER_H_ +#define _FILE_SYSTEM_WATCHER_H_ + +#include <QtCore/QObject> +#include <QtCore/QDateTime> + + +/** + * Watches a file system by periodically checking the + * folder modification date. + */ +class FileSystemWatcher : public QObject +{ + Q_OBJECT + +public: + FileSystemWatcher( QObject* parent = 0 ); + ~FileSystemWatcher(); + + QStringList folders() const; + bool watchRecursively() const; + int interval() const; + +public Q_SLOTS: + void setFolders( const QStringList& folders ); + + /** + * Enabled by default. + */ + void setWatchRecursively( bool ); + + void setInterval( int seconds ); + + /** + * Actually start checking the folders. Once the FileSystemWatcher + * is started it will check the configured folders every \p interval() + * seconds. + * + * Be aware that changing the settings on a started FileSystemWatcher + * will have no effect until it is restarted. + */ + void start( const QDateTime& startTime = QDateTime::currentDateTime() ); + + void stop(); + +Q_SIGNALS: + /** + * Emitted if a folder is dirty, i.e. its contents + * changed. + */ + void dirty( const QString& folder ); + +private: + class Private; + Private* const d; + + Q_PRIVATE_SLOT( d, void checkFolders() ) +}; + +#endif diff -Naur nepomuk/services/strigi/indexscheduler.cpp nepomuk/services/strigi/indexscheduler.cpp --- nepomuk/services/strigi/indexscheduler.cpp 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/indexscheduler.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,431 @@ +/* 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 "indexscheduler.h" +#include "config.h" + +#include <QtCore/QMutexLocker> +#include <QtCore/QList> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtCore/QDirIterator> +#include <QtCore/QDateTime> +#include <QtCore/QByteArray> +#include <QtCore/QUrl> + +#include <KDebug> +#include <KTemporaryFile> + +#include <map> +#include <vector> + +#include <strigi/indexwriter.h> +#include <strigi/indexmanager.h> +#include <strigi/indexreader.h> +#include <strigi/analysisresult.h> +#include <strigi/fileinputstream.h> +#include <strigi/analyzerconfiguration.h> + + +class StoppableConfiguration : public Strigi::AnalyzerConfiguration { +public: + StoppableConfiguration() + : m_stop(false) { + } + + bool indexMore() const { + return !m_stop; + } + + bool addMoreText() const { + return !m_stop; + } + + void setStop( bool s ) { + m_stop = s; + } + +private: + bool m_stop; +}; + + +Nepomuk::IndexScheduler::IndexScheduler( Strigi::IndexManager* manager, QObject* parent ) + : QThread( parent ), + m_suspended( false ), + m_stopped( false ), + m_indexing( false ), + m_indexManager( manager ) +{ + m_analyzerConfig = new StoppableConfiguration; + + connect( Config::self(), SIGNAL( configChanged() ), + this, SLOT( readConfig() ) ); +} + + +Nepomuk::IndexScheduler::~IndexScheduler() +{ + delete m_analyzerConfig; +} + + +void Nepomuk::IndexScheduler::suspend() +{ + if ( isRunning() ) { + QMutexLocker locker( &m_resumeStopMutex ); + m_suspended = true; + } +} + + +void Nepomuk::IndexScheduler::resume() +{ + if ( isRunning() ) { + QMutexLocker locker( &m_resumeStopMutex ); + m_suspended = false; + m_resumeStopWc.wakeAll(); + } +} + + +void Nepomuk::IndexScheduler::setSuspended( bool suspended ) +{ + if ( suspended ) + suspend(); + else + resume(); +} + + +void Nepomuk::IndexScheduler::stop() +{ + if ( isRunning() ) { + QMutexLocker locker( &m_resumeStopMutex ); + m_stopped = true; + m_suspended = false; + m_analyzerConfig->setStop( true ); + m_dirsToUpdateWc.wakeAll(); + m_resumeStopWc.wakeAll(); + } +} + + +bool Nepomuk::IndexScheduler::isSuspended() const +{ + return isRunning() && m_suspended; +} + + +bool Nepomuk::IndexScheduler::isIndexing() const +{ + return m_indexing; +} + + +QString Nepomuk::IndexScheduler::currentFolder() const +{ + return m_currentFolder; +} + + +void Nepomuk::IndexScheduler::setIndexingStarted( bool started ) +{ + if ( started != m_indexing ) { + m_indexing = started; + if ( m_indexing ) + emit indexingStarted(); + else + emit indexingStopped(); + } +} + + +void Nepomuk::IndexScheduler::run() +{ + // set lowest priority for this thread + setPriority( QThread::IdlePriority ); + + // initialization + m_suspended = false; + m_stopped = false; + m_analyzerConfig->setStop( false ); + readConfig(); + + Strigi::StreamAnalyzer analyzer( *m_analyzerConfig ); + analyzer.setIndexWriter( *m_indexManager->indexWriter() ); + + setIndexingStarted( true ); + + // do the actual indexing + m_dirsToUpdate.clear(); + foreach( const QString& f, Config::self()->folders() ) + m_dirsToUpdate << qMakePair( f, Config::self()->recursive() ); + + m_startedRecursive = Config::self()->recursive(); + + while ( 1 ) { + // wait for more dirs to analyze in case the initial + // indexing is done + if ( m_dirsToUpdate.isEmpty() ) { + setIndexingStarted( false ); + + m_dirsToUpdateMutex.lock(); + m_dirsToUpdateWc.wait( &m_dirsToUpdateMutex ); + m_dirsToUpdateMutex.unlock(); + + if ( !m_stopped ) + setIndexingStarted( true ); + } + + // wait for resume or stop (or simply continue) + if ( !waitForContinue() ) { + break; + } + + // get the next folder + m_dirsToUpdateMutex.lock(); + QPair<QString, bool> dir = *m_dirsToUpdate.begin(); + m_dirsToUpdate.erase( m_dirsToUpdate.begin() ); + m_dirsToUpdateMutex.unlock(); + + // update until stopped + if ( !updateDir( dir.first, &analyzer, dir.second ) ) { + break; + } + m_currentFolder.clear(); + } + + setIndexingStarted( false ); +} + + +// this method should be thread-safe ("should" because of the indexreader and -writer) +bool Nepomuk::IndexScheduler::updateDir( const QString& dir, Strigi::StreamAnalyzer* analyzer, bool recursive ) +{ +// kDebug() << dir << analyzer << recursive; + + m_currentFolder = dir; + + // get a map of all indexed files from the dir including their stored mtime + std::map<std::string, time_t> filesInStore; + m_indexManager->indexReader()->getChildren( QFile::encodeName( dir ).data(), filesInStore ); + std::map<std::string, time_t>::const_iterator filesInStoreEnd = filesInStore.end(); + + QList<QFileInfo> filesToIndex; + QList<QString> subFolders; + std::vector<std::string> filesToDelete; + + // iterate over all files in the dir + // and select the ones we need to add or delete from the store + QDirIterator dirIt( dir, QDir::NoDotAndDotDot|QDir::Readable|QDir::Files|QDir::Dirs ); + while ( dirIt.hasNext() ) { + QString path = dirIt.next(); + + QFileInfo fileInfo = dirIt.fileInfo(); + + // check if this file is new by looking it up in the store + std::map<std::string, time_t>::iterator filesInStoreIt = filesInStore.find( QFile::encodeName( path ).data() ); + bool newFile = ( filesInStoreIt == filesInStoreEnd ); + + // do we need to update? Did the file change? + bool fileChanged = !newFile && fileInfo.lastModified().toTime_t() != filesInStoreIt->second; + + if ( newFile || fileChanged ) + filesToIndex << fileInfo; + + if ( !newFile && fileChanged ) + filesToDelete.push_back( filesInStoreIt->first ); + + // cleanup a bit for faster lookups + if ( !newFile ) + filesInStore.erase( filesInStoreIt ); + + if ( recursive && fileInfo.isDir() && !fileInfo.isSymLink() ) + subFolders << path; + } + + // all the files left in filesInStore are not in the current + // directory and should be deleted + for ( std::map<std::string, time_t>::const_iterator it = filesInStore.begin(); + it != filesInStoreEnd; ++it ) { + filesToDelete.push_back( it->first ); + } + + // inform interested clients + if ( !filesToIndex.isEmpty() || !filesToDelete.empty() ) + emit indexingFolder( dir ); + + // remove all files that need updating or have been removed + m_indexManager->indexWriter()->deleteEntries( filesToDelete ); + + // analyse all files that are new or need updating + foreach( const QFileInfo& file, filesToIndex ) { + + analyzeFile( file, analyzer ); + + // wait if we are suspended or return if we are stopped + if ( !waitForContinue() ) + return false; + } + + // recurse into subdirs (we do this in a separate loop to always keep a proper state: + // compare m_currentFolder) + if ( recursive ) { + foreach( const QString& folder, subFolders ) { + if ( !updateDir( folder, analyzer, true ) ) + return false; + } + } + + return true; +} + + +void Nepomuk::IndexScheduler::analyzeFile( const QFileInfo& file, Strigi::StreamAnalyzer* analyzer ) +{ +// kDebug() << file.filePath(); + + Strigi::AnalysisResult analysisresult( QFile::encodeName( file.filePath() ).data(), + file.lastModified().toTime_t(), + *m_indexManager->indexWriter(), + *analyzer, + QFile::encodeName( file.path() ).data() ); + if ( file.isFile() && !file.isSymLink() ) { + Strigi::FileInputStream stream( QFile::encodeName( file.filePath() ) ); + analysisresult.index( &stream ); + } + else { + analysisresult.index(0); + } +} + + +bool Nepomuk::IndexScheduler::waitForContinue() +{ + QMutexLocker locker( &m_resumeStopMutex ); + if ( m_suspended ) { + setIndexingStarted( false ); + m_resumeStopWc.wait( &m_resumeStopMutex ); + setIndexingStarted( true ); + } + + return !m_stopped; +} + + +void Nepomuk::IndexScheduler::updateDir( const QString& path ) +{ + QMutexLocker lock( &m_dirsToUpdateMutex ); + m_dirsToUpdate << qMakePair( path, false ); + m_dirsToUpdateWc.wakeAll(); +} + + +void Nepomuk::IndexScheduler::updateAll() +{ + QMutexLocker lock( &m_dirsToUpdateMutex ); + foreach( const QString& f, Config::self()->folders() ) + m_dirsToUpdate << qMakePair( f, true ); + m_dirsToUpdateWc.wakeAll(); +} + + +void Nepomuk::IndexScheduler::readConfig() +{ + // load Strigi configuration + std::vector<std::pair<bool, std::string> > filters; + QStringList excludeFilters = Config::self()->excludeFilters(); + QStringList includeFilters = Config::self()->includeFilters(); + foreach( const QString& filter, excludeFilters ) { + filters.push_back( std::make_pair<bool, std::string>( false, filter.toUtf8().data() ) ); + } + foreach( const QString& filter, includeFilters ) { + filters.push_back( std::make_pair<bool, std::string>( true, filter.toUtf8().data() ) ); + } + m_analyzerConfig->setFilters(filters); + + // if the recursion setting changed, update everything again + // FIXME: this does not really help if the new value is false! + if ( m_startedRecursive != Config::self()->recursive() ) { + QMutexLocker lock( &m_dirsToUpdateMutex ); + foreach( const QString& f, Config::self()->folders() ) + m_dirsToUpdate << qMakePair( f, Config::self()->recursive() ); + m_dirsToUpdateWc.wakeAll(); + } +} + + +namespace { + class QDataStreamStrigiBufferedStream : public Strigi::BufferedStream<char> + { + public: + QDataStreamStrigiBufferedStream( QDataStream& stream ) + : m_stream( stream ) { + } + + int32_t fillBuffer( char* start, int32_t space ) { + int r = m_stream.readRawData( start, space ); + if ( r == 0 ) { + // Strigi's API is so weird! + return -1; + } + else if ( r < 0 ) { + // Again: weird API. m_status is a protected member of StreamBaseBase (yes, 2x Base) + m_status = Strigi::Error; + return -1; + } + else { + return r; + } + } + + private: + QDataStream& m_stream; + }; +} + + +void Nepomuk::IndexScheduler::analyzeResource( const QUrl& uri, const QDateTime& modificationTime, QDataStream& data ) +{ + QDateTime existingMTime = QDateTime::fromTime_t( m_indexManager->indexReader()->mTime( uri.toEncoded().data() ) ); + if ( existingMTime < modificationTime ) { + // remove the old data + std::vector<std::string> entries; + entries.push_back( uri.toEncoded().data() ); + m_indexManager->indexWriter()->deleteEntries( entries ); + + // create the new + Strigi::StreamAnalyzer analyzer( *m_analyzerConfig ); + analyzer.setIndexWriter( *m_indexManager->indexWriter() ); + Strigi::AnalysisResult analysisresult( uri.toEncoded().data(), + modificationTime.toTime_t(), + *m_indexManager->indexWriter(), + analyzer ); + QDataStreamStrigiBufferedStream stream( data ); + analysisresult.index( &stream ); + } + else { + kDebug() << uri << "up to date"; + } +} + +#include "indexscheduler.moc" diff -Naur nepomuk/services/strigi/indexscheduler.h nepomuk/services/strigi/indexscheduler.h --- nepomuk/services/strigi/indexscheduler.h 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/indexscheduler.h 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,140 @@ +/* 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_STRIGI_INDEX_SCHEDULER_H_ +#define _NEPOMUK_STRIGI_INDEX_SCHEDULER_H_ + +#include <QtCore/QThread> +#include <QtCore/QMutex> +#include <QtCore/QWaitCondition> +#include <QtCore/QSet> + + +namespace Strigi { + class StreamAnalyzer; + class IndexManager; +} + +class StoppableConfiguration; +class QFileInfo; +class QUrl; +class QDateTime; +class QByteArray; + + +namespace Nepomuk { + /** + * The IndexScheduler performs the normal indexing, + * ie. the initial indexing and the timed updates + * of all files. + * + * Events are not handled. + */ + class IndexScheduler : public QThread + { + Q_OBJECT + + public: + IndexScheduler( Strigi::IndexManager* manager, QObject* parent ); + ~IndexScheduler(); + + bool isSuspended() const; + bool isIndexing() const; + + /** + * The folder currently being indexed. Empty if not indexing. + * If suspended the folder might still be set! + */ + QString currentFolder() const; + + public Q_SLOTS: + void suspend(); + void resume(); + void stop(); + + void setSuspended( bool ); + + /** + * Slot to connect to certain event systems like KDirNotify + * or KDirWatch + * + * Updates a complete folder (non-recursively). Makes sense for + * signals like KDirWatch::dirty. + */ + void updateDir( const QString& path ); + + /** + * Updates all configured folders. + */ + void updateAll(); + + /** + * Analyze a resource that is not read from the local harddisk. + * + * \param uri The resource URI to identify the resource. + * \param modificationTime The modification date of the resource. Used to determine if + * an actual update is necessary. + * \data The data to analyze, ie. the contents of the resource. + */ + void analyzeResource( const QUrl& uri, const QDateTime& modificationTime, QDataStream& data ); + + Q_SIGNALS: + void indexingStarted(); + void indexingStopped(); + void indexingFolder( const QString& ); + + private Q_SLOTS: + void readConfig(); + + private: + void run(); + + bool waitForContinue(); + bool updateDir( const QString& dir, Strigi::StreamAnalyzer* analyzer, bool recursive ); + void analyzeFile( const QFileInfo& file, Strigi::StreamAnalyzer* analyzer ); + + // emits indexingStarted or indexingStopped based on parameter. Makes sure + // no signal is emitted twice + void setIndexingStarted( bool started ); + + bool m_suspended; + bool m_stopped; + bool m_indexing; + + // true if recursion was configured at start + // if this differs from the new value when the + // config changes, all folders are updated again + bool m_startedRecursive; + + QMutex m_resumeStopMutex; + QWaitCondition m_resumeStopWc; + + StoppableConfiguration* m_analyzerConfig; + Strigi::IndexManager* m_indexManager; + + // set of folders to update (+recursive flag) - changed by updateDir + QSet<QPair<QString, bool> > m_dirsToUpdate; + + QMutex m_dirsToUpdateMutex; + QWaitCondition m_dirsToUpdateWc; + + QString m_currentFolder; + }; +} + +#endif diff -Naur nepomuk/services/strigi/nepomukstrigiservice.desktop nepomuk/services/strigi/nepomukstrigiservice.desktop --- nepomuk/services/strigi/nepomukstrigiservice.desktop 2008-08-28 10:07:16.000000000 +0200 +++ nepomuk/services/strigi/nepomukstrigiservice.desktop 2008-09-01 14:33:17.000000000 +0200 @@ -2,11 +2,10 @@ Type=Service X-KDE-ServiceTypes=NepomukService X-KDE-Library=nepomukstrigiservice -X-KDE-Nepomuk-autostart=false +X-KDE-Nepomuk-autostart=true X-KDE-Nepomuk-start-on-demand=false Name=Nepomuk Strigi Service Name[af]=Nepomuk Strigi diens -Name[ar]=Nepomuk خدمة بحث سطح المكتب Name[bg]=Услуга Nepomuk Strigi Name[bn_IN]=Nepomuk Strigi পরিসেবা Name[ca]=Servei Strigi del Nepomuk @@ -47,6 +46,7 @@ Name[sr]=Непомуков сервис Стригија Name[sr@latin]=Nepomukov servis Strigija Name[sv]=Nepomuk-Strigitjänst +Name[te]=Nepomuk Strigi సేవ Name[tg]=Хидматҳои Nepomuk Strigi Name[th]=บริการ Nepomuk Strigi Name[tr]=Nepomuk Strigi Servisi @@ -58,7 +58,6 @@ Name[zh_CN]=Nepomuk Strigi 服务 Name[zh_TW]=Nepomuk Strigi 服務 Comment=Nepomuk Service which controls the strigidaemon, i.e. indexes files on the desktop -Comment[ar]=خدمة Nepomuk للبحث على سطح المكتب Comment[bg]=Услуга, която контролира демона на Strigi, напр. файлове с индекси Comment[ca]=Servei del Nepomuk que controla el strigidaemon, p.ex. indexa els fitxers de l'escriptori Comment[csb]=Ùsłëznota Nepomuka, jakô sprôwiô demonã strigi, to òznôczô: indeksëje lopczi na pùlce @@ -92,6 +91,7 @@ Comment[sr]=Сервис Непомука за управљање демоном Стригија, тј. индексирање фајлова Comment[sr@latin]=Servis Nepomuka za upravljanje demonom Strigija, tj. indeksiranje fajlova Comment[sv]=Nepomuk-tjänst som styr Strigi-demonen, dvs. indexerar filer på skrivbordet +Comment[te]=Nepomuk సేవ strigidaemon ను నియత్రిస్తుంది, అంటే. డెస్క్టాప్ పైన దస్త్రములను క్రమపరుస్తుంది Comment[th]=บริการของ Nepomuk สำหรับสำหรับควบคุมดีมอน strigidaemon ที่ทำหน้าที่ เช่น สร้างดัชนีแฟ้มสำหรับพื้นที่ทำงาน เป็นต้น Comment[tr]=Strigidaemon uygulamasını yöneten Nepomuk servisi, masaüstünüzdeki dosyaları indeksleyen bir uygulama Comment[uk]=Служба Nepomuk, яка контролює фонову службу strigi, тобто, індексує файли на стільниці diff -Naur nepomuk/services/strigi/nepomukstrigiservice.notifyrc nepomuk/services/strigi/nepomukstrigiservice.notifyrc --- nepomuk/services/strigi/nepomukstrigiservice.notifyrc 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/nepomukstrigiservice.notifyrc 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,158 @@ +[Global] +IconName=nepomuk +Comment=The Nepomuk Strigi file indexer +Comment[et]=Nepomuki Strigi failide indekseerija +Comment[gl]=O indexador de ficheiros Strigi para Nepomuk +Comment[gu]=નેપોમુક સ્ટ્રિગિ ફાઇલ ઇન્ડેક્સર +Comment[km]=កម្មវិធីបង្កើតលិបិក្រមឯកសាររបស់ Nepomuk Strigi +Comment[nb]=Nepomuk Strigi filindekseringen +Comment[nds]=De Nepomuk-Dateiindizeerdeenst Strigi +Comment[nn]=Nepomuk Strigi – filindeksering +Comment[pt]=O serviço de indexação de ficheiros Strigi para o Nepomuk +Comment[pt_BR]=O serviço de indexação de ficheiros Strigi para o Nepomuk +Comment[sl]=Indeksirnik datotek Nepomuk Strigi +Comment[sv]=Nepomuk Strigi-filindexering +Comment[te]=Nepomuk Strigi దస్త్ర విషయసూచకి +Comment[tr]=Nepomuk Strigi dosya indeksleyici +Comment[uk]=Служба Strigi Nepomuk для індексування файлів +Comment[zh_TW]=Nepomuk Strigi 檔案索引服務 + +[Event/initialIndexingStarted] +Name=Initial Indexing started +Name[et]=Esmaindekseerimine on käivitatud +Name[gl]=Iniciouse a indexación inicial +Name[gu]=શરૂઆતનું ઇન્ડેક્સીંગ શરૂ થયેલ છે +Name[km]=បានចាប់ផ្ដើមការបង្កើតលិបិក្រមដំបូង +Name[nb]=Første indeksering har startet +Name[nds]=Eerst Indizeren anfungen +Name[nn]=Førsteindekseringa har starta +Name[pt]=Início da primeira indexação +Name[pt_BR]=Início da primeira indexação +Name[sl]=Pričelo se je začetno indeksiranje +Name[sv]=Inledande indexering startad +Name[te]=ప్రాధమిక విషయవర్గీకరణ ప్రారంభమైంది +Name[tr]=Temel İndeksleme başladı +Name[uk]=Запущено початкове індексування +Name[zh_TW]=初始化索引已開始 +Comment=Strigi started the initial indexing of local files for fast desktop searches +Comment[et]=Strigi alustas kohalike failide esimest indekseerimist kiire töölauaotsingu võimaldamiseks +Comment[gl]=Strigi comezou a indexación inicial dos ficheiros locais para facer procuras rápidas no escritorio +Comment[gu]=સ્ટ્રીગીએ ઝડપી ડેસ્કટોપ શોધ માટે સ્થાનિક ફાઇલોનું શરૂઆતી ઇન્ડેક્સીંગ ચાલુ કર્યું છે +Comment[km]=បានចាប់ផ្ដើមការបង្កើតលិបិក្រមដំបូងរបស់ Strigi នៃឯកសារមូលដ្ឋានសម្រាប់ការស្វែងរកផ្ទៃតុរហ័ស +Comment[nb]=Strigi startet den første indekseringen av lokale filer som vil gjøre søk raskere +Comment[nds]=Strigi hett mit dat eerste Indizeren vun lokaal Dateien anfungen, dat hölp bi't gaue Söken op den Schriefdisch +Comment[nn]=Strigi starta førsteindekseringa av lokale filer for snøgge skrivebordsøk +Comment[pt]=O Strigi iniciou a primeira indexação dos ficheiros para pesquisas mais rápidas +Comment[pt_BR]=O Strigi iniciou a primeira indexação dos ficheiros para pesquisas mais rápidas +Comment[sl]=Strigi je pričel z začetnim indeksiranjem krajevnih datotek, da bo namizno iskanje hitro +Comment[sv]=Strigi har startat den inledande indexeringen av lokala filer för snabb skrivbordssökning +Comment[te]=వేగమైన డెస్క్ టాప్ శోధనలకొరకు Strigi స్థానిక దస్త్రముల ప్రాధమిక విషయవర్గీకరణను ప్రారంభించింది. +Comment[tr]=Strigi hızlı masaüstü araması için yerel dosyaların temel indeksleme işlemine başladı +Comment[uk]=Програма Strigi запустила початкове індексування локальних файлів для швидкого стільничного пошуку +Comment[zh_TW]=Strigi 已開始初始化本地檔案的索引 +Action=Popup + +[Event/initialIndexingFinished] +Name=Initial Indexing finished +Name[et]=Esmaindekseerimine on lõpetatud +Name[gl]=Rematou a indexación inicial +Name[gu]=શરૂઆતનું ઇન્ડેક્સીંગ પૂર્ણ થયેલ છે +Name[km]=បានបញ្ចប់ការបង្កើតលិបិក្រមដំបូង +Name[nb]=Første indeksering er ferdig +Name[nds]=Eerst Indizeren afslaten +Name[nn]=Førsteindekseringa er ferdig +Name[pt]=Fim da primeira indexação +Name[pt_BR]=Fim da primeira indexação +Name[sl]=Začetno indeksiranje se je zaključilo +Name[sv]=Inledande indexering klar +Name[te]=ప్రాధమిక విషయవర్గీకరణ పూర్తైనది. +Name[tr]=Temel İndeksleme tamamlandı +Name[uk]=Початкове індексування закінчено +Name[zh_TW]=初始化索引已完成 +Comment=Strigi finished the initial indexing of local files for fast desktop searches +Comment[et]=Strigi lõpetas kohalike failide esimese indekseerimise kiire töölauaotsingu võimaldamiseks +Comment[gl]=Strigi rematou a indexación inicial dos ficheiros locais para facer procuras rápidas no escritorio +Comment[gu]=સ્ટ્રીગીએ ઝડપી ડેસ્કટોપ શોધ માટે સ્થાનિક ફાઇલોનું શરૂઆતી ઇન્ડેક્સીંગ પૂર્ણ કર્યું છે +Comment[km]=បានបញ្ចប់កការបង្កើតលិបិក្រមរបស់ Strigi នៃឯកសារមូលដ្ឋានសម្រាប់ការស្វែងរកផ្ទៃតុរហ័ស +Comment[nb]=Strigi gjorde ferdig første indeksering av lokale filer som vil gjøre søk raskere +Comment[nds]=Strigi hett dat eerste Indizeren vun lokaal Dateien afslaten, dat hölp bi't gaue Söken op den Schriefdisch +Comment[nn]=Strigi er ferdig med førsteindekseringa av lokale filer for snøgge skrivebordsøk +Comment[pt]=O Strigi terminou a primeira indexação dos ficheiros para pesquisas mais rápidas +Comment[pt_BR]=O Strigi terminou a primeira indexação dos ficheiros para pesquisas mais rápidas +Comment[sl]=Strigi je zaključil z začetnim indeksiranjem krajevnih datotek za hitro namizno iskanje +Comment[sv]=Strigi har gjort färdig den inledande indexeringen av lokala filer för snabb skrivbordssökning +Comment[te]=వేగమైన డెస్క్ టాప్ శోధనలకొరకు Strigi స్థానిక దస్త్రములయొక్క విషయవర్గీకరణ పూర్తైనది +Comment[tr]=Strigi hızlı masaüstü araması için yerel dosyaların temel indeksleme işlemini tamamladı +Comment[uk]=Програма Strigi завершила початкове індексування локальних файлів для швидкого стільничного пошуку +Comment[zh_TW]=Strigi 已完成本地端檔案的初始化索引 +Action=Popup + +[Event/indexingSuspended] +Name=Indexing suspended +Name[et]=Indekseerimine on peatatud +Name[gl]=Suspendeuse a indexación +Name[gu]=ઇન્ડેક્સીંગ બંધ કરવામાં આવ્યું +Name[km]=បានផ្អាកការដាក់លិបិក្រម +Name[nb]=Indekseringen stoppet midleridig +Name[nds]=Indizeren anhollen +Name[nn]=Indekseringa vart stoppa +Name[pt]=Indexação suspensa +Name[pt_BR]=Indexação suspensa +Name[sl]=Indeksiranje je zaustavljeno +Name[sv]=Indexering tillfälligt stoppad +Name[te]=విషయవర్దీకరణ సంస్పెండ్ చేయబడింది +Name[tr]=İndeksleme beklemeye alındı +Name[uk]=Пауза індексування +Name[zh_TW]=索引暫停 +Comment=Strigi file indexing has been suspended +Comment[et]=Strigi failide indekseerimine on peatatud +Comment[gl]=A indexación de ficheiros con Strigi suspendeuse +Comment[gu]=સ્ટ્રીગીએ ફાઇલ ઇન્ડેક્સીંગ બંધ કરવામાં આવ્યું છે +Comment[km]=បានផ្អាកការបង្កើតលិបិក្រមឯកសាររបស់ Strigi +Comment[nb]=Strigi filindeksering har blitt stoppet midlertidig +Comment[nds]=Strigi hett mit dat Indizeren vun Dateien anhollen +Comment[nn]=Filindekseringa med Strigi vart stoppa +Comment[pt]=A indexação de ficheiros do Strigi foi suspensa +Comment[pt_BR]=A indexação de ficheiros do Strigi foi suspensa +Comment[sl]=Indeksiranje datotek s Strigijem je zaustavljeno +Comment[sv]=Strigi filindexering har tillfälligt stoppats +Comment[te]=Strigi దస్త్రము విషయవర్గీకరణ సస్పెండ్ చేయబడింది +Comment[tr]=Strigi dosya indeksleyici beklemeye alındı +Comment[uk]=Пауза індексування файлів програмою Strigi +Comment[zh_TW]=Strigi 檔案索引已被暫停 +Action=Popup + +[Event/indexingResumed] +Name=Indexing resumed +Name[et]=Indekseerimine jätkub +Name[gl]=Continuouse a indexación +Name[gu]=ઇન્ડેક્સીંગ પુન: શરૂ કરવામાં આવ્યું +Name[km]=បានបន្តការបង្កើតលិបិក្រម +Name[nb]=Indekseringen fortsetter +Name[nds]=Indizeren geiht wieder +Name[nn]=Indekseringa held fram +Name[pt]=Indexação prosseguida +Name[pt_BR]=Indexação prosseguida +Name[sl]=Indeksiranje se nadaljuje +Name[sv]=Indexering återupptagen +Name[te]=విషయవర్గీకరణ తిరిగికొనసాగించబడింది +Name[tr]=İndeksleme çalışmaya devam ettirildi +Name[uk]=Продовження індексування +Name[zh_TW]=索引回復 +Comment=Strigi file indexing has been resumed +Comment[et]=Strigi failide indekseerimine jätkub +Comment[gl]=Continúase a indexación de ficheiros con Strigi +Comment[gu]=સ્ટ્રીગીએ ફાઇલ ઇન્ડેક્સીંગ પુન: શરૂ કરવામાં આવ્યું છે +Comment[km]=បានបន្តការបង្កើតលិបិក្រមឯកសាររបស់ Strigi +Comment[nb]=Strigi filindeksering er gjenopptatt +Comment[nds]=Strigi maakt mit dat Indizeren vun Dateien wieder +Comment[nn]=Filindekseringa med Strigi held fram +Comment[pt]=Prosseguiu-se com a indexação de ficheiros no Strigi +Comment[pt_BR]=Prosseguiu-se com a indexação de ficheiros no Strigi +Comment[sl]=Indeksiranje datotek s Strigijem se nadaljuje +Comment[sv]=Strigi filindexering har återupptagits +Comment[te]=Strigi దస్త్రము విషయవర్గీకరణ తిరిగికొనసాగించబడింది +Comment[tr]=Strigi dosya indeksleyici çalışmaya devam ettirildi +Comment[uk]=Strigi продовжує індексування файлів +Comment[zh_TW]=Strigi 檔案索引已回復 +Action=Popup diff -Naur nepomuk/services/strigi/priority.cpp nepomuk/services/strigi/priority.cpp --- nepomuk/services/strigi/priority.cpp 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/priority.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,100 @@ +/* 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> +#include <sys/syscall.h> +#include <errno.h> + +#include <sched.h> + + +#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() +{ + return !setpriority( PRIO_PROCESS, 0, 19 ); +} + + +// FIXME: is this really useful? Should we better use SCHED_IDLE? +bool lowerSchedulingPriority() +{ +#ifdef SCHED_BATCH + struct sched_param param; + memset( ¶m, 0, sizeof(param) ); + param.sched_priority = 0; + return !sched_setscheduler( 0, SCHED_BATCH, ¶m ); +#else + return false; +#endif +} diff -Naur nepomuk/services/strigi/priority.h nepomuk/services/strigi/priority.h --- nepomuk/services/strigi/priority.h 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/priority.h 2008-09-01 14:33:17.000000000 +0200 @@ -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_PRIO_H_ +#define _NEPOMUK_LINUX_PRIO_H_ + +bool lowerIOPriority(); +bool lowerSchedulingPriority(); +bool lowerPriority(); + +#endif diff -Naur nepomuk/services/strigi/statuswidget.cpp nepomuk/services/strigi/statuswidget.cpp --- nepomuk/services/strigi/statuswidget.cpp 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/statuswidget.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,209 @@ +/* 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. +*/ + +#include "statuswidget.h" +#include "indexscheduler.h" + +#include <KCMultiDialog> +#include <KIcon> +#include <KLocale> +#include <KTitleWidget> +#include <KStandardDirs> +#include <KIO/NetAccess> +#include <kio/directorysizejob.h> + +#include <Soprano/Model> +#include <Soprano/QueryResultIterator> +#include <Soprano/Vocabulary/Xesam> + +#include <QtCore/QTimer> + + +Nepomuk::StatusWidget::StatusWidget( Soprano::Model* model, IndexScheduler* scheduler, QWidget* parent ) + : KDialog( parent ), + m_model( model ), + m_indexScheduler( scheduler ), + m_connected( false ), + m_updating( false ), + m_updateRequested( false ) +{ + setupUi( mainWidget() ); + + setCaption( m_title->text() ); + setButtons( Ok|User1 ); + setDefaultButton( Ok ); + setButtonGuiItem( User1, KGuiItem( i18n( "Configure" ), KIcon( "configure" ) ) ); + + m_title->setPixmap( KIcon( "nepomuk" ).pixmap( 32, 32 ) ); + + m_updateTimer.setSingleShot( true ); + m_updateTimer.setInterval( 10*1000 ); // do not update multiple times in 10 seconds + connect( &m_updateTimer, SIGNAL( timeout() ), + this, SLOT( slotUpdateTimeout() ) ); + + connect( this, SIGNAL( user1Clicked() ), + this, SLOT( slotConfigure() ) ); +} + + +Nepomuk::StatusWidget::~StatusWidget() +{ +} + + +void Nepomuk::StatusWidget::slotUpdateStrigiStatus() +{ + bool indexing = m_indexScheduler->isIndexing(); + bool suspended = m_indexScheduler->isSuspended(); + QString folder = m_indexScheduler->currentFolder(); + + if ( suspended ) + m_labelStrigiState->setText( i18n( "File indexer is suspended" ) ); + else if ( indexing ) + m_labelStrigiState->setText( i18n( "Strigi is currently indexing files in folder %1", folder ) ); + else + m_labelStrigiState->setText( i18n( "File indexer is idle" ) ); +} + + +void Nepomuk::StatusWidget::slotUpdateStoreStatus() +{ + if ( !m_updating && !m_updateTimer.isActive() ) { + m_updating = true; + + // update storage size + // ======================================== + QString path = KStandardDirs::locateLocal( "data", "nepomuk/repository/main/", false ); + KIO::DirectorySizeJob* job = KIO::directorySize( path ); + if ( KIO::NetAccess::synchronousRun( job, this ) ) + m_labelStoreSize->setText( KIO::convertSize( job->totalSize() ) ); + else + m_labelStoreSize->setText( i18n( "Calculation failed" ) ); + + + // update file count + // ======================================== + Soprano::QueryResultIterator it = m_model->executeQuery( QString( "select distinct ?r where { ?r a <%1> . }" ) + .arg( Soprano::Vocabulary::Xesam::File().toString() ), + Soprano::Query::QueryLanguageSparql ); + int cnt = 0; + while ( it.next() ) { + // a bit of hacking to keep the GUI responsive + // TODO: if we don't get aggregate functions in SPARQL soon, use a thread + if ( cnt % 100 == 0 ) + QApplication::processEvents(); + ++cnt; + } + m_labelFileCount->setText( i18np( "1 file in index", "%1 files in index", cnt ) ); + + m_updating = false; + + // start the timer to avoid too many updates + m_updateTimer.start(); + } + else { + m_updateRequested = true; + } +} + + +void Nepomuk::StatusWidget::slotUpdateTimeout() +{ + if ( m_updateRequested ) { + m_updateRequested = false; + slotUpdateStoreStatus(); + } +} + + +void Nepomuk::StatusWidget::slotConfigure() +{ + KCMultiDialog dlg; + dlg.addModule( "kcm_nepomuk" ); + dlg.exec(); +} + +#include <QApplication> +#include <QDesktopWidget> + +// from kdialog.cpp since KDialog::centerOnScreen will simply do nothing on X11! +static QRect screenRect( QWidget *widget, int screen ) +{ + QDesktopWidget *desktop = QApplication::desktop(); + KConfig gc( "kdeglobals", KConfig::NoGlobals ); + KConfigGroup cg(&gc, "Windows" ); + if ( desktop->isVirtualDesktop() && + cg.readEntry( "XineramaEnabled", true ) && + cg.readEntry( "XineramaPlacementEnabled", true ) ) { + + if ( screen < 0 || screen >= desktop->numScreens() ) { + if ( screen == -1 ) + screen = desktop->primaryScreen(); + else if ( screen == -3 ) + screen = desktop->screenNumber( QCursor::pos() ); + else + screen = desktop->screenNumber( widget ); + } + + return desktop->availableGeometry( screen ); + } else + return desktop->geometry(); +} + +void Nepomuk::StatusWidget::showEvent( QShowEvent* event ) +{ + if ( !m_connected ) { + connect( m_indexScheduler, SIGNAL( indexingStarted() ), + this, SLOT( slotUpdateStrigiStatus() ) ); + connect( m_indexScheduler, SIGNAL( indexingStopped() ), + this, SLOT( slotUpdateStrigiStatus() ) ); + connect( m_indexScheduler, SIGNAL( indexingFolder(QString) ), + this, SLOT( slotUpdateStrigiStatus() ) ); + + connect( m_model, SIGNAL( statementsAdded() ), + this, SLOT( slotUpdateStoreStatus() ) ); + connect( m_model, SIGNAL( statementsRemoved() ), + this, SLOT( slotUpdateStoreStatus() ) ); + + m_connected = true; + } + + QTimer::singleShot( 0, this, SLOT( slotUpdateStoreStatus() ) ); + QTimer::singleShot( 0, this, SLOT( slotUpdateStrigiStatus() ) ); + + KDialog::showEvent( event ); + + QRect rect = screenRect( this, -1 ); + move( rect.center().x() - width() / 2, + rect.center().y() - height() / 2 ); + //KDialog::centerOnScreen( this ); +} + + +void Nepomuk::StatusWidget::hideEvent( QHideEvent* event ) +{ + if ( m_connected ) { + m_indexScheduler->disconnect( this ); + m_model->disconnect( this ); + m_connected = false; + } + + KDialog::hideEvent( event ); +} + +#include "statuswidget.moc" diff -Naur nepomuk/services/strigi/statuswidget.h nepomuk/services/strigi/statuswidget.h --- nepomuk/services/strigi/statuswidget.h 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/statuswidget.h 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,66 @@ +/* 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 _STATUS_WIDGET_H_ +#define _STATUS_WIDGET_H_ + +#include <KDialog> +#include "ui_statuswidget.h" + +#include <QtCore/QTimer> + +class QShowEvent; +class QHideEvent; + +namespace Soprano { + class Model; +} + +namespace Nepomuk { + + class IndexScheduler; + + class StatusWidget : public KDialog, public Ui::StatusWidget + { + Q_OBJECT + + public: + StatusWidget( Soprano::Model* model, IndexScheduler* scheduler, QWidget* parent = 0 ); + ~StatusWidget(); + + private Q_SLOTS: + void slotConfigure(); + void slotUpdateStrigiStatus(); + void slotUpdateStoreStatus(); + void slotUpdateTimeout(); + + private: + void showEvent( QShowEvent* event ); + void hideEvent( QHideEvent* event ); + + Soprano::Model* m_model; + IndexScheduler* m_indexScheduler; + + bool m_connected; + QTimer m_updateTimer; + bool m_updating; + bool m_updateRequested; + }; +} + +#endif diff -Naur nepomuk/services/strigi/statuswidget.ui nepomuk/services/strigi/statuswidget.ui --- nepomuk/services/strigi/statuswidget.ui 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/statuswidget.ui 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,102 @@ +<ui version="4.0" > + <author>Sebastian Trueg</author> + <class>StatusWidget</class> + <widget class="QWidget" name="StatusWidget" > + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <widget class="KTitleWidget" name="m_title" > + <property name="text" > + <string>Nepomuk Strigi File Indexing</string> + </property> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox" > + <property name="title" > + <string>Strigi Indexing State</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout" > + <item> + <widget class="KSqueezedTextLabel" name="m_labelStrigiState" > + <property name="font" > + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text" > + <string>KSqueezedTextLabel</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_2" > + <property name="title" > + <string>Nepomuk Storage State</string> + </property> + <layout class="QFormLayout" name="formLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Indexed files:</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLabel" name="m_labelFileCount" > + <property name="font" > + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text" > + <string>Calculating...</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>Nepomuk store size:</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QLabel" name="m_labelStoreSize" > + <property name="font" > + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text" > + <string>Calculating...</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <layoutfunction spacing="KDialog::spacingHint" margin="KDialog::marginHint" /> + <customwidgets> + <customwidget> + <class>KSqueezedTextLabel</class> + <extends>QLabel</extends> + <header>ksqueezedtextlabel.h</header> + </customwidget> + <customwidget> + <class>KTitleWidget</class> + <extends>QWidget</extends> + <header>ktitlewidget.h</header> + </customwidget> + </customwidgets> + <includes/> + <resources/> + <connections/> +</ui> diff -Naur nepomuk/services/strigi/strigicontroller.cpp nepomuk/services/strigi/strigicontroller.cpp --- nepomuk/services/strigi/strigicontroller.cpp 2008-04-24 14:27:53.000000000 +0200 +++ nepomuk/services/strigi/strigicontroller.cpp 1970-01-01 01:00:00.000000000 +0100 @@ -1,167 +0,0 @@ -/* This file is part of the KDE Project - Copyright (c) 2007 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 "strigicontroller.h" - -#include <QtDBus/QDBusConnection> -#include <QtDBus/QDBusMessage> -#include <QtCore/QTimer> -#include <QtCore/QFile> -#include <QtCore/QDir> - -#include <strigi/qtdbus/strigiclient.h> - -#include <KDebug> -#include <KProcess> -#include <KStandardDirs> -#include <KMessageBox> -#include <KLocale> - - -Nepomuk::StrigiController::StrigiController( QObject* parent ) - : QObject( parent ), - m_strigiProcess( 0 ), - m_running5Minutes( false ), - m_state( Idle ) -{ -} - - -Nepomuk::StrigiController::~StrigiController() -{ - shutdown(); -} - - -Nepomuk::StrigiController::State Nepomuk::StrigiController::state() const -{ - return m_state; -} - - -bool Nepomuk::StrigiController::start() -{ - kDebug(300002) << "(Nepomuk::StrigiController::start)"; - if ( !m_strigiProcess ) { - m_strigiProcess = new KProcess( this ); - m_strigiProcess->setOutputChannelMode( KProcess::ForwardedChannels ); - connect( m_strigiProcess, SIGNAL( finished( int, QProcess::ExitStatus) ), - this, SLOT( slotProcessFinished( int, QProcess::ExitStatus) ) ); - } - - m_strigiProcess->clearProgram(); - *m_strigiProcess << KStandardDirs::findExe( "strigidaemon" ); - - if ( m_strigiProcess->state() == QProcess::NotRunning ) { - m_running5Minutes = false; - m_state = StartingUp; - m_strigiProcess->start(); - if ( m_strigiProcess->waitForStarted() ) { - m_state = Running; - QTimer::singleShot( 50000, this, SLOT( slotRunning5Minutes() ) ); - - kDebug(300002) << "Strigi started successfully."; - - // Strigi might refuse to start properly for some reason (invalid config, lock file invalid, whatever.) - // In that case the dbus client would hang. Thus, we wait for 5 seconds before starting the indexing - // (Which is ugly anyway since Strigi should do that automatically) - QTimer::singleShot( 5000, this, SLOT( slotStartStrigiIndexing() ) ); - - return true; - } - else { - kDebug(300002) << "Failed to start strigidaemon."; - m_state = Idle; - return false; - } - } - else { - kDebug(300002) << "strigidaemon already running."; - return false; - } -} - - -void Nepomuk::StrigiController::shutdown() -{ - kDebug(300002) << "(Nepomuk::StrigiController::shutdown)"; - - StrigiClient strigiClient; - - m_state = ShuttingDown; - - if ( isRunning() ) { - strigiClient.stopDaemon(); - } - - if ( state() == Running ) { - kDebug(300002) << "We started Strigi ourselves. Trying to shut it down gracefully."; - if ( !m_strigiProcess->waitForFinished(60000) ) { - kDebug(300002) << "strigidaemon does not terminate properly. Killing process..."; - m_strigiProcess->terminate(); - } - m_state = Idle; - } -} - - -void Nepomuk::StrigiController::slotProcessFinished( int exitCode, QProcess::ExitStatus exitStatus ) -{ - if ( m_state == Running ) { - kDebug(300002) << "strigidaemon shut down unexpectedly with exit code:" << exitCode; - - m_state = Idle; - - if ( exitStatus == QProcess::CrashExit ) { - kDebug(300002) << "strigidaemon crashed."; - if ( m_running5Minutes ) { - kDebug(300002) << "restarting strigidaemon..."; - start(); - } - else { - kDebug(300002) << "looks like a recurring crash!"; - KMessageBox::error( 0, - i18n( "Strigi (the desktop file indexer) crashed repeatedly. It will not be started again." ), - i18n( "Strigi Desktop Search" ) ); - } - } - } -} - - -void Nepomuk::StrigiController::slotRunning5Minutes() -{ - m_running5Minutes = true; -} - - -bool Nepomuk::StrigiController::isRunning() -{ - return QDBusConnection::sessionBus().interface()->isServiceRegistered( "vandenoever.strigi" ); -} - - -void Nepomuk::StrigiController::slotStartStrigiIndexing() -{ - if ( isRunning() ) { - StrigiClient strigiClient; - strigiClient.startIndexing(); - } -} - -#include "strigicontroller.moc" diff -Naur nepomuk/services/strigi/strigicontroller.h nepomuk/services/strigi/strigicontroller.h --- nepomuk/services/strigi/strigicontroller.h 2008-04-23 17:51:26.000000000 +0200 +++ nepomuk/services/strigi/strigicontroller.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,62 +0,0 @@ -/* This file is part of the KDE Project - Copyright (c) 2007 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_STRIGI_CONTROLLER_H_ -#define _NEPOMUK_STRIGI_CONTROLLER_H_ - -#include <QtCore/QObject> -#include <KProcess> - - -namespace Nepomuk { - class StrigiController : public QObject - { - Q_OBJECT - - public: - StrigiController( QObject* parent = 0 ); - ~StrigiController(); - - enum State { - Idle, - StartingUp, - Running, - ShuttingDown - }; - - State state() const; - - public Q_SLOTS: - bool start(); - void shutdown(); - - static bool isRunning(); - - private Q_SLOTS: - void slotProcessFinished( int exitCode, QProcess::ExitStatus exitStatus ); - void slotRunning5Minutes(); - void slotStartStrigiIndexing(); - - private: - KProcess* m_strigiProcess; - bool m_running5Minutes; - State m_state; - }; -} - -#endif diff -Naur nepomuk/services/strigi/strigiservice.cpp nepomuk/services/strigi/strigiservice.cpp --- nepomuk/services/strigi/strigiservice.cpp 2008-04-02 14:18:19.000000000 +0200 +++ nepomuk/services/strigi/strigiservice.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -17,31 +17,78 @@ */ #include "strigiservice.h" -#include "strigicontroller.h" -#include "../../common/strigiconfigfile.h" +#include "strigiserviceadaptor.h" +#include "priority.h" +#include "indexscheduler.h" +#include "eventmonitor.h" +#include "systray.h" +#include "config.h" +#include "statuswidget.h" +#include "nepomukstorageinterface.h" -Nepomuk::StrigiService::StrigiService( QObject* parent, const QList<QVariant>& ) - : Service( parent ) -{ +#include <KDebug> - m_strigiController = new StrigiController( this ); - updateStrigiConfig(); - m_strigiController->start(); -} +#include <strigi/indexpluginloader.h> +#include <strigi/indexmanager.h> -Nepomuk::StrigiService::~StrigiService() + +Nepomuk::StrigiService::StrigiService( QObject* parent, const QList<QVariant>& ) + : Service( parent, true ) { + // 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."; + + // Using Strigi with the redland backend is torture. + // Thus we simply fail initialization if it is used + // ============================================================== + if ( org::kde::nepomuk::Storage( "org.kde.NepomukStorage", + "/nepomukstorage", + QDBusConnection::sessionBus() ) + .usedSopranoBackend().value() != QString::fromLatin1( "redland" ) ) { + // setup the actual index scheduler including strigi stuff + // ============================================================== + if ( ( m_indexManager = Strigi::IndexPluginLoader::createIndexManager( "sopranobackend", 0 ) ) ) { + m_indexScheduler = new IndexScheduler( m_indexManager, this ); + + ( void )new EventMonitor( m_indexScheduler, this ); + ( void )new StrigiServiceAdaptor( m_indexScheduler, this ); + StatusWidget* sw = new StatusWidget( mainModel(), m_indexScheduler ); + ( new SystemTray( m_indexScheduler, sw ) )->show(); + + m_indexScheduler->start(); + } + else { + kDebug() << "Failed to load sopranobackend Strigi index manager."; + } + + + // service initialization done if creating a strigi index manager was successful + // ============================================================== + setServiceInitialized( m_indexManager != 0 ); + } + else { + kDebug() << "Will not start when using redland Soprano backend due to horrible performance."; + setServiceInitialized( false ); + } } -void Nepomuk::StrigiService::updateStrigiConfig() +Nepomuk::StrigiService::~StrigiService() { - StrigiConfigFile strigiConfig ( StrigiConfigFile::defaultStrigiConfigFilePath() ); - strigiConfig.load(); - strigiConfig.defaultRepository().setType( "sopranobackend" ); - strigiConfig.save(); + if ( m_indexManager ) { + m_indexScheduler->stop(); + m_indexScheduler->wait(); + Strigi::IndexPluginLoader::deleteIndexManager( m_indexManager ); + } } + #include <kpluginfactory.h> #include <kpluginloader.h> diff -Naur nepomuk/services/strigi/strigiservice.h nepomuk/services/strigi/strigiservice.h --- nepomuk/services/strigi/strigiservice.h 2008-04-02 14:18:19.000000000 +0200 +++ nepomuk/services/strigi/strigiservice.h 2008-09-01 14:33:17.000000000 +0200 @@ -20,10 +20,15 @@ #define _NEPOMUK_STRIGI_SERVICE_H_ #include <Nepomuk/Service> +#include <QtCore/QTimer> + +namespace Strigi { + class IndexManager; +} namespace Nepomuk { - class StrigiController; + class IndexScheduler; /** * Service controlling the strigidaemon @@ -39,7 +44,8 @@ private: void updateStrigiConfig(); - StrigiController* m_strigiController; + Strigi::IndexManager* m_indexManager; + IndexScheduler* m_indexScheduler; }; } diff -Naur nepomuk/services/strigi/strigiserviceadaptor.cpp nepomuk/services/strigi/strigiserviceadaptor.cpp --- nepomuk/services/strigi/strigiserviceadaptor.cpp 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/strigiserviceadaptor.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,110 @@ +/* This file is part of the KDE Project + Copyright (c) 2008 Sebastian Trueg <trueg@kde.org> + + Based on code generated by dbusxml2cpp version 0.6 + dbusxml2cpp is Copyright (C) 2006 Trolltech ASA. All rights reserved. + + 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 "strigiserviceadaptor.h" +#include "strigiservice.h" +#include "indexscheduler.h" + +#include <QtCore/QUrl> +#include <QtCore/QDateTime> +#include <QtCore/QFile> +#include <QtCore/QDataStream> + +#include <KDebug> + + +Nepomuk::StrigiServiceAdaptor::StrigiServiceAdaptor( IndexScheduler* scheduler, StrigiService* parent ) + : QDBusAbstractAdaptor(parent), + m_indexScheduler( scheduler ) +{ + connect( m_indexScheduler, SIGNAL( indexingStarted() ), + this, SIGNAL( indexingStarted() ) ); + connect( m_indexScheduler, SIGNAL( indexingStopped() ), + this, SIGNAL( indexingStopped() ) ); + connect( m_indexScheduler, SIGNAL( indexingFolder(QString) ), + this, SIGNAL( indexingFolder(QString) ) ); +} + + +Nepomuk::StrigiServiceAdaptor::~StrigiServiceAdaptor() +{ +} + + +bool Nepomuk::StrigiServiceAdaptor::isIndexing() +{ + // handle method call org.kde.nepomuk.Strigi.isIndexing + return m_indexScheduler->isIndexing(); +} + + +bool Nepomuk::StrigiServiceAdaptor::isSuspended() +{ + // handle method call org.kde.nepomuk.Strigi.isSuspended + return m_indexScheduler->isSuspended(); +} + + +QString Nepomuk::StrigiServiceAdaptor::currentFolder() +{ + return m_indexScheduler->currentFolder(); +} + + +void Nepomuk::StrigiServiceAdaptor::resume() +{ + // handle method call org.kde.nepomuk.Strigi.resume + m_indexScheduler->resume(); +} + + +void Nepomuk::StrigiServiceAdaptor::suspend() +{ + // handle method call org.kde.nepomuk.Strigi.suspend + m_indexScheduler->suspend(); +} + + +void Nepomuk::StrigiServiceAdaptor::updateFolder( const QString& path ) +{ + m_indexScheduler->updateDir( path ); +} + + +void Nepomuk::StrigiServiceAdaptor::analyzeResource( const QString& uri, uint mTime, const QByteArray& data ) +{ + QDataStream stream( data ); + m_indexScheduler->analyzeResource( QUrl::fromEncoded( uri.toAscii() ), QDateTime::fromTime_t( mTime ), stream ); +} + + +void Nepomuk::StrigiServiceAdaptor::analyzeResourceFromTempFileAndDeleteTempFile( const QString& uri, uint mTime, const QString& tmpFile ) +{ + QFile file( tmpFile ); + if ( file.open( QIODevice::ReadOnly ) ) { + QDataStream stream( &file ); + m_indexScheduler->analyzeResource( QUrl::fromEncoded( uri.toAscii() ), QDateTime::fromTime_t( mTime ), stream ); + file.remove(); + } + else { + kDebug() << "Failed to open" << tmpFile; + } +} diff -Naur nepomuk/services/strigi/strigiserviceadaptor.h nepomuk/services/strigi/strigiserviceadaptor.h --- nepomuk/services/strigi/strigiserviceadaptor.h 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/strigiserviceadaptor.h 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,94 @@ +/* This file is part of the KDE Project + Copyright (c) 2008 Sebastian Trueg <trueg@kde.org> + + Based on code generated by dbusxml2cpp version 0.6 + dbusxml2cpp is Copyright (C) 2006 Trolltech ASA. All rights reserved. + + 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 _STRIGISERVICE_ADAPTOR_H_ +#define _STRIGISERVICE_ADAPTOR_H_ + +#include <QtDBus/QDBusAbstractAdaptor> + +namespace Nepomuk { + + class IndexScheduler; + class StrigiService; + + class StrigiServiceAdaptor: public QDBusAbstractAdaptor + { + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.nepomuk.Strigi") + Q_CLASSINFO("D-Bus Introspection", "" + " <interface name=\"org.kde.nepomuk.Strigi\" >\n" + " <method name=\"isIndexing\" >\n" + " <arg direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"isSuspended\" >\n" + " <arg direction=\"out\" type=\"b\" />\n" + " </method>\n" + " <method name=\"currentFolder\" >\n" + " <arg direction=\"out\" type=\"s\" />\n" + " </method>\n" + " <method name=\"suspend\" />\n" + " <method name=\"resume\" />\n" + " <method name=\"updateFolder\" >\n" + " <arg name=\"path\" direction=\"in\" type=\"s\" />\n" + " </method>\n" + " <method name=\"analyzeResource\" >\n" + " <arg name=\"uri\" direction=\"in\" type=\"s\" />\n" + " <arg name=\"lastModificationDate\" direction=\"in\" type=\"u\" />\n" + " <arg name=\"data\" direction=\"in\" type=\"ay\" />\n" + " </method>\n" + " <method name=\"analyzeResourceFromTempFileAndDeleteTempFile\" >\n" + " <arg name=\"uri\" direction=\"in\" type=\"s\" />\n" + " <arg name=\"lastModificationDate\" direction=\"in\" type=\"u\" />\n" + " <arg name=\"tmpFileName\" direction=\"in\" type=\"s\" />\n" + " </method>\n" + " <signal name=\"indexingStarted\" />\n" + " <signal name=\"indexingStopped\" />\n" + " <signal name=\"indexingFolder\" >\n" + " <arg type=\"s\" name=\"path\" />\n" + " </signal>\n" + " </interface>\n" + "") + + public: + StrigiServiceAdaptor( IndexScheduler* scheduler, StrigiService* parent ); + ~StrigiServiceAdaptor(); + + public Q_SLOTS: + bool isIndexing(); + bool isSuspended(); + QString currentFolder(); + void resume(); + void suspend(); + void updateFolder( const QString& path ); + void analyzeResource( const QString& uri, uint mTime, const QByteArray& data ); + void analyzeResourceFromTempFileAndDeleteTempFile( const QString& uri, uint mTime, const QString& tmpFile ); + + Q_SIGNALS: + void indexingFolder( const QString& path ); + void indexingStarted(); + void indexingStopped(); + + private: + IndexScheduler* m_indexScheduler; + }; +} + +#endif diff -Naur nepomuk/services/strigi/systray.cpp nepomuk/services/strigi/systray.cpp --- nepomuk/services/strigi/systray.cpp 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/systray.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,92 @@ +/* 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. +*/ + +#include "systray.h" +#include "indexscheduler.h" + +#include <KMenu> +#include <KToggleAction> +#include <KLocale> +#include <KCMultiDialog> +#include <KIcon> + + + +Nepomuk::SystemTray::SystemTray( IndexScheduler* scheduler, QWidget* parent ) + : KSystemTrayIcon( "nepomuk", parent ), + m_indexScheduler( scheduler ) +{ + KMenu* menu = new KMenu; + menu->addTitle( i18n( "Strigi File Indexing" ) ); + + m_suspendResumeAction = new KToggleAction( i18n( "Suspend Strigi Indexing" ), menu ); + m_suspendResumeAction->setCheckedState( KGuiItem( i18n( "Resume Strigi Indexing" ) ) ); + m_suspendResumeAction->setToolTip( i18n( "Suspend or resume the Strigi file indexer manually" ) ); + connect( m_suspendResumeAction, SIGNAL( toggled( bool ) ), + m_indexScheduler, SLOT( setSuspended( bool ) ) ); + + KAction* configAction = new KAction( menu ); + configAction->setText( i18n( "Configure Strigi" ) ); + configAction->setIcon( KIcon( "configure" ) ); + connect( configAction, SIGNAL( triggered() ), + this, SLOT( slotConfigure() ) ); + + menu->addAction( m_suspendResumeAction ); + menu->addAction( configAction ); + + setContextMenu( menu ); + + connect( m_indexScheduler, SIGNAL( indexingStarted() ), + this, SLOT( slotUpdateStrigiStatus() ) ); + connect( m_indexScheduler, SIGNAL( indexingStopped() ), + this, SLOT( slotUpdateStrigiStatus() ) ); + connect( m_indexScheduler, SIGNAL( indexingFolder(QString) ), + this, SLOT( slotUpdateStrigiStatus() ) ); +} + + +Nepomuk::SystemTray::~SystemTray() +{ +} + + +void Nepomuk::SystemTray::slotUpdateStrigiStatus() +{ + bool indexing = m_indexScheduler->isIndexing(); + bool suspended = m_indexScheduler->isSuspended(); + QString folder = m_indexScheduler->currentFolder(); + + if ( suspended ) + setToolTip( i18n( "File indexer is suspended" ) ); + else if ( indexing ) + setToolTip( i18n( "Strigi is currently indexing files in folder %1", folder ) ); + else + setToolTip( i18n( "File indexer is idle" ) ); + + m_suspendResumeAction->setChecked( suspended ); +} + + +void Nepomuk::SystemTray::slotConfigure() +{ + KCMultiDialog dlg; + dlg.addModule( "kcm_nepomuk" ); + dlg.exec(); +} + +#include "systray.moc" diff -Naur nepomuk/services/strigi/systray.h nepomuk/services/strigi/systray.h --- nepomuk/services/strigi/systray.h 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/services/strigi/systray.h 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,49 @@ +/* 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_STRIGI_SYSTRAY_H_ +#define _NEPOMUK_STRIGI_SYSTRAY_H_ + +#include <KSystemTrayIcon> + +class KToggleAction; + +namespace Nepomuk { + + class IndexScheduler; + + class SystemTray : public KSystemTrayIcon + { + Q_OBJECT + + public: + SystemTray( IndexScheduler* scheduler, QWidget* parent ); + ~SystemTray(); + + private Q_SLOTS: + void slotUpdateStrigiStatus(); + void slotConfigure(); + + private: + KToggleAction* m_suspendResumeAction; + + IndexScheduler* m_indexScheduler; + }; +} + +#endif diff -Naur nepomuk/servicestub/CMakeLists.txt nepomuk/servicestub/CMakeLists.txt --- nepomuk/servicestub/CMakeLists.txt 2008-07-03 07:05:21.000000000 +0200 +++ nepomuk/servicestub/CMakeLists.txt 2008-09-01 14:33:17.000000000 +0200 @@ -25,8 +25,10 @@ target_link_libraries(nepomukservicestub ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY} ${QT_QTDBUS_LIBRARY} ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} ${NEPOMUK_LIBRARIES} ${SOPRANO_LIBRARIES} ) diff -Naur nepomuk/servicestub/main.cpp nepomuk/servicestub/main.cpp --- nepomuk/servicestub/main.cpp 2008-07-03 07:05:21.000000000 +0200 +++ nepomuk/servicestub/main.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -23,10 +23,10 @@ #include <KService> #include <KServiceTypeTrader> #include <KDebug> -#include <Nepomuk/Service> -#include <QtCore/QCoreApplication> #include <QtCore/QTextStream> +#include <QtCore/QTimer> +#include <QtGui/QApplication> #include <QtDBus/QDBusConnection> #include <QtDBus/QDBusConnectionInterface> @@ -34,20 +34,8 @@ #include <stdio.h> #include "servicecontrol.h" -#include "servicecontroladaptor.h" namespace { - QString dbusServiceName( const QString& serviceName ) { - return QString("org.kde.nepomuk.services.%1").arg(serviceName); - } - - enum Errors { - ErrorUnknownServiceName = -9, - ErrorServiceAlreadyRunning = -10, - ErrorFailedToStart = -11, - ErrorMissingDependency = -12 - }; - #ifndef Q_OS_WIN void signalHandler( int signal ) { @@ -77,7 +65,7 @@ { KAboutData aboutData( "nepomukservicestub", "nepomuk", ki18n("Nepomuk Service Stub"), - "0.1", + "0.2", ki18n("Nepomuk Service Stub"), KAboutData::License_GPL, ki18n("(c) 2008, Sebastian Trüg"), @@ -91,9 +79,9 @@ KCmdLineArgs::init( argc, argv, &aboutData ); - QCoreApplication app( argc, argv ); + QApplication app( argc, argv ); installSignalHandler(); - KComponentData compData( aboutData ); + QApplication::setQuitOnLastWindowClosed( false ); // FIXME: set the proper KConfig rc name using the service name @@ -105,6 +93,12 @@ QTextStream s( stderr ); + QString serviceName = args->arg(0); + args->clear(); + + aboutData.setAppName( serviceName.toLocal8Bit() ); + KComponentData compData( aboutData ); + // check if NepomukServer is running // ==================================== @@ -116,20 +110,19 @@ // search the service // ==================================== - QString serviceName = args->arg(0); KService::List services = KServiceTypeTrader::self()->query( "NepomukService", "DesktopEntryName == '" + serviceName + "'" ); if( services.isEmpty() ) { s << i18n( "Unknown service name:") << " " << serviceName << endl; - return ErrorUnknownServiceName; + return Nepomuk::ServiceControl::ErrorUnknownServiceName; } KService::Ptr service = services.first(); // Check if this service is already running // ==================================== - if( QDBusConnection::sessionBus().interface()->isServiceRegistered( dbusServiceName( serviceName ) ) ) { + if( QDBusConnection::sessionBus().interface()->isServiceRegistered( Nepomuk::ServiceControl::dbusServiceName( serviceName ) ) ) { s << "Service " << serviceName << " already running." << endl; - return ErrorServiceAlreadyRunning; + return Nepomuk::ServiceControl::ErrorServiceAlreadyRunning; } @@ -137,42 +130,21 @@ // ==================================== QStringList dependencies = service->property( "X-KDE-Nepomuk-dependencies", QVariant::StringList ).toStringList(); foreach( const QString &dep, dependencies ) { - if( !QDBusConnection::sessionBus().interface()->isServiceRegistered( dbusServiceName( dep ) ) ) { + if( !QDBusConnection::sessionBus().interface()->isServiceRegistered( Nepomuk::ServiceControl::dbusServiceName( dep ) ) ) { s << "Missing dependency " << dep << endl; - return ErrorMissingDependency; + return Nepomuk::ServiceControl::ErrorMissingDependency; } } // register the service control // ==================================== - Nepomuk::ServiceControl* control = new Nepomuk::ServiceControl( &app ); - (void)new ServiceControlAdaptor( control ); - if( !QDBusConnection::sessionBus().registerObject( "/servicecontrol", control ) ) { - s << "Failed to register dbus service " << dbusServiceName( serviceName ) << "." << endl; - return ErrorFailedToStart; - } + Nepomuk::ServiceControl* control = new Nepomuk::ServiceControl( serviceName, service, &app ); - // start the service - // ==================================== - Nepomuk::Service* module = service->createInstance<Nepomuk::Service>( control ); - if( !module ) { - s << "Failed to start service " << serviceName << "." << endl; - return ErrorFailedToStart; - } - // register the service interface + // start the service (queued since we need an event loop) // ==================================== - if( !QDBusConnection::sessionBus().registerService( dbusServiceName( serviceName ) ) ) { - s << "Failed to register dbus service " << dbusServiceName( serviceName ) << "." << endl; - return ErrorFailedToStart; - } - - QDBusConnection::sessionBus().registerObject( '/' + serviceName, - module, - QDBusConnection::ExportScriptableSlots | - QDBusConnection::ExportScriptableProperties | - QDBusConnection::ExportAdaptors); + QTimer::singleShot( 0, control, SLOT( start() ) ); return app.exec(); } diff -Naur nepomuk/servicestub/servicecontrol.cpp nepomuk/servicestub/servicecontrol.cpp --- nepomuk/servicestub/servicecontrol.cpp 2008-04-02 14:18:21.000000000 +0200 +++ nepomuk/servicestub/servicecontrol.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -17,12 +17,18 @@ */ #include "servicecontrol.h" +#include "servicecontroladaptor.h" #include <QtCore/QCoreApplication> +#include <QtCore/QTextStream> +#include <Nepomuk/Service> -Nepomuk::ServiceControl::ServiceControl( QObject* parent ) + +Nepomuk::ServiceControl::ServiceControl( const QString& serviceName, const KService::Ptr& service, QObject* parent ) : QObject( parent ), + m_serviceName( serviceName ), + m_service( service ), m_initialized( false ) { } @@ -35,7 +41,7 @@ void Nepomuk::ServiceControl::setServiceInitialized( bool success ) { - m_initialized = true; + m_initialized = success; emit serviceInitialized( success ); } @@ -46,9 +52,56 @@ } +void Nepomuk::ServiceControl::start() +{ + QTextStream s( stderr ); + + // register the service interface + // We need to do this before creating the module to ensure that + // the server can catch the serviceInitialized signal + // ==================================== + (void)new ServiceControlAdaptor( this ); + if( !QDBusConnection::sessionBus().registerObject( "/servicecontrol", this ) ) { + s << "Failed to register dbus service " << dbusServiceName( m_serviceName ) << "." << endl; + qApp->exit( ErrorFailedToStart ); + return; + } + + if( !QDBusConnection::sessionBus().registerService( dbusServiceName( m_serviceName ) ) ) { + s << "Failed to register dbus service " << dbusServiceName( m_serviceName ) << "." << endl; + qApp->exit( ErrorFailedToStart ); + return; + } + + + // start the service + // ==================================== + Nepomuk::Service* module = m_service->createInstance<Nepomuk::Service>( this ); + if( !module ) { + s << "Failed to start service " << m_serviceName << "." << endl; + qApp->exit( ErrorFailedToStart ); + return; + } + + // register the service + // ==================================== + QDBusConnection::sessionBus().registerObject( '/' + m_serviceName, + module, + QDBusConnection::ExportScriptableSlots | + QDBusConnection::ExportScriptableProperties | + QDBusConnection::ExportAdaptors); +} + + void Nepomuk::ServiceControl::shutdown() { QCoreApplication::quit(); } + +QString Nepomuk::ServiceControl::dbusServiceName( const QString& serviceName ) +{ + return QString("org.kde.nepomuk.services.%1").arg(serviceName); +} + #include "servicecontrol.moc" diff -Naur nepomuk/servicestub/servicecontrol.h nepomuk/servicestub/servicecontrol.h --- nepomuk/servicestub/servicecontrol.h 2008-04-02 14:18:21.000000000 +0200 +++ nepomuk/servicestub/servicecontrol.h 2008-09-01 14:33:17.000000000 +0200 @@ -21,6 +21,7 @@ #include <QtCore/QObject> +#include <KService> namespace Nepomuk { class ServiceControl : public QObject @@ -28,18 +29,30 @@ Q_OBJECT public: - ServiceControl( QObject* parent = 0 ); + ServiceControl( const QString& serviceName, const KService::Ptr& service, QObject* parent = 0 ); ~ServiceControl(); + static QString dbusServiceName( const QString& serviceName ); + + enum Errors { + ErrorUnknownServiceName = -9, + ErrorServiceAlreadyRunning = -10, + ErrorFailedToStart = -11, + ErrorMissingDependency = -12 + }; + Q_SIGNALS: - void serviceInitialized( bool ); + void serviceInitialized( bool success ); public Q_SLOTS: - void setServiceInitialized( bool ); + void start(); + void setServiceInitialized( bool success ); bool isInitialized() const; void shutdown(); private: + QString m_serviceName; + KService::Ptr m_service; bool m_initialized; }; } diff -Naur nepomuk/strigibackend/CMakeLists.txt nepomuk/strigibackend/CMakeLists.txt --- nepomuk/strigibackend/CMakeLists.txt 2008-05-21 10:33:02.000000000 +0200 +++ nepomuk/strigibackend/CMakeLists.txt 2008-09-01 14:33:17.000000000 +0200 @@ -43,6 +43,7 @@ ${SOPRANO_CLIENT_LIBRARIES} ${QT_QTCORE_LIBRARY} ${CLUCENE_LIBRARY} + ${KDE4_KDECORE_LIBS} ) install(TARGETS sopranobackend LIBRARY DESTINATION ${LIB_INSTALL_DIR}/strigi) diff -Naur nepomuk/strigibackend/nepomukmainmodel.cpp nepomuk/strigibackend/nepomukmainmodel.cpp --- nepomuk/strigibackend/nepomukmainmodel.cpp 2008-04-18 09:21:46.000000000 +0200 +++ nepomuk/strigibackend/nepomukmainmodel.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -87,8 +87,6 @@ // we may get disconnected from the server but we don't want to try // to connect every time the model is requested - // FIXME: I doubt that this will work since the client is created in another thread than the - // connections and that is something Qt really does not like. :( if ( !m_socketConnectFailed && !m_localSocketClient.isConnected() ) { delete m_localSocketModel; QString socketName = nepomukServerSocketPath(); diff -Naur nepomuk/strigibackend/sopranoindexreader.cpp nepomuk/strigibackend/sopranoindexreader.cpp --- nepomuk/strigibackend/sopranoindexreader.cpp 2008-07-03 07:05:21.000000000 +0200 +++ nepomuk/strigibackend/sopranoindexreader.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -59,6 +59,16 @@ static lucene::search::Query* createMultiFieldQuery( const Strigi::Query& query ); +static QString luceneQueryEscape( const QString& s ) +{ + /* Chars to escape: + - && || ! ( ) { } [ ] ^ " ~ : \ */ + + static QRegExp rx( "([\\-" + QRegExp::escape( "+&|!(){}[]^\"~:\\" ) + "])" ); + QString es( s ); + es.replace( rx, "\\\\1" ); + return es; +} + static lucene::index::Term* createWildCardTerm( const TString& name, const string& value ) { @@ -266,7 +276,7 @@ lucene::search::Query* q = createQuery( query ); ::Soprano::QueryResultIterator hits = d->repository->executeQuery( TString( q->toString(), true ), - ::Soprano::Query::QUERY_LANGUAGE_USER, + ::Soprano::Query::QueryLanguageUser, QLatin1String( "lucene" ) ); // Iterator< ::Soprano::Index::QueryHit> hits = d->repository->index()->search( q ); int s = 0; @@ -288,7 +298,7 @@ qDebug() << "IndexReader::getHits in thread" << QThread::currentThread(); lucene::search::Query* bq = createQuery( query ); ::Soprano::QueryResultIterator hits = d->repository->executeQuery( TString( bq->toString(), true ), - ::Soprano::Query::QUERY_LANGUAGE_USER, + ::Soprano::Query::QueryLanguageUser, QLatin1String( "lucene" ) ); // Iterator< ::Soprano::Index::QueryHit> hits = d->repository->index()->search( bq ); @@ -339,7 +349,7 @@ vector<IndexedDocument> results; lucene::search::Query* bq = createQuery( query ); ::Soprano::QueryResultIterator hits = d->repository->executeQuery( TString( bq->toString(), true ), - ::Soprano::Query::QUERY_LANGUAGE_USER, + ::Soprano::Query::QueryLanguageUser, QLatin1String( "lucene" ) ); // Iterator< ::Soprano::Index::QueryHit> hits = d->repository->index()->search( bq ); @@ -374,15 +384,15 @@ { // qDebug() << "IndexReader::getChildren in thread" << QThread::currentThread(); QString query = QString( "select distinct ?path ?mtime where { ?r <%1> \"%2\"^^<%3> . ?r <%4> ?mtime . ?r <%5> ?path . }") - .arg( Util::fieldUri( FieldRegister::parentLocationFieldName ).toString() ) - .arg( escapeLiteralForSparqlQuery( QString::fromUtf8( parent.c_str() ) ) ) - .arg( Vocabulary::XMLSchema::string().toString() ) - .arg( Util::fieldUri( FieldRegister::mtimeFieldName ).toString() ) - .arg( Util::fieldUri( FieldRegister::pathFieldName ).toString() ); + .arg( Util::fieldUri( FieldRegister::parentLocationFieldName ).toString(), + escapeLiteralForSparqlQuery( QString::fromUtf8( parent.c_str() ) ), + Vocabulary::XMLSchema::string().toString(), + Util::fieldUri( FieldRegister::mtimeFieldName ).toString(), + Util::fieldUri( FieldRegister::pathFieldName ).toString() ); - qDebug() << "running getChildren query:" << query; +// qDebug() << "running getChildren query:" << query; - QueryResultIterator result = d->repository->executeQuery( query, ::Soprano::Query::QUERY_LANGUAGE_SPARQL ); + QueryResultIterator result = d->repository->executeQuery( query, ::Soprano::Query::QueryLanguageSparql ); while ( result.next() ) { Node pathNode = result.binding( "path" ); @@ -427,14 +437,14 @@ { // qDebug() << "IndexReader::mTime in thread" << QThread::currentThread(); QString query = QString( "select ?mtime where { ?r <%2> \"%3\"^^<%4> . ?r <%1> ?mtime . }" ) - .arg( Util::fieldUri( FieldRegister::mtimeFieldName ).toString() ) - .arg( Util::fieldUri( FieldRegister::pathFieldName ).toString() ) - .arg( escapeLiteralForSparqlQuery( QString::fromUtf8( uri.c_str() ) ) ) - .arg( Vocabulary::XMLSchema::string().toString() ); + .arg( Util::fieldUri( FieldRegister::mtimeFieldName ).toString(), + Util::fieldUri( FieldRegister::pathFieldName ).toString(), + escapeLiteralForSparqlQuery( QString::fromUtf8( uri.c_str() ) ), + Vocabulary::XMLSchema::string().toString() ); qDebug() << "mTime( " << uri.c_str() << ") query:" << query; - QueryResultIterator it = d->repository->executeQuery( query, ::Soprano::Query::QUERY_LANGUAGE_SPARQL ); + QueryResultIterator it = d->repository->executeQuery( query, ::Soprano::Query::QueryLanguageSparql ); time_t mtime = 0; if ( it.next() ) { @@ -459,7 +469,7 @@ // Our list of field names (the predicates) is probably awefully long. std::vector<std::string> fields; - QueryResultIterator it = d->repository->executeQuery( "select distinct ?p where { ?r ?p ?o . }", ::Soprano::Query::QUERY_LANGUAGE_SPARQL ); + QueryResultIterator it = d->repository->executeQuery( "select distinct ?p where { ?r ?p ?o . }", ::Soprano::Query::QueryLanguageSparql ); while ( it.next() ) { fields.push_back( Util::fieldName( it.binding("p").uri() ) ); } diff -Naur nepomuk/strigibackend/sopranoindexreader.h nepomuk/strigibackend/sopranoindexreader.h --- nepomuk/strigibackend/sopranoindexreader.h 2008-05-07 11:05:22.000000000 +0200 +++ nepomuk/strigibackend/sopranoindexreader.h 2008-09-01 14:33:17.000000000 +0200 @@ -1,5 +1,5 @@ /* - Copyright (C) 2007 Sebastian Trueg <trueg@kde.org> + Copyright (C) 2007-2008 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 @@ -34,41 +34,41 @@ class Query; namespace Soprano { - class IndexReader : public Strigi::IndexReader - { - public: - IndexReader( ::Soprano::Model* ); - ~IndexReader(); - - int32_t countHits( const Query& query ); - std::vector<IndexedDocument> query( const Query&, int off, int max ); - void getHits( const Strigi::Query& query, - const std::vector<std::string>& fields, - const std::vector<Strigi::Variant::Type>& types, - std::vector<std::vector<Strigi::Variant> >& result, - int off, int max ); - - void getChildren( const std::string& parent, - std::map<std::string, time_t>& children ); - - int32_t countDocuments(); - int32_t countWords(); - int64_t indexSize(); - time_t mTime( const std::string& uri ); - std::vector<std::string> fieldNames(); - std::vector<std::pair<std::string,uint32_t> > histogram( const std::string& query, - const std::string& fieldname, - const std::string& labeltype ); - int32_t countKeywords( const std::string& keywordprefix, - const std::vector<std::string>& fieldnames); - std::vector<std::string> keywords( const std::string& keywordmatch, - const std::vector<std::string>& fieldnames, - uint32_t max, uint32_t offset ); - - private: - class Private; - Private* d; - }; + class IndexReader : public Strigi::IndexReader + { + public: + IndexReader( ::Soprano::Model* ); + ~IndexReader(); + + int32_t countHits( const Query& query ); + std::vector<IndexedDocument> query( const Query&, int off, int max ); + void getHits( const Strigi::Query& query, + const std::vector<std::string>& fields, + const std::vector<Strigi::Variant::Type>& types, + std::vector<std::vector<Strigi::Variant> >& result, + int off, int max ); + + void getChildren( const std::string& parent, + std::map<std::string, time_t>& children ); + + int32_t countDocuments(); + int32_t countWords(); + int64_t indexSize(); + time_t mTime( const std::string& uri ); + std::vector<std::string> fieldNames(); + std::vector<std::pair<std::string,uint32_t> > histogram( const std::string& query, + const std::string& fieldname, + const std::string& labeltype ); + int32_t countKeywords( const std::string& keywordprefix, + const std::vector<std::string>& fieldnames); + std::vector<std::string> keywords( const std::string& keywordmatch, + const std::vector<std::string>& fieldnames, + uint32_t max, uint32_t offset ); + + private: + class Private; + Private* d; + }; } } diff -Naur nepomuk/strigibackend/sopranoindexwriter.cpp nepomuk/strigibackend/sopranoindexwriter.cpp --- nepomuk/strigibackend/sopranoindexwriter.cpp 2008-09-01 14:44:51.000000000 +0200 +++ nepomuk/strigibackend/sopranoindexwriter.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -37,6 +37,8 @@ #include <QtCore/QThread> #include <QtCore/QDateTime> +#include <KUrl> + #include <sys/stat.h> #include <stdlib.h> #include <string.h> @@ -76,8 +78,13 @@ // such as tar:/ or zip:/ // Here we try to use KDE-compatible URIs for these indexed files the best we can // everything else defaults to file:/ + QUrl uri; QString path = QFile::decodeName( idx->path().c_str() ); - QUrl url = QUrl::fromLocalFile( QFileInfo( path ).absoluteFilePath() ); + if ( KUrl::isRelativeUrl( path ) ) + uri = QUrl::fromLocalFile( QFileInfo( path ).absoluteFilePath() ); + else + uri = KUrl( path ); // try to support http and other URLs + if ( idx->depth() > 0 ) { QString archivePath = findArchivePath( path ); if ( QFile::exists( archivePath ) ) { @@ -85,20 +92,20 @@ archivePath.endsWith( QLatin1String( ".tar.gz" ) ) || archivePath.endsWith( QLatin1String( ".tar.bz2" ) ) || archivePath.endsWith( QLatin1String( ".tar.lzma" ) ) ) { - url.setScheme( "tar" ); + uri.setScheme( "tar" ); } else if ( archivePath.endsWith( QLatin1String( ".zip" ) ) ) { - url.setScheme( "zip" ); + uri.setScheme( "zip" ); } } } // fallback for all - if ( url.scheme().isEmpty() ) { - url.setScheme( "file" ); + if ( uri.scheme().isEmpty() ) { + uri.setScheme( "file" ); } - return url; + return uri; } class FileMetaData @@ -156,9 +163,13 @@ if ( type == QVariant::DateTime ) { // dataTime is stored as integer in strigi! return LiteralValue( QDateTime::fromTime_t( value.toUInt() ) ); } - else { + else if ( type != QVariant::Invalid ) { return LiteralValue::fromString( value, type ); } + else { + // we default to string + return LiteralValue( value ); + } } // ::Soprano::Index::IndexFilterModel* repository; @@ -176,6 +187,7 @@ // qDebug() << "IndexWriter::IndexWriter in thread" << QThread::currentThread(); d = new Private; d->repository = model; + Util::storeStrigiMiniOntology( d->repository ); // qDebug() << "IndexWriter::IndexWriter done in thread" << QThread::currentThread(); } @@ -205,14 +217,14 @@ .arg( path ) .arg( Vocabulary::XMLSchema::string().toString() ); - qDebug() << "deleteEntries query:" << query; +// qDebug() << "deleteEntries query:" << query; - QueryResultIterator result = d->repository->executeQuery( query, ::Soprano::Query::QUERY_LANGUAGE_SPARQL ); + QueryResultIterator result = d->repository->executeQuery( query, ::Soprano::Query::QueryLanguageSparql ); if ( result.next() ) { Node indexGraph = result.binding( "g" ); result.close(); - qDebug() << "Found indexGraph to delete:" << indexGraph; +// qDebug() << "Found indexGraph to delete:" << indexGraph; // delete the indexed data d->repository->removeContext( indexGraph ); @@ -271,7 +283,7 @@ data->context = Util::uniqueUri( "http://www.strigi.org/contexts/", d->repository ); } - qDebug() << "Starting analysis for" << data->fileUri << "in thread" << QThread::currentThread(); +// qDebug() << "Starting analysis for" << data->fileUri << "in thread" << QThread::currentThread(); idx->setWriterData( data ); } @@ -319,15 +331,10 @@ } else { - if ( rfd->dataType != QVariant::Invalid ) { - d->repository->addStatement( Statement( md->fileUri, - rfd->property, - d->createLiteralValue( rfd->dataType, ( unsigned char* )value.c_str(), value.length() ), - md->context) ); - } - else { - qDebug() << "Ignoring field" << rfd->property << "due to unknown type" << field->properties().typeUri().c_str(); - } + d->repository->addStatement( Statement( md->fileUri, + rfd->property, + d->createLiteralValue( rfd->dataType, ( unsigned char* )value.c_str(), value.length() ), + md->context) ); } } // qDebug() << "IndexWriter::addValue done in thread" << QThread::currentThread(); @@ -449,10 +456,16 @@ // Strigi only indexes files and extractors mostly (if at all) store the xesam:DataObject type (i.e. the contents) // Thus, here we go the easy way and mark each indexed file as a xesam:File. - d->repository->addStatement( Statement( md->fileUri, - Vocabulary::RDF::type(), - Vocabulary::Xesam::File(), - md->context ) ); + if ( QFileInfo( QFile::decodeName( idx->path().c_str() ) ).isDir() ) + d->repository->addStatement( Statement( md->fileUri, + Vocabulary::RDF::type(), + Vocabulary::Xesam::Folder(), + md->context ) ); + else + d->repository->addStatement( Statement( md->fileUri, + Vocabulary::RDF::type(), + Vocabulary::Xesam::File(), + md->context ) ); // create the provedance data for the data graph diff -Naur nepomuk/strigibackend/sopranoindexwriter.cpp.liblzma nepomuk/strigibackend/sopranoindexwriter.cpp.liblzma --- nepomuk/strigibackend/sopranoindexwriter.cpp.liblzma 2008-05-15 20:37:14.000000000 +0200 +++ nepomuk/strigibackend/sopranoindexwriter.cpp.liblzma 1970-01-01 01:00:00.000000000 +0100 @@ -1,507 +0,0 @@ -/* - Copyright (C) 2007-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 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 General Public License - along with this library; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - */ - -#include "sopranoindexwriter.h" -#include "util.h" - -#include <Soprano/Soprano> -#include <Soprano/Index/IndexFilterModel> -#include <Soprano/Index/CLuceneIndex> -#include <Soprano/Vocabulary/RDF> -#include <Soprano/Vocabulary/Xesam> -#include <Soprano/LiteralValue> - -#include <QtCore/QList> -#include <QtCore/QHash> -#include <QtCore/QVariant> -#include <QtCore/QFileInfo> -#include <QtCore/QFile> -#include <QtCore/QUrl> -#include <QtCore/QDebug> -#include <QtCore/QThread> -#include <QtCore/QDateTime> - -#include <sys/stat.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#include <map> -#include <sstream> -#include <algorithm> - - -// IMPORTANT: strings in Strigi are apparently UTF8! Except for file names. Those are in local encoding. - -using namespace Soprano; - - -uint qHash( const std::string& s ) -{ - return qHash( s.c_str() ); -} - -namespace { - QString findArchivePath( const QString& path ) { - QString p( path ); - int i = 0; - while ( ( i = p.lastIndexOf( '/' ) ) > 0 ) { - p.truncate( i ); - if ( QFileInfo( p ).isFile() ) { - return p; - } - } - return QString(); - } - - QUrl createResourceUri( const Strigi::AnalysisResult* idx ) { - // HACK: Strigi includes analysers that recurse into tar or zip archives and index - // the files therein. In KDE these files could perfectly be handled through kio slaves - // such as tar:/ or zip:/ - // Here we try to use KDE-compatible URIs for these indexed files the best we can - // everything else defaults to file:/ - QString path = QFile::decodeName( idx->path().c_str() ); - QUrl url = QUrl::fromLocalFile( QFileInfo( path ).absoluteFilePath() ); - if ( idx->depth() > 0 ) { - QString archivePath = findArchivePath( path ); - if ( QFile::exists( archivePath ) ) { - if ( archivePath.endsWith( QLatin1String( ".tar" ) ) || - archivePath.endsWith( QLatin1String( ".tar.gz" ) ) || - archivePath.endsWith( QLatin1String( ".tar.bz2" ) ) ) { - url.setScheme( "tar" ); - } - else if ( archivePath.endsWith( QLatin1String( ".zip" ) ) ) { - url.setScheme( "zip" ); - } - } - } - - // fallback for all - if ( url.scheme().isEmpty() ) { - url.setScheme( "file" ); - } - - return url; - } - - class FileMetaData - { - public: - // caching URIs for little speed improvement - QUrl fileUri; - QUrl context; - std::string content; - }; - - class RegisteredFieldData - { - public: - RegisteredFieldData( const QUrl& prop, QVariant::Type t ) - : property( prop ), - dataType( t ), - isRdfType( prop == Vocabulary::RDF::type() ) { - } - - QUrl property; - QVariant::Type dataType; - bool isRdfType; - }; -} - - -class Strigi::Soprano::IndexWriter::Private -{ -public: - Private() - : indexTransactionID( 0 ) { - literalTypes[FieldRegister::stringType] = QVariant::String; - literalTypes[FieldRegister::floatType] = QVariant::Double; - literalTypes[FieldRegister::integerType] = QVariant::Int; - literalTypes[FieldRegister::binaryType] = QVariant::ByteArray; - literalTypes[FieldRegister::datetimeType] = QVariant::DateTime; // Strigi encodes datetime as unsigned integer, i.e. addValue( ..., uint ) - } - - QVariant::Type literalType( const Strigi::FieldProperties& strigiType ) { - // it looks as if the typeUri can contain arbitrary values, URIs or stuff like "string" - QHash<std::string, QVariant::Type>::const_iterator it = literalTypes.find( strigiType.typeUri() ); - if ( it == literalTypes.constEnd() ) { - return LiteralValue::typeFromDataTypeUri( QUrl::fromEncoded( strigiType.typeUri().c_str() ) ); - } - else { - return *it; - } - } - - LiteralValue createLiteralValue( QVariant::Type type, - const unsigned char* data, - uint32_t size ) { - QString value = QString::fromUtf8( ( const char* )data, size ); - if ( type == QVariant::DateTime ) { // dataTime is stored as integer in strigi! - return LiteralValue( QDateTime::fromTime_t( value.toUInt() ) ); - } - else { - return LiteralValue::fromString( value, type ); - } - } - -// ::Soprano::Index::IndexFilterModel* repository; - ::Soprano::Model* repository; - int indexTransactionID; - -private: - QHash<std::string, QVariant::Type> literalTypes; -}; - - -Strigi::Soprano::IndexWriter::IndexWriter( ::Soprano::Model* model ) - : Strigi::IndexWriter() -{ -// qDebug() << "IndexWriter::IndexWriter in thread" << QThread::currentThread(); - d = new Private; - d->repository = model; -// qDebug() << "IndexWriter::IndexWriter done in thread" << QThread::currentThread(); -} - - -Strigi::Soprano::IndexWriter::~IndexWriter() -{ - delete d; -} - - -void Strigi::Soprano::IndexWriter::commit() -{ -} - - -// delete all indexed data for the files listed in entries -void Strigi::Soprano::IndexWriter::deleteEntries( const std::vector<std::string>& entries ) -{ -// qDebug() << "IndexWriter::deleteEntries in thread" << QThread::currentThread(); - - QString systemLocationUri = Util::fieldUri( FieldRegister::pathFieldName ).toString(); - for ( unsigned int i = 0; i < entries.size(); ++i ) { - QString path = QString::fromUtf8( entries[i].c_str() ); - QString query = QString( "select ?g where { ?r <%1> \"%2\"^^<%3> . " - "?g <http://www.strigi.org/fields#indexGraphFor> ?r . }" ) - .arg( systemLocationUri ) - .arg( path ) - .arg( Vocabulary::XMLSchema::string().toString() ); - - qDebug() << "deleteEntries query:" << query; - - QueryResultIterator result = d->repository->executeQuery( query, ::Soprano::Query::QUERY_LANGUAGE_SPARQL ); - if ( result.next() ) { - Node indexGraph = result.binding( "g" ); - result.close(); - - qDebug() << "Found indexGraph to delete:" << indexGraph; - - // delete the indexed data - d->repository->removeContext( indexGraph ); - - // delete the metadata - d->repository->removeAllStatements( Statement( indexGraph, Node(), Node() ) ); - } - } -} - - -void Strigi::Soprano::IndexWriter::deleteAllEntries() -{ -// qDebug() << "IndexWriter::deleteAllEntries in thread" << QThread::currentThread(); - - // query all index graphs (FIXME: would a type derived from nrl:Graph be better than only the predicate?) - QString query = QString( "select ?g where { ?g <http://www.strigi.org/fields#indexGraphFor> ?r . }" ); - - qDebug() << "deleteAllEntries query:" << query; - - QueryResultIterator result = d->repository->executeQuery( query, ::Soprano::Query::QUERY_LANGUAGE_SPARQL ); - QList<Node> allIndexGraphs = result.iterateBindings( "g" ).allNodes(); - for ( QList<Node>::const_iterator it = allIndexGraphs.constBegin(); it != allIndexGraphs.constEnd(); ++it ) { - Node indexGraph = *it; - - qDebug() << "Found indexGraph to delete:" << indexGraph; - - // delete the indexed data - d->repository->removeContext( indexGraph ); - - // delete the metadata - d->repository->removeAllStatements( Statement( indexGraph, Node(), Node() ) ); - } -} - - -// called for each indexed file -void Strigi::Soprano::IndexWriter::startAnalysis( const AnalysisResult* idx ) -{ - if ( idx->depth() > 0 ) { - return; - } - -// qDebug() << "IndexWriter::startAnalysis in thread" << QThread::currentThread(); - FileMetaData* data = new FileMetaData(); - data->fileUri = createResourceUri( idx ); - - // let's check if we already have data on the file - StatementIterator it = d->repository->listStatements( Node(), - QUrl::fromEncoded( "http://www.strigi.org/fields#indexGraphFor", QUrl::StrictMode ), // FIXME: put the URI somewhere else - data->fileUri ); - if ( it.next() ) { - data->context = it.current().subject().uri(); - } - else { - data->context = Util::uniqueUri( "http://www.strigi.org/contexts/", d->repository ); - } - - qDebug() << "Starting analysis for" << data->fileUri << "in thread" << QThread::currentThread(); - - idx->setWriterData( data ); -} - - -void Strigi::Soprano::IndexWriter::addText( const AnalysisResult* idx, const char* text, int32_t length ) -{ - if ( idx->depth() > 0 ) { - return; - } - - FileMetaData* md = reinterpret_cast<FileMetaData*>( idx->writerData() ); - md->content.append( text, length ); -} - - -void Strigi::Soprano::IndexWriter::addValue( const AnalysisResult* idx, - const RegisteredField* field, - const std::string& value ) -{ - if ( idx->depth() > 0 ) { - return; - } - -// qDebug() << "IndexWriter::addValue in thread" << QThread::currentThread(); - if ( value.length() > 0 ) { - FileMetaData* md = reinterpret_cast<FileMetaData*>( idx->writerData() ); - RegisteredFieldData* rfd = reinterpret_cast<RegisteredFieldData*>( field->writerData() ); - - if ( rfd->isRdfType ) { - - // Strigi uses rdf:type improperly since it stores the value as a string. We have to - // make sure it is a resource. The problem is that this results in the type not being - // indexed properly. Thus, it cannot be searched with normal lucene queries. - // That is why we need to introduce a stringType property - - d->repository->addStatement( Statement( md->fileUri, - ::Soprano::Vocabulary::RDF::type(), - QUrl::fromEncoded( value.c_str(), QUrl::StrictMode ), // fromEncoded is faster than the plain constructor and all Xesam URIs work here - md->context) ); - d->repository->addStatement( Statement( md->fileUri, - QUrl::fromEncoded( "http://strigi.sourceforge.net/fields#rdf-string-type", QUrl::StrictMode ), - LiteralValue( QString::fromUtf8( value.c_str() ) ), - md->context) ); - } - - else { - if ( rfd->dataType != QVariant::Invalid ) { - d->repository->addStatement( Statement( md->fileUri, - rfd->property, - d->createLiteralValue( rfd->dataType, ( unsigned char* )value.c_str(), value.length() ), - md->context) ); - } - else { - qDebug() << "Ignoring field" << rfd->property << "due to unknown type" << field->properties().typeUri().c_str(); - } - } - } -// qDebug() << "IndexWriter::addValue done in thread" << QThread::currentThread(); -} - - -// the main addValue method -void Strigi::Soprano::IndexWriter::addValue( const AnalysisResult* idx, - const RegisteredField* field, - const unsigned char* data, - uint32_t size ) -{ - addValue( idx, field, std::string( ( const char* )data, size ) ); -} - - -void Strigi::Soprano::IndexWriter::addValue( const AnalysisResult*, const RegisteredField*, - const std::string&, const std::string& ) -{ - // we do not support map types -} - - -void Strigi::Soprano::IndexWriter::addValue( const AnalysisResult* idx, - const RegisteredField* field, - uint32_t value ) -{ - if ( idx->depth() > 0 ) { - return; - } - -// qDebug() << "IndexWriter::addValue in thread" << QThread::currentThread(); - FileMetaData* md = reinterpret_cast<FileMetaData*>( idx->writerData() ); - RegisteredFieldData* rfd = reinterpret_cast<RegisteredFieldData*>( field->writerData() ); - - LiteralValue val( value ); - if ( field->type() == FieldRegister::datetimeType ) { - val = QDateTime::fromTime_t( value ); - } - - d->repository->addStatement( Statement( md->fileUri, - rfd->property, - val, - md->context) ); -// qDebug() << "IndexWriter::addValue done in thread" << QThread::currentThread(); -} - - -void Strigi::Soprano::IndexWriter::addValue( const AnalysisResult* idx, - const RegisteredField* field, - int32_t value ) -{ - if ( idx->depth() > 0 ) { - return; - } - -// qDebug() << "IndexWriter::addValue in thread" << QThread::currentThread(); - FileMetaData* md = reinterpret_cast<FileMetaData*>( idx->writerData() ); - RegisteredFieldData* rfd = reinterpret_cast<RegisteredFieldData*>( field->writerData() ); - - d->repository->addStatement( Statement( md->fileUri, - rfd->property, - LiteralValue( value ), - md->context) ); -// qDebug() << "IndexWriter::addValue done in thread" << QThread::currentThread(); -} - - -void Strigi::Soprano::IndexWriter::addValue( const AnalysisResult* idx, - const RegisteredField* field, - double value ) -{ - if ( idx->depth() > 0 ) { - return; - } - -// qDebug() << "IndexWriter::addValue in thread" << QThread::currentThread(); - FileMetaData* md = reinterpret_cast<FileMetaData*>( idx->writerData() ); - RegisteredFieldData* rfd = reinterpret_cast<RegisteredFieldData*>( field->writerData() ); - - d->repository->addStatement( Statement( md->fileUri, - rfd->property, - LiteralValue( value ), - md->context) ); -// qDebug() << "IndexWriter::addValue done in thread" << QThread::currentThread(); -} - - -void Strigi::Soprano::IndexWriter::addTriplet( const std::string& subject, - const std::string& predicate, const std::string& object ) -{ - // PROBLEM: which named graph (context) should we use here? Create a new one for each triple? Use one until the - // next commit()? - - // FIXME: create an NRL metadata graph - d->repository->addStatement( Statement( Node( QUrl( QString::fromUtf8( subject.c_str() ) ) ), - Node( QUrl( QString::fromUtf8( predicate.c_str() ) ) ), - Node( QUrl( QString::fromUtf8( object.c_str() ) ) ), - Node() ) ); -} - - -// called after each indexed file -void Strigi::Soprano::IndexWriter::finishAnalysis( const AnalysisResult* idx ) -{ - if ( idx->depth() > 0 ) { - return; - } - -// qDebug() << "IndexWriter::finishAnalysis in thread" << QThread::currentThread(); - FileMetaData* md = static_cast<FileMetaData*>( idx->writerData() ); - - if ( md->content.length() > 0 ) { - d->repository->addStatement( Statement( md->fileUri, - Vocabulary::Xesam::asText(), - LiteralValue( QString::fromUtf8( md->content.c_str() ) ), - md->context ) ); - } - - // Strigi only indexes files and extractors mostly (if at all) store the xesam:DataObject type (i.e. the contents) - // Thus, here we go the easy way and mark each indexed file as a xesam:File. - d->repository->addStatement( Statement( md->fileUri, - Vocabulary::RDF::type(), - Vocabulary::Xesam::File(), - md->context ) ); - - - // create the provedance data for the data graph - // TODO: add more data at some point when it becomes of interest - QUrl metaDataContext = Util::uniqueUri( "http://www.strigi.org/graphMetaData/", d->repository ); - d->repository->addStatement( Statement( md->context, - Vocabulary::RDF::type(), - Vocabulary::NRL::InstanceBase(), - metaDataContext ) ); - d->repository->addStatement( Statement( md->context, - Vocabulary::NAO::created(), - LiteralValue( QDateTime::currentDateTime() ), - metaDataContext ) ); - d->repository->addStatement( Statement( md->context, - QUrl::fromEncoded( "http://www.strigi.org/fields#indexGraphFor", QUrl::StrictMode ), // FIXME: put the URI somewhere else - md->fileUri, - metaDataContext ) ); - d->repository->addStatement( Statement( metaDataContext, - Vocabulary::RDF::type(), - Vocabulary::NRL::GraphMetadata(), - metaDataContext ) ); - - // cleanup - delete md; - idx->setWriterData( 0 ); - -// qDebug() << "IndexWriter::finishAnalysis done in thread" << QThread::currentThread(); -} - - -void Strigi::Soprano::IndexWriter::initWriterData( const Strigi::FieldRegister& f ) -{ - map<string, RegisteredField*>::const_iterator i; - map<string, RegisteredField*>::const_iterator end = f.fields().end(); - for (i = f.fields().begin(); i != end; ++i) { - QUrl prop = Util::fieldUri( i->second->key() ); - i->second->setWriterData( new RegisteredFieldData( prop, - prop == Vocabulary::RDF::type() - ? QVariant::Invalid - : d->literalType( i->second->properties() ) ) ); - } -} - - -void Strigi::Soprano::IndexWriter::releaseWriterData( const Strigi::FieldRegister& f ) -{ - map<string, RegisteredField*>::const_iterator i; - map<string, RegisteredField*>::const_iterator end = f.fields().end(); - for (i = f.fields().begin(); i != end; ++i) { - delete static_cast<RegisteredFieldData*>( i->second->writerData() ); - i->second->setWriterData( 0 ); - } -} diff -Naur nepomuk/strigibackend/sopranoindexwriter.cpp~ nepomuk/strigibackend/sopranoindexwriter.cpp~ --- nepomuk/strigibackend/sopranoindexwriter.cpp~ 1970-01-01 01:00:00.000000000 +0100 +++ nepomuk/strigibackend/sopranoindexwriter.cpp~ 2008-09-01 14:33:17.000000000 +0200 @@ -0,0 +1,521 @@ +/* + Copyright (C) 2007-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 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 General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "sopranoindexwriter.h" +#include "util.h" + +#include <Soprano/Soprano> +#include <Soprano/Index/IndexFilterModel> +#include <Soprano/Index/CLuceneIndex> +#include <Soprano/Vocabulary/RDF> +#include <Soprano/Vocabulary/Xesam> +#include <Soprano/LiteralValue> + +#include <QtCore/QList> +#include <QtCore/QHash> +#include <QtCore/QVariant> +#include <QtCore/QFileInfo> +#include <QtCore/QFile> +#include <QtCore/QUrl> +#include <QtCore/QDebug> +#include <QtCore/QThread> +#include <QtCore/QDateTime> + +#include <KUrl> + +#include <sys/stat.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <map> +#include <sstream> +#include <algorithm> + + +// IMPORTANT: strings in Strigi are apparently UTF8! Except for file names. Those are in local encoding. + +using namespace Soprano; + + +uint qHash( const std::string& s ) +{ + return qHash( s.c_str() ); +} + +namespace { + QString findArchivePath( const QString& path ) { + QString p( path ); + int i = 0; + while ( ( i = p.lastIndexOf( '/' ) ) > 0 ) { + p.truncate( i ); + if ( QFileInfo( p ).isFile() ) { + return p; + } + } + return QString(); + } + + QUrl createResourceUri( const Strigi::AnalysisResult* idx ) { + // HACK: Strigi includes analysers that recurse into tar or zip archives and index + // the files therein. In KDE these files could perfectly be handled through kio slaves + // such as tar:/ or zip:/ + // Here we try to use KDE-compatible URIs for these indexed files the best we can + // everything else defaults to file:/ + QUrl uri; + QString path = QFile::decodeName( idx->path().c_str() ); + if ( KUrl::isRelativeUrl( path ) ) + uri = QUrl::fromLocalFile( QFileInfo( path ).absoluteFilePath() ); + else + uri = KUrl( path ); // try to support http and other URLs + + if ( idx->depth() > 0 ) { + QString archivePath = findArchivePath( path ); + if ( QFile::exists( archivePath ) ) { + if ( archivePath.endsWith( QLatin1String( ".tar" ) ) || + archivePath.endsWith( QLatin1String( ".tar.gz" ) ) || + archivePath.endsWith( QLatin1String( ".tar.bz2" ) ) || + archivePath.endsWith( QLatin1String( ".tar.lzma" ) ) ) { + uri.setScheme( "tar" ); + } + else if ( archivePath.endsWith( QLatin1String( ".zip" ) ) ) { + uri.setScheme( "zip" ); + } + } + } + + // fallback for all + if ( uri.scheme().isEmpty() ) { + uri.setScheme( "file" ); + } + + return uri; + } + + class FileMetaData + { + public: + // caching URIs for little speed improvement + QUrl fileUri; + QUrl context; + std::string content; + }; + + class RegisteredFieldData + { + public: + RegisteredFieldData( const QUrl& prop, QVariant::Type t ) + : property( prop ), + dataType( t ), + isRdfType( prop == Vocabulary::RDF::type() ) { + } + + QUrl property; + QVariant::Type dataType; + bool isRdfType; + }; +} + + +class Strigi::Soprano::IndexWriter::Private +{ +public: + Private() + : indexTransactionID( 0 ) { + literalTypes[FieldRegister::stringType] = QVariant::String; + literalTypes[FieldRegister::floatType] = QVariant::Double; + literalTypes[FieldRegister::integerType] = QVariant::Int; + literalTypes[FieldRegister::binaryType] = QVariant::ByteArray; + literalTypes[FieldRegister::datetimeType] = QVariant::DateTime; // Strigi encodes datetime as unsigned integer, i.e. addValue( ..., uint ) + } + + QVariant::Type literalType( const Strigi::FieldProperties& strigiType ) { + // it looks as if the typeUri can contain arbitrary values, URIs or stuff like "string" + QHash<std::string, QVariant::Type>::const_iterator it = literalTypes.find( strigiType.typeUri() ); + if ( it == literalTypes.constEnd() ) { + return LiteralValue::typeFromDataTypeUri( QUrl::fromEncoded( strigiType.typeUri().c_str() ) ); + } + else { + return *it; + } + } + + LiteralValue createLiteralValue( QVariant::Type type, + const unsigned char* data, + uint32_t size ) { + QString value = QString::fromUtf8( ( const char* )data, size ); + if ( type == QVariant::DateTime ) { // dataTime is stored as integer in strigi! + return LiteralValue( QDateTime::fromTime_t( value.toUInt() ) ); + } + else if ( type != QVariant::Invalid ) { + return LiteralValue::fromString( value, type ); + } + else { + // we default to string + return LiteralValue( value ); + } + } + +// ::Soprano::Index::IndexFilterModel* repository; + ::Soprano::Model* repository; + int indexTransactionID; + +private: + QHash<std::string, QVariant::Type> literalTypes; +}; + + +Strigi::Soprano::IndexWriter::IndexWriter( ::Soprano::Model* model ) + : Strigi::IndexWriter() +{ +// qDebug() << "IndexWriter::IndexWriter in thread" << QThread::currentThread(); + d = new Private; + d->repository = model; + Util::storeStrigiMiniOntology( d->repository ); +// qDebug() << "IndexWriter::IndexWriter done in thread" << QThread::currentThread(); +} + + +Strigi::Soprano::IndexWriter::~IndexWriter() +{ + delete d; +} + + +void Strigi::Soprano::IndexWriter::commit() +{ +} + + +// delete all indexed data for the files listed in entries +void Strigi::Soprano::IndexWriter::deleteEntries( const std::vector<std::string>& entries ) +{ +// qDebug() << "IndexWriter::deleteEntries in thread" << QThread::currentThread(); + + QString systemLocationUri = Util::fieldUri( FieldRegister::pathFieldName ).toString(); + for ( unsigned int i = 0; i < entries.size(); ++i ) { + QString path = QString::fromUtf8( entries[i].c_str() ); + QString query = QString( "select ?g where { ?r <%1> \"%2\"^^<%3> . " + "?g <http://www.strigi.org/fields#indexGraphFor> ?r . }" ) + .arg( systemLocationUri ) + .arg( path ) + .arg( Vocabulary::XMLSchema::string().toString() ); + +// qDebug() << "deleteEntries query:" << query; + + QueryResultIterator result = d->repository->executeQuery( query, ::Soprano::Query::QueryLanguageSparql ); + if ( result.next() ) { + Node indexGraph = result.binding( "g" ); + result.close(); + +// qDebug() << "Found indexGraph to delete:" << indexGraph; + + // delete the indexed data + d->repository->removeContext( indexGraph ); + + // delete the metadata + d->repository->removeAllStatements( Statement( indexGraph, Node(), Node() ) ); + } + } +} + + +void Strigi::Soprano::IndexWriter::deleteAllEntries() +{ +// qDebug() << "IndexWriter::deleteAllEntries in thread" << QThread::currentThread(); + + // query all index graphs (FIXME: would a type derived from nrl:Graph be better than only the predicate?) + QString query = QString( "select ?g where { ?g <http://www.strigi.org/fields#indexGraphFor> ?r . }" ); + + qDebug() << "deleteAllEntries query:" << query; + + QueryResultIterator result = d->repository->executeQuery( query, ::Soprano::Query::QUERY_LANGUAGE_SPARQL ); + QList<Node> allIndexGraphs = result.iterateBindings( "g" ).allNodes(); + for ( QList<Node>::const_iterator it = allIndexGraphs.constBegin(); it != allIndexGraphs.constEnd(); ++it ) { + Node indexGraph = *it; + + qDebug() << "Found indexGraph to delete:" << indexGraph; + + // delete the indexed data + d->repository->removeContext( indexGraph ); + + // delete the metadata + d->repository->removeAllStatements( Statement( indexGraph, Node(), Node() ) ); + } +} + + +// called for each indexed file +void Strigi::Soprano::IndexWriter::startAnalysis( const AnalysisResult* idx ) +{ + if ( idx->depth() > 0 ) { + return; + } + +// qDebug() << "IndexWriter::startAnalysis in thread" << QThread::currentThread(); + FileMetaData* data = new FileMetaData(); + data->fileUri = createResourceUri( idx ); + + // let's check if we already have data on the file + StatementIterator it = d->repository->listStatements( Node(), + QUrl::fromEncoded( "http://www.strigi.org/fields#indexGraphFor", QUrl::StrictMode ), // FIXME: put the URI somewhere else + data->fileUri ); + if ( it.next() ) { + data->context = it.current().subject().uri(); + } + else { + data->context = Util::uniqueUri( "http://www.strigi.org/contexts/", d->repository ); + } + +// qDebug() << "Starting analysis for" << data->fileUri << "in thread" << QThread::currentThread(); + + idx->setWriterData( data ); +} + + +void Strigi::Soprano::IndexWriter::addText( const AnalysisResult* idx, const char* text, int32_t length ) +{ + if ( idx->depth() > 0 ) { + return; + } + + FileMetaData* md = reinterpret_cast<FileMetaData*>( idx->writerData() ); + md->content.append( text, length ); +} + + +void Strigi::Soprano::IndexWriter::addValue( const AnalysisResult* idx, + const RegisteredField* field, + const std::string& value ) +{ + if ( idx->depth() > 0 ) { + return; + } + +// qDebug() << "IndexWriter::addValue in thread" << QThread::currentThread(); + if ( value.length() > 0 ) { + FileMetaData* md = reinterpret_cast<FileMetaData*>( idx->writerData() ); + RegisteredFieldData* rfd = reinterpret_cast<RegisteredFieldData*>( field->writerData() ); + + if ( rfd->isRdfType ) { + + // Strigi uses rdf:type improperly since it stores the value as a string. We have to + // make sure it is a resource. The problem is that this results in the type not being + // indexed properly. Thus, it cannot be searched with normal lucene queries. + // That is why we need to introduce a stringType property + + d->repository->addStatement( Statement( md->fileUri, + ::Soprano::Vocabulary::RDF::type(), + QUrl::fromEncoded( value.c_str(), QUrl::StrictMode ), // fromEncoded is faster than the plain constructor and all Xesam URIs work here + md->context) ); + d->repository->addStatement( Statement( md->fileUri, + QUrl::fromEncoded( "http://strigi.sourceforge.net/fields#rdf-string-type", QUrl::StrictMode ), + LiteralValue( QString::fromUtf8( value.c_str() ) ), + md->context) ); + } + + else { + d->repository->addStatement( Statement( md->fileUri, + rfd->property, + d->createLiteralValue( rfd->dataType, ( unsigned char* )value.c_str(), value.length() ), + md->context) ); + } + } +// qDebug() << "IndexWriter::addValue done in thread" << QThread::currentThread(); +} + + +// the main addValue method +void Strigi::Soprano::IndexWriter::addValue( const AnalysisResult* idx, + const RegisteredField* field, + const unsigned char* data, + uint32_t size ) +{ + addValue( idx, field, std::string( ( const char* )data, size ) ); +} + + +void Strigi::Soprano::IndexWriter::addValue( const AnalysisResult*, const RegisteredField*, + const std::string&, const std::string& ) +{ + // we do not support map types +} + + +void Strigi::Soprano::IndexWriter::addValue( const AnalysisResult* idx, + const RegisteredField* field, + uint32_t value ) +{ + if ( idx->depth() > 0 ) { + return; + } + +// qDebug() << "IndexWriter::addValue in thread" << QThread::currentThread(); + FileMetaData* md = reinterpret_cast<FileMetaData*>( idx->writerData() ); + RegisteredFieldData* rfd = reinterpret_cast<RegisteredFieldData*>( field->writerData() ); + + LiteralValue val( value ); + if ( field->type() == FieldRegister::datetimeType ) { + val = QDateTime::fromTime_t( value ); + } + + d->repository->addStatement( Statement( md->fileUri, + rfd->property, + val, + md->context) ); +// qDebug() << "IndexWriter::addValue done in thread" << QThread::currentThread(); +} + + +void Strigi::Soprano::IndexWriter::addValue( const AnalysisResult* idx, + const RegisteredField* field, + int32_t value ) +{ + if ( idx->depth() > 0 ) { + return; + } + +// qDebug() << "IndexWriter::addValue in thread" << QThread::currentThread(); + FileMetaData* md = reinterpret_cast<FileMetaData*>( idx->writerData() ); + RegisteredFieldData* rfd = reinterpret_cast<RegisteredFieldData*>( field->writerData() ); + + d->repository->addStatement( Statement( md->fileUri, + rfd->property, + LiteralValue( value ), + md->context) ); +// qDebug() << "IndexWriter::addValue done in thread" << QThread::currentThread(); +} + + +void Strigi::Soprano::IndexWriter::addValue( const AnalysisResult* idx, + const RegisteredField* field, + double value ) +{ + if ( idx->depth() > 0 ) { + return; + } + +// qDebug() << "IndexWriter::addValue in thread" << QThread::currentThread(); + FileMetaData* md = reinterpret_cast<FileMetaData*>( idx->writerData() ); + RegisteredFieldData* rfd = reinterpret_cast<RegisteredFieldData*>( field->writerData() ); + + d->repository->addStatement( Statement( md->fileUri, + rfd->property, + LiteralValue( value ), + md->context) ); +// qDebug() << "IndexWriter::addValue done in thread" << QThread::currentThread(); +} + + +void Strigi::Soprano::IndexWriter::addTriplet( const std::string& subject, + const std::string& predicate, const std::string& object ) +{ + // PROBLEM: which named graph (context) should we use here? Create a new one for each triple? Use one until the + // next commit()? + + // FIXME: create an NRL metadata graph + d->repository->addStatement( Statement( Node( QUrl( QString::fromUtf8( subject.c_str() ) ) ), + Node( QUrl( QString::fromUtf8( predicate.c_str() ) ) ), + Node( QUrl( QString::fromUtf8( object.c_str() ) ) ), + Node() ) ); +} + + +// called after each indexed file +void Strigi::Soprano::IndexWriter::finishAnalysis( const AnalysisResult* idx ) +{ + if ( idx->depth() > 0 ) { + return; + } + +// qDebug() << "IndexWriter::finishAnalysis in thread" << QThread::currentThread(); + FileMetaData* md = static_cast<FileMetaData*>( idx->writerData() ); + + if ( md->content.length() > 0 ) { + d->repository->addStatement( Statement( md->fileUri, + Vocabulary::Xesam::asText(), + LiteralValue( QString::fromUtf8( md->content.c_str() ) ), + md->context ) ); + } + + // Strigi only indexes files and extractors mostly (if at all) store the xesam:DataObject type (i.e. the contents) + // Thus, here we go the easy way and mark each indexed file as a xesam:File. + if ( QFileInfo( QFile::decodeName( idx->path().c_str() ) ).isDir() ) + d->repository->addStatement( Statement( md->fileUri, + Vocabulary::RDF::type(), + Vocabulary::Xesam::Folder(), + md->context ) ); + else + d->repository->addStatement( Statement( md->fileUri, + Vocabulary::RDF::type(), + Vocabulary::Xesam::File(), + md->context ) ); + + + // create the provedance data for the data graph + // TODO: add more data at some point when it becomes of interest + QUrl metaDataContext = Util::uniqueUri( "http://www.strigi.org/graphMetaData/", d->repository ); + d->repository->addStatement( Statement( md->context, + Vocabulary::RDF::type(), + Vocabulary::NRL::InstanceBase(), + metaDataContext ) ); + d->repository->addStatement( Statement( md->context, + Vocabulary::NAO::created(), + LiteralValue( QDateTime::currentDateTime() ), + metaDataContext ) ); + d->repository->addStatement( Statement( md->context, + QUrl::fromEncoded( "http://www.strigi.org/fields#indexGraphFor", QUrl::StrictMode ), // FIXME: put the URI somewhere else + md->fileUri, + metaDataContext ) ); + d->repository->addStatement( Statement( metaDataContext, + Vocabulary::RDF::type(), + Vocabulary::NRL::GraphMetadata(), + metaDataContext ) ); + + // cleanup + delete md; + idx->setWriterData( 0 ); + +// qDebug() << "IndexWriter::finishAnalysis done in thread" << QThread::currentThread(); +} + + +void Strigi::Soprano::IndexWriter::initWriterData( const Strigi::FieldRegister& f ) +{ + map<string, RegisteredField*>::const_iterator i; + map<string, RegisteredField*>::const_iterator end = f.fields().end(); + for (i = f.fields().begin(); i != end; ++i) { + QUrl prop = Util::fieldUri( i->second->key() ); + i->second->setWriterData( new RegisteredFieldData( prop, + prop == Vocabulary::RDF::type() + ? QVariant::Invalid + : d->literalType( i->second->properties() ) ) ); + } +} + + +void Strigi::Soprano::IndexWriter::releaseWriterData( const Strigi::FieldRegister& f ) +{ + map<string, RegisteredField*>::const_iterator i; + map<string, RegisteredField*>::const_iterator end = f.fields().end(); + for (i = f.fields().begin(); i != end; ++i) { + delete static_cast<RegisteredFieldData*>( i->second->writerData() ); + i->second->setWriterData( 0 ); + } +} diff -Naur nepomuk/strigibackend/util.cpp nepomuk/strigibackend/util.cpp --- nepomuk/strigibackend/util.cpp 2008-05-07 11:05:22.000000000 +0200 +++ nepomuk/strigibackend/util.cpp 2008-09-01 14:33:17.000000000 +0200 @@ -31,6 +31,10 @@ #include <Soprano/Index/CLuceneIndex> #include <Soprano/Model> #include <Soprano/Vocabulary/RDF> +#include <Soprano/Vocabulary/RDFS> +#include <Soprano/Vocabulary/Xesam> +#include <Soprano/Vocabulary/NRL> +#include <Soprano/Vocabulary/XMLSchema> #define STRIGI_NS "http://www.strigi.org/data#" @@ -81,7 +85,7 @@ return TString::fromUtf8( field.c_str() ); } else if ( QString( field.c_str() ) == ::Soprano::Vocabulary::RDF::type().toString() ) { - // see sopranoindexwriter:addValue for details in this conversion + // see sopranoindexwriter:addValue for details on this conversion static TString strigiType( "http://strigi.sourceforge.net/fields#rdf-string-type" ); return strigiType; } @@ -124,3 +128,41 @@ return Strigi::Variant(); } } + + +void Strigi::Soprano::Util::storeStrigiMiniOntology( ::Soprano::Model* model ) +{ + // we use some nice URI here although we still have the STRIGI_NS for backwards comp + // at some point (if parentUrl will not be moved to xesam) we should move to a proper onto + + QUrl graph( "http://nepomuk.kde.org/ontologies/2008/07/24/strigi/metadata" ); + ::Soprano::Statement parentUrlProp( fieldUri( FieldRegister::parentLocationFieldName ), + ::Soprano::Vocabulary::RDF::type(), + ::Soprano::Vocabulary::RDF::Property(), + graph ); + ::Soprano::Statement parentUrlRange( parentUrlProp.subject(), + ::Soprano::Vocabulary::RDFS::range(), + ::Soprano::Vocabulary::XMLSchema::string(), + graph ); + ::Soprano::Statement parentUrlDomain( parentUrlProp.subject(), + ::Soprano::Vocabulary::RDFS::domain(), + ::Soprano::Vocabulary::Xesam::File(), + graph ); + ::Soprano::Statement metaDataType( graph, + ::Soprano::Vocabulary::RDF::type(), + ::Soprano::Vocabulary::NRL::Ontology(), + graph ); + + if ( !model->containsStatement( parentUrlProp ) ) { + model->addStatement( parentUrlProp ); + } + if ( !model->containsStatement( parentUrlRange ) ) { + model->addStatement( parentUrlRange ); + } + if ( !model->containsStatement( parentUrlDomain ) ) { + model->addStatement( parentUrlDomain ); + } + if ( !model->containsStatement( metaDataType ) ) { + model->addStatement( metaDataType ); + } +} diff -Naur nepomuk/strigibackend/util.h nepomuk/strigibackend/util.h --- nepomuk/strigibackend/util.h 2008-05-07 11:05:22.000000000 +0200 +++ nepomuk/strigibackend/util.h 2008-09-01 14:33:17.000000000 +0200 @@ -34,14 +34,20 @@ class Variant; namespace Soprano { - namespace Util { - QUrl fieldUri( const std::string& s ); - QUrl fileUrl( const std::string& filename ); - std::string fieldName( const QUrl& uri ); - TString convertSearchField( const std::string& field ); - QUrl uniqueUri( const QString& ns, ::Soprano::Model* model ); - Strigi::Variant nodeToVariant( const ::Soprano::Node& node ); - } + namespace Util { + QUrl fieldUri( const std::string& s ); + QUrl fileUrl( const std::string& filename ); + std::string fieldName( const QUrl& uri ); + TString convertSearchField( const std::string& field ); + QUrl uniqueUri( const QString& ns, ::Soprano::Model* model ); + Strigi::Variant nodeToVariant( const ::Soprano::Node& node ); + + /** + * For now only stores the parentUrl property so it can be + * searched. + */ + void storeStrigiMiniOntology( ::Soprano::Model* model ); + } } }