File kdebase-runtime-nepomuk-strigi2.patch of Package kdebase4-runtime
diff -Nru kdebase-runtime-4.3.2/nepomuk/kioslaves/search/CMakeLists.txt kdebase-runtime-4.3.2-new/nepomuk/kioslaves/search/CMakeLists.txt
--- kdebase-runtime-4.3.2/nepomuk/kioslaves/search/CMakeLists.txt 2009-07-21 17:18:35.000000000 +0200
+++ kdebase-runtime-4.3.2-new/nepomuk/kioslaves/search/CMakeLists.txt 2009-10-26 09:52:22.000000000 +0100
@@ -12,7 +12,7 @@
${nepomuk_SOURCE_DIR}/libnepomukquery
)
-add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
+add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS} -DDISABLE_NEPOMUK_LEGACY)
set(kio_nepomuksearch_PART_SRCS
kio_nepomuksearch.cpp
@@ -25,16 +25,29 @@
${nepomuk_SOURCE_DIR}/libnepomukquery/dbusoperators.cpp
)
-soprano_add_ontology(kio_nepomuksearch_PART_SRCS
- ${nepomukontologies_SOURCE_DIR}/nfo.trig
- "NFO"
- "Nepomuk::Vocabulary"
- "trig")
-soprano_add_ontology(kio_nepomuksearch_PART_SRCS
- ${nepomukontologies_SOURCE_DIR}/nie.trig
- "NIE"
- "Nepomuk::Vocabulary"
- "trig")
+# find the nfo.trig file from the kdebase installation
+#find_file(NIE_TRIG_SOURCE
+# nie.trig
+# PATHS "${KDE4_DATA_INSTALL_DIR}/.." "${KDE4_DATA_INSTALL_DIR}" ENV XDG_DATA_DIRS
+# PATH_SUFFIXES "apps/nepomuk/ontologies"
+# NO_DEFAULT_PATH
+# )
+#find_file(NFO_TRIG_SOURCE
+# nfo.trig
+# PATHS "${KDE4_DATA_INSTALL_DIR}/.." "${KDE4_DATA_INSTALL_DIR}" ENV XDG_DATA_DIRS
+# PATH_SUFFIXES "apps/nepomuk/ontologies"
+# NO_DEFAULT_PATH
+# )
+#find_file(PIMO_TRIG_SOURCE
+# pimo.trig
+# PATHS "${KDE4_DATA_INSTALL_DIR}/.." "${KDE4_DATA_INSTALL_DIR}" ENV XDG_DATA_DIRS
+# PATH_SUFFIXES "apps/nepomuk/ontologies"
+# NO_DEFAULT_PATH
+# )
+
+soprano_add_ontology(kio_nepomuksearch_PART_SRCS ${nepomukontologies_SOURCE_DIR}/nfo.trig "NFO" "Nepomuk::Vocabulary" "trig")
+soprano_add_ontology(kio_nepomuksearch_PART_SRCS ${nepomukontologies_SOURCE_DIR}/nie.trig "NIE" "Nepomuk::Vocabulary" "trig")
+soprano_add_ontology(kio_nepomuksearch_PART_SRCS ${nepomukontologies_SOURCE_DIR}/pimo.trig "PIMO" "Nepomuk::Vocabulary" "trig")
set_source_files_properties(
../../interfaces/org.kde.nepomuk.QueryService.xml
diff -Nru kdebase-runtime-4.3.2/nepomuk/kioslaves/search/kio_nepomuksearch.cpp kdebase-runtime-4.3.2-new/nepomuk/kioslaves/search/kio_nepomuksearch.cpp
--- kdebase-runtime-4.3.2/nepomuk/kioslaves/search/kio_nepomuksearch.cpp 2009-08-27 10:17:34.000000000 +0200
+++ kdebase-runtime-4.3.2-new/nepomuk/kioslaves/search/kio_nepomuksearch.cpp 2009-10-26 10:35:59.000000000 +0100
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2008-2009 by Sebastian Trueg <trueg at kde.org>
+ Copyright (C) 2008 by Sebastian Trueg <trueg at kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,6 +20,8 @@
#include "searchfolder.h"
#include "nfo.h"
#include "nie.h"
+#include "pimo.h"
+#include "queryserviceclient.h"
#include <QtCore/QFile>
@@ -27,10 +29,13 @@
#include <KDebug>
#include <KAboutData>
#include <KApplication>
+#include <KConfig>
+#include <KConfigGroup>
#include <KCmdLineArgs>
#include <kio/global.h>
#include <kio/job.h>
#include <KMimeType>
+#include <KStandardDirs>
#include <Nepomuk/Resource>
#include <Nepomuk/ResourceManager>
@@ -38,7 +43,10 @@
#include "queryparser.h"
#include <Soprano/Vocabulary/RDF>
-#include <Soprano/Vocabulary/Xesam>
+#include <Soprano/Vocabulary/RDFS>
+#include <Soprano/Vocabulary/NRL>
+#include <Soprano/Vocabulary/NAO>
+#include <Soprano/Vocabulary/XMLSchema>
#include <sys/types.h>
#include <unistd.h>
@@ -55,6 +63,53 @@
return uds;
}
+
+ //if type != 0, also retreives the type of the query and stores it into type
+ QString queryNameFromURL( const KUrl& url, Nepomuk::Search::Query::Type* type = 0 ) {
+ if(url.queryItems().contains( "sparql" ) ) {
+ if( type ) {
+ *type = Nepomuk::Search::Query::SPARQLQuery;
+ }
+ return url.queryItem( "sparql" );
+ }
+ else if(url.queryItems().contains( "query" ) ) {
+ if( type ) {
+ *type = Nepomuk::Search::Query::PlainQuery;
+ }
+ return url.queryItem( "query" );
+ }
+ else {
+ if( type ) {
+ *type = Nepomuk::Search::Query::PlainQuery;
+ }
+ return url.path().section( '/', 0, 0, QString::SectionSkipEmpty );
+ }
+ }
+
+ /**
+ * Empty if the path only contains the query.
+ */
+ QString fileNameFromUrl( const KUrl& url ) {
+ QString fn;
+ if ( url.hasQueryItem( QLatin1String( "sparql" ) ) ||
+ url.hasQueryItem( QLatin1String( "query" ) ) ||
+ url.directory() != QLatin1String( "/" ) ) {
+ return url.fileName();
+ }
+ else {
+ return QString();
+ }
+ }
+
+ Nepomuk::Search::Query createQuery( const QString& name, Nepomuk::Search::Query::Type type ) {
+ if( type == Nepomuk::Search::Query::PlainQuery ) {
+ return Nepomuk::Search::QueryParser::parseQuery( name );
+ }
+ else /*type == Search::Query::SPARQLQuery*/ {
+ return Nepomuk::Search::Query( name );
+ }
+ }
+
// do not cache more than SEARCH_CACHE_MAX search folders at the same time
const int SEARCH_CACHE_MAX = 5;
}
@@ -63,26 +118,21 @@
Nepomuk::SearchProtocol::SearchProtocol( const QByteArray& poolSocket, const QByteArray& appSocket )
: KIO::ForwardingSlaveBase( "nepomuksearch", poolSocket, appSocket )
{
- // FIXME: load default searches from config
- // FIXME: allow icons
+ // FIXME: trueg: install a file watch on this file and update it whenever the queries change.
+ // FIXME: trueg: also emit a KDirNotify signal to inform KIO about that change
+ KConfig config("kionepomukuserqueriesrc" );
+
+ foreach( QString search, config.group("Searches").readEntry("All searches", QStringList() ) )
+ {
+ search = search.simplified();
+ KConfigGroup grp = config.group(search);
+ KUrl url( QUrl( QString("nepomuksearch:/") + grp.readEntry("Query",QString() ) ) );
+
+ Search::Query::Type type;
+ QString name = queryNameFromURL(url, &type );
- // all music files
- Search::Term musicOrTerm;
- musicOrTerm.setType( Search::Term::OrTerm );
- musicOrTerm.addSubTerm( Search::Term( Soprano::Vocabulary::RDF::type(),
- Soprano::Vocabulary::Xesam::Music() ) );
- musicOrTerm.addSubTerm( Search::Term( Soprano::Vocabulary::RDF::type(),
- Nepomuk::Vocabulary::NFO::Audio() ) );
- addDefaultSearch( i18n( "All Music Files" ), musicOrTerm );
-
- // select the 10 most recent files:
- addDefaultSearch( i18n( "Recent Files" ),
- Search::Query( QString( "select distinct ?r where { "
- "?r a %1 . "
- "?r %2 ?date . "
- "} ORDER BY DESC(?date) LIMIT 10" )
- .arg(Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NFO::FileDataObject() ))
- .arg(Soprano::Node::resourceToN3( Nepomuk::Vocabulary::NFO::fileLastModified() )) ) );
+ addDefaultSearch(search, createQuery( name, type ) );
+ }
}
@@ -91,10 +141,25 @@
}
+bool Nepomuk::SearchProtocol::ensureNepomukRunning()
+{
+ if ( Nepomuk::ResourceManager::instance()->init() ) {
+ error( KIO::ERR_SLAVE_DEFINED, i18n( "The Nepomuk system is not activated. Unable to answer queries without it." ) );
+ return false;
+ }
+ else if ( !Nepomuk::Search::QueryServiceClient::serviceAvailable() ) {
+ error( KIO::ERR_SLAVE_DEFINED, i18n( "The Nepomuk query service is not running. Unable to answer queries without it." ) );
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+
void Nepomuk::SearchProtocol::addDefaultSearch( const QString& name, const Search::Query& q )
{
Search::Query query( q );
- query.addRequestProperty( Soprano::Vocabulary::Xesam::url(), true );
query.addRequestProperty( Nepomuk::Vocabulary::NIE::url(), true );
m_defaultSearches.insert( name, query );
}
@@ -102,13 +167,14 @@
Nepomuk::SearchFolder* Nepomuk::SearchProtocol::extractSearchFolder( const KUrl& url )
{
- QString name = url.path().section( '/', 0, 0, QString::SectionSkipEmpty );
+ Search::Query::Type type;
+ QString name = queryNameFromURL( url, &type );
kDebug() << url << name;
if ( SearchFolder* sf = getDefaultQueryFolder( name ) ) {
kDebug() << "-----> is default search folder";
return sf;
}
- else if ( SearchFolder* sf = getQueryResults( name ) ) {
+ else if ( SearchFolder* sf = getQueryResults( name, type ) ) {
kDebug() << "-----> is on-the-fly search folder";
return sf;
}
@@ -121,7 +187,12 @@
void Nepomuk::SearchProtocol::listDir( const KUrl& url )
{
- kDebug() << url;
+ Search::Query::Type type;
+ QString name = queryNameFromURL( url, &type );
+ kDebug() << url << name;
+
+ if ( !ensureNepomukRunning() )
+ return;
//
// Root dir: * list default searches: "all music files", "recent files"
@@ -134,17 +205,16 @@
// * Look for a default search and execute that
//
- if ( url.path() == "/" ) {
+ if ( name.isEmpty() ) {
listRoot();
}
- else if ( url.directory() == "/" &&
- m_defaultSearches.contains( url.fileName() ) ) {
+ else if ( m_defaultSearches.contains( name ) ) {
// the default search name is the folder name
- listDefaultSearch( url.fileName() );
+ listDefaultSearch( name );
}
else {
// lets create an on-the-fly search
- listQuery( url.fileName() );
+ listQuery( name, type );
}
}
@@ -152,6 +222,10 @@
void Nepomuk::SearchProtocol::get( const KUrl& url )
{
kDebug() << url;
+
+ if ( !ensureNepomukRunning() )
+ return;
+
ForwardingSlaveBase::get( url );
}
@@ -159,6 +233,10 @@
void Nepomuk::SearchProtocol::put( const KUrl& url, int permissions, KIO::JobFlags flags )
{
kDebug() << url << permissions << flags;
+
+ if ( !ensureNepomukRunning() )
+ return;
+
// this will work only for existing files (ie. overwrite to allow saving of opened files)
ForwardingSlaveBase::put( url, permissions, flags );
}
@@ -168,6 +246,9 @@
{
kDebug() << url;
+ if ( !ensureNepomukRunning() )
+ return;
+
if ( url.path() == "/" ) {
mimeType( QString::fromLatin1( "inode/directory" ) );
finished();
@@ -187,52 +268,84 @@
{
kDebug() << url;
- if ( url.path() == "/" ) {
- if ( url.queryItems().isEmpty() ) {
- kDebug() << "/";
- //
- // stat the root path
- //
- KIO::UDSEntry uds;
- uds.insert( KIO::UDSEntry::UDS_NAME, QString::fromLatin1( "/" ) );
- uds.insert( KIO::UDSEntry::UDS_ICON_NAME, QString::fromLatin1( "nepomuk" ) );
- uds.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
- uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1( "inode/directory" ) );
+ Search::Query::Type type;
+ QString name = queryNameFromURL( url, &type );
+ kDebug() << url << name;
- statEntry( uds );
- finished();
- }
- else {
- kDebug() << "query folder:" << url.queryItemValue("query");
+ if ( !ensureNepomukRunning() )
+ return;
+
+ //
+ // Root dir: * list default searches: "all music files", "recent files"
+ // * list configuration entries: "create new default search"
+ //
+ // Root dir with query:
+ // * execute the query (cached) and list its results
+ //
+ // some folder:
+ // * Look for a default search and execute that
+ //
- //
- // stat a query folder
- //
- KIO::UDSEntry uds;
- uds.insert( KIO::UDSEntry::UDS_NAME, url.fileName() );
- uds.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
- uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1( "inode/directory" ) );
+ if ( name.isEmpty() ) {
+ kDebug() << "Stating root" << url;
+ //
+ // stat the root path
+ //
+ KIO::UDSEntry uds;
+ uds.insert( KIO::UDSEntry::UDS_NAME, QString::fromLatin1( "/" ) );
+ uds.insert( KIO::UDSEntry::UDS_ICON_NAME, QString::fromLatin1( "nepomuk" ) );
+ uds.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
+ uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1( "inode/directory" ) );
- statEntry( uds );
- finished();
- }
+ statEntry( uds );
+ finished();
}
- else if ( url.directory() == "/" ) {
- if ( SearchFolder* sf = extractSearchFolder( url ) ) {
- KIO::UDSEntry uds = statDefaultSearchFolder( sf->name() );
- Q_ASSERT( !uds.stringValue( KIO::UDSEntry::UDS_NAME ).isEmpty() );
- statEntry( uds );
+ else if ( m_defaultSearches.contains( name ) ) {
+ kDebug() << "Stating default search" << url;
+ statEntry( statDefaultSearchFolder( name ) );
+ finished();
+ }
+ else if ( fileNameFromUrl(url).isEmpty() ) {
+ kDebug() << "Stating search folder" << url;
+ statEntry( statDefaultSearchFolder( name ) );
+ finished();
+ }
+ else {
+ kDebug() << "Stating file" << url;
+ ForwardingSlaveBase::stat(url);
+ }
+}
+
+
+void Nepomuk::SearchProtocol::del(const KUrl& url, bool isFile)
+{
+ if ( !ensureNepomukRunning() )
+ return;
+
+ Nepomuk::SearchFolder* folder = extractSearchFolder( url );
+
+ if (folder) {
+ if ( SearchEntry* entry = folder->findEntry( url.fileName() ) ) {
+ kDebug() << "findEntry returned something";
+
+ if ( entry->isFile() ) {
+ kDebug() << entry->resource() << "is file";
+ KIO::ForwardingSlaveBase::del(entry->entry().stringValue( KIO::UDSEntry::UDS_TARGET_URL ), isFile);
+ }
+ else {
+ kDebug() << entry->resource() << "is non file";
+ Nepomuk::Resource(entry->resource()).remove();
+ }
finished();
}
else {
- error( KIO::ERR_DOES_NOT_EXIST, url.url() );
+ kDebug() << "findEntry returned nothing";
+ error( KIO::ERR_DOES_NOT_EXIST, url.fileName() ); // not in m_entries
}
}
- else if ( SearchFolder* folder = extractSearchFolder( url ) ) {
- folder->stat( url.fileName() );
- }
else {
- error( KIO::ERR_DOES_NOT_EXIST, url.url() );
+ kDebug() << "ERROR : extractSearchFolder returned NOTHING";
+ error( KIO::ERR_DOES_NOT_EXIST, url.fileName() );
}
}
@@ -244,7 +357,7 @@
if ( SearchFolder* folder = extractSearchFolder( url ) ) {
if ( SearchEntry* entry = folder->findEntry( url.fileName() ) ) {
QString localPath = entry->entry().stringValue( KIO::UDSEntry::UDS_LOCAL_PATH );
- if ( localPath.isEmpty() ) {
+ if ( !localPath.isEmpty() ) {
newURL = localPath;
}
else {
@@ -276,7 +389,7 @@
}
-Nepomuk::SearchFolder* Nepomuk::SearchProtocol::getQueryResults( const QString& query )
+Nepomuk::SearchFolder* Nepomuk::SearchProtocol::getQueryResults( const QString& query, Search::Query::Type type )
{
if ( m_searchCache.contains( query ) ) {
return m_searchCache[query];
@@ -287,8 +400,8 @@
delete m_searchCache.take( oldestQuery );
}
- Search::Query q = Nepomuk::Search::QueryParser::parseQuery( query );
- q.addRequestProperty( Soprano::Vocabulary::Xesam::url(), true );
+ Search::Query q = createQuery( query, type );
+
q.addRequestProperty( Nepomuk::Vocabulary::NIE::url(), true );
SearchFolder* folder = new SearchFolder( query, q, this );
m_searchCacheNameQueue.enqueue( query );
@@ -314,10 +427,10 @@
}
-void Nepomuk::SearchProtocol::listQuery( const QString& query )
+void Nepomuk::SearchProtocol::listQuery( const QString& query, Search::Query::Type type )
{
kDebug() << query;
- getQueryResults( query )->list();
+ getQueryResults( query, type )->list();
}
@@ -350,11 +463,6 @@
KComponentData comp( "kio_nepomuksearch" );
QCoreApplication app( argc, argv );
- if ( Nepomuk::ResourceManager::instance()->init() ) {
- kError() << "Unable to initialized Nepomuk.";
- return -1;
- }
-
kDebug(7102) << "Starting nepomuksearch slave " << getpid();
Nepomuk::SearchProtocol slave( argv[2], argv[3] );
diff -Nru kdebase-runtime-4.3.2/nepomuk/kioslaves/search/kio_nepomuksearch.h kdebase-runtime-4.3.2-new/nepomuk/kioslaves/search/kio_nepomuksearch.h
--- kdebase-runtime-4.3.2/nepomuk/kioslaves/search/kio_nepomuksearch.h 2008-09-26 16:55:58.000000000 +0200
+++ kdebase-runtime-4.3.2-new/nepomuk/kioslaves/search/kio_nepomuksearch.h 2009-10-26 09:52:22.000000000 +0100
@@ -40,7 +40,7 @@
virtual ~SearchProtocol();
/**
- *
+ *
*/
void listDir( const KUrl& url );
@@ -66,6 +66,11 @@
*/
void stat( const KUrl& url );
+ /**
+ * Delete resources
+ */
+ void del(const KUrl&, bool);
+
protected:
/**
* reimplemented from ForwardingSlaveBase
@@ -73,8 +78,9 @@
bool rewriteUrl( const KUrl& url, KUrl& newURL );
private:
+ bool ensureNepomukRunning();
void listRoot();
- void listQuery( const QString& query );
+ void listQuery( const QString& query, Search::Query::Type type );
void listActions();
void listDefaultSearches();
void listDefaultSearch( const QString& path );
@@ -85,7 +91,7 @@
/**
* Get (possibly cached) query results
*/
- SearchFolder* getQueryResults( const QString& query );
+ SearchFolder* getQueryResults( const QString& query, Search::Query::Type type );
SearchFolder* getDefaultQueryFolder( const QString& name );
// the default search folders
diff -Nru kdebase-runtime-4.3.2/nepomuk/kioslaves/search/nepomuksearch.protocol kdebase-runtime-4.3.2-new/nepomuk/kioslaves/search/nepomuksearch.protocol
--- kdebase-runtime-4.3.2/nepomuk/kioslaves/search/nepomuksearch.protocol 2008-09-26 16:55:58.000000000 +0200
+++ kdebase-runtime-4.3.2-new/nepomuk/kioslaves/search/nepomuksearch.protocol 2009-10-26 09:52:22.000000000 +0100
@@ -5,7 +5,7 @@
output=filesystem
reading=true
writing=false
-deleting=false
+deleting=true
linking=false
makedir=false
moving=false
diff -Nru kdebase-runtime-4.3.2/nepomuk/kioslaves/search/searchfolder.cpp kdebase-runtime-4.3.2-new/nepomuk/kioslaves/search/searchfolder.cpp
--- kdebase-runtime-4.3.2/nepomuk/kioslaves/search/searchfolder.cpp 2009-08-27 10:17:34.000000000 +0200
+++ kdebase-runtime-4.3.2-new/nepomuk/kioslaves/search/searchfolder.cpp 2009-10-26 09:52:22.000000000 +0100
@@ -19,6 +19,7 @@
#include "searchfolder.h"
#include "nfo.h"
#include "nie.h"
+#include "pimo.h"
#include "queryserviceclient.h"
@@ -37,6 +38,7 @@
#include <KIO/NetAccess>
#include <KUser>
#include <kdirnotify.h>
+#include <kdeversion.h>
namespace {
@@ -59,9 +61,11 @@
Nepomuk::SearchEntry::SearchEntry( const QUrl& res,
- const KIO::UDSEntry& uds )
+ bool isFile,
+ const KIO::UDSEntry& uds)
: m_resource( res ),
- m_entry( uds )
+ m_entry( uds ),
+ m_isFile(isFile)
{
}
@@ -427,6 +431,19 @@
uds.insert( KIO::UDSEntry::UDS_USER, KUser().loginName() );
// uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, "application/x-nepomuk-resource" );
}
+#if KDE_IS_VERSION( 4, 3, 61 )
+ //
+ // We always want the display type, even for pimo thing linked files, in the
+ // end showing "Invoice" or "Letter" is better than "text file"
+ // However, mimetypes are better than generic stuff like pimo:Thing and pimo:Document
+ //
+ Nepomuk::Types::Class type( res.pimoThing().isValid() ? res.pimoThing().resourceType() : res.resourceType() );
+ if ( !isPimoThingLinkedFile ||
+ type.uri() != Nepomuk::Vocabulary::PIMO::Thing() ) {
+ if (!type.label().isEmpty())
+ uds.insert( KIO::UDSEntry::UDS_DISPLAY_TYPE, type.label() );
+ }
+#endif
//
// Although in KDE 4.3 the target url is sort of deprecated, we still set it.
@@ -461,7 +478,7 @@
uds.insert( KIO::UDSEntry::UDS_NAME, name );
uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, name );
- SearchEntry* entry = new SearchEntry( result.resourceUri(), uds );
+ SearchEntry* entry = new SearchEntry( result.resourceUri(), isFile, uds );
m_entries.insert( name, entry );
m_resourceNameMap.insert( result.resourceUri(), name );
diff -Nru kdebase-runtime-4.3.2/nepomuk/kioslaves/search/searchfolder.h kdebase-runtime-4.3.2-new/nepomuk/kioslaves/search/searchfolder.h
--- kdebase-runtime-4.3.2/nepomuk/kioslaves/search/searchfolder.h 2009-08-27 10:17:34.000000000 +0200
+++ kdebase-runtime-4.3.2-new/nepomuk/kioslaves/search/searchfolder.h 2009-10-26 09:52:22.000000000 +0100
@@ -48,14 +48,17 @@
{
public:
SearchEntry( const QUrl& uri,
+ bool isFile,
const KIO::UDSEntry& = KIO::UDSEntry() );
QUrl resource() const { return m_resource; }
KIO::UDSEntry entry() const { return m_entry; }
+ bool isFile() const { return m_isFile; }
private:
QUrl m_resource;
KIO::UDSEntry m_entry;
+ bool m_isFile;
friend class SearchFolder;
};
diff -Nru kdebase-runtime-4.3.2/nepomuk/libnepomukquery/dbusoperators.cpp kdebase-runtime-4.3.2-new/nepomuk/libnepomukquery/dbusoperators.cpp
--- kdebase-runtime-4.3.2/nepomuk/libnepomukquery/dbusoperators.cpp 2008-11-28 16:33:44.000000000 +0100
+++ kdebase-runtime-4.3.2-new/nepomuk/libnepomukquery/dbusoperators.cpp 2009-10-26 09:52:22.000000000 +0100
@@ -99,8 +99,9 @@
QDBusArgument& operator<<( QDBusArgument& arg, const Nepomuk::Search::Term& term )
{
//
- // Signature: (ii(isss)sss)
+ // Signature: (ibi(isss)sss)
// i -> type
+ // b -> positive/negative term
// i -> comparator type
// (isss) -> Soprano::LiteralValue encoded as a Soprano::Node for simplicity
// s -> resource
@@ -110,6 +111,7 @@
arg.beginStructure();
arg << ( int )term.type()
+ << term.positive()
<< ( int )term.comparator()
<< Soprano::Node( term.value() )
<< QString::fromAscii( term.resource().toEncoded() )
@@ -124,8 +126,9 @@
const QDBusArgument& operator>>( const QDBusArgument& arg, Nepomuk::Search::Term& term )
{
//
- // Signature: (ii(isss)sss)
+ // Signature: (ibi(isss)sss)
// i -> type
+ // b -> positive/negative term
// i -> comparator type
// (isss) -> Soprano::LiteralValue encoded as a Soprano::Node for simplicity
// s -> resource
@@ -135,16 +138,19 @@
arg.beginStructure();
int type = Nepomuk::Search::Term::InvalidTerm;
+ bool positive = true;
int comparator = Nepomuk::Search::Term::Equal;
Soprano::Node valueNode;
QString resource, field, property;
arg >> type
+ >> positive
>> comparator
>> valueNode
>> resource
>> field
>> property;
term.setType( Nepomuk::Search::Term::Type( type ) );
+ term.setPositive( positive );
term.setComparator( Nepomuk::Search::Term::Comparator( comparator ) );
if ( valueNode.isLiteral() )
term.setValue( valueNode.literal() );
@@ -183,13 +189,14 @@
QDBusArgument& operator<<( QDBusArgument& arg, const Nepomuk::Search::Query& query )
{
//
- // Signature: (isa(ii(isss)sss)a{iai}ia{sb})
+ // Signature: (isa(ii(isss)sss)a{iai}ia{sb}a{s})
// i -> type
// s -> sparql query
// a(ii(isss)sss) -> array of terms (first is root term)
// a{iai} -> hash of term relations
// i -> limit
// a{sb} -> request properties
+ // a{sb} -> folder limits
//
arg.beginStructure();
@@ -222,6 +229,15 @@
arg.endMapEntry();
}
arg.endMap();
+
+ arg.beginMap( QVariant::String, QVariant::Bool );
+ QList<Nepomuk::Search::Query::FolderLimit> folderLimits = query.folderLimits();
+ foreach( const Nepomuk::Search::Query::FolderLimit& fl, folderLimits ) {
+ arg.beginMapEntry();
+ arg << QString::fromAscii( fl.first.toEncoded() ) << fl.second;
+ arg.endMapEntry();
+ }
+ arg.endMap();
arg.endStructure();
@@ -244,13 +260,14 @@
const QDBusArgument& operator>>( const QDBusArgument& arg, Nepomuk::Search::Query& query )
{
//
- // Signature: (isa(ii(isss)sss)a{iai}ia{sb})
+ // Signature: (isa(ii(isss)sss)a{iai}ia{sb}a{s})
// i -> type
// s -> sparql query
// a(ii(isss)sss) -> array of terms (first is root term)
// a{iai} -> hash of term relations
// i -> limit
// a{sb} -> request properties
+ // a{sb} -> folder limits
//
arg.beginStructure();
@@ -288,6 +305,17 @@
query.addRequestProperty( QUrl::fromEncoded( prop.toAscii() ), optional );
}
arg.endMap();
+
+ arg.beginMap();
+ while( !arg.atEnd() ) {
+ QString prop;
+ bool include = true;
+ arg.beginMapEntry();
+ arg >> prop >> include;
+ arg.endMapEntry();
+ query.addFolderLimit( QUrl::fromEncoded( prop.toAscii() ), include );
+ }
+ arg.endMap();
arg.endStructure();
diff -Nru kdebase-runtime-4.3.2/nepomuk/libnepomukquery/query.cpp kdebase-runtime-4.3.2-new/nepomuk/libnepomukquery/query.cpp
--- kdebase-runtime-4.3.2/nepomuk/libnepomukquery/query.cpp 2008-09-26 16:55:58.000000000 +0200
+++ kdebase-runtime-4.3.2-new/nepomuk/libnepomukquery/query.cpp 2009-10-26 09:52:22.000000000 +0100
@@ -38,6 +38,7 @@
int limit;
QList<RequestProperty> requestProperties;
+ QList<FolderLimit> folderLimits;
};
@@ -145,14 +146,15 @@
namespace {
- bool compareRequestProperties( const QList<Nepomuk::Search::Query::RequestProperty>& rp1, const QList<Nepomuk::Search::Query::RequestProperty>& rp2 ) {
+ template<typename T>
+ bool compareQList( const QList<T>& rp1, const QList<T>& rp2 ) {
// brute force
- foreach( const Nepomuk::Search::Query::RequestProperty& rp, rp1 ) {
+ foreach( const T& rp, rp1 ) {
if ( !rp2.contains( rp ) ) {
return false;
}
}
- foreach( const Nepomuk::Search::Query::RequestProperty& rp, rp2 ) {
+ foreach( const T& rp, rp2 ) {
if ( !rp1.contains( rp ) ) {
return false;
}
@@ -167,11 +169,13 @@
d->limit == other.d->limit ) {
if ( d->type == SPARQLQuery ) {
return( d->sparqlQuery == other.d->sparqlQuery &&
- compareRequestProperties( d->requestProperties, other.d->requestProperties ) );
+ compareQList( d->requestProperties, other.d->requestProperties ) &&
+ compareQList( d->folderLimits, other.d->folderLimits ) );
}
else {
return( d->term == other.d->term &&
- compareRequestProperties( d->requestProperties, other.d->requestProperties ) );
+ compareQList( d->requestProperties, other.d->requestProperties ) &&
+ compareQList( d->folderLimits, other.d->folderLimits ) );
}
}
@@ -179,6 +183,24 @@
}
+void Nepomuk::Search::Query::addFolderLimit( const QUrl& folder, bool include )
+{
+ d->folderLimits.append( qMakePair( folder, include ) );
+}
+
+
+void Nepomuk::Search::Query::clearFolderLimits()
+{
+ d->folderLimits.clear();
+}
+
+
+QList<Nepomuk::Search::Query::FolderLimit> Nepomuk::Search::Query::folderLimits() const
+{
+ return d->folderLimits;
+}
+
+
QDebug operator<<( QDebug dbg, const Nepomuk::Search::Query& query )
{
dbg << "(Query" << query.term() << query.limit() << ")";
diff -Nru kdebase-runtime-4.3.2/nepomuk/libnepomukquery/query.h kdebase-runtime-4.3.2-new/nepomuk/libnepomukquery/query.h
--- kdebase-runtime-4.3.2/nepomuk/libnepomukquery/query.h 2008-09-26 16:55:58.000000000 +0200
+++ kdebase-runtime-4.3.2-new/nepomuk/libnepomukquery/query.h 2009-10-26 09:52:22.000000000 +0100
@@ -107,6 +107,20 @@
QList<RequestProperty> requestProperties() const;
bool operator==( const Query& ) const;
+
+ /**
+ * Add a folder to the search space. If no folder limits are set, will
+ * search the entire Nepomuk database
+ * \param folder the folder to search
+ * \param include true if we should search this folder, false
+ * if we should exclude this folder from search results
+ */
+ void addFolderLimit( const QUrl& folder, bool include );
+ void clearFolderLimits();
+
+ typedef QPair<QUrl, bool> FolderLimit;
+
+ QList<FolderLimit> folderLimits() const;
private:
class Private;
diff -Nru kdebase-runtime-4.3.2/nepomuk/libnepomukquery/queryparser.cpp kdebase-runtime-4.3.2-new/nepomuk/libnepomukquery/queryparser.cpp
--- kdebase-runtime-4.3.2/nepomuk/libnepomukquery/queryparser.cpp 2009-02-04 19:18:10.000000000 +0100
+++ kdebase-runtime-4.3.2-new/nepomuk/libnepomukquery/queryparser.cpp 2009-10-26 09:52:22.000000000 +0100
@@ -121,6 +121,17 @@
return Soprano::LiteralValue( d );
return s;
}
+
+ bool positiveTerm( const QString& s) {
+ if(s.isEmpty())
+ return true;
+ else if(s == "+")
+ return true;
+ else if(s == "-")
+ return false;
+ else //unrecognized capture
+ return true;
+ }
}
@@ -164,6 +175,7 @@
// TODO: a "real" parser which can handle all of the Xesam user language
// This one for example does not handle nesting at all.
+ Nepomuk::Search::Query final;
QList<Term> terms;
bool inOrBlock = false;
@@ -181,15 +193,15 @@
if ( pos < query.length() ) {
if ( s_resourceRx.indexIn( query, pos ) == pos ) {
- // FIXME: honour the +-
kDebug() << "matched resource term at" << pos << s_resourceRx.cap( 0 );
term = Term( tryToBeIntelligentAboutParsingUrl( s_resourceRx.cap( 2 ) ),
- tryToBeIntelligentAboutParsingUrl( s_resourceRx.cap( 3 ) ) );
+ tryToBeIntelligentAboutParsingUrl( s_resourceRx.cap( 3 ) ),
+ positiveTerm(s_resourceRx.cap( 1 ) ) );
pos += s_resourceRx.matchedLength();
}
else if ( s_propertyRx.indexIn( query, pos ) == pos ) {
- // FIXME: honour the +-
kDebug() << "matched property term at" << pos << s_propertyRx.cap( 0 );
+ term.setPositive( positiveTerm(s_propertyRx.cap( 1 ) ) );
term.setProperty( tryToBeIntelligentAboutParsingUrl( s_propertyRx.cap( 2 ) ) );
term.addSubTerm( Term( createLiteral( stripQuotes( s_propertyRx.cap( 4 ) ) ) ) );
QString comparator = s_propertyRx.cap( 3 );
@@ -213,17 +225,24 @@
pos += s_fieldFieldRx.matchedLength();
}
else if ( s_fieldRx.indexIn( query, pos ) == pos ) {
- // FIXME: honour the +-
kDebug() << "matched field term at" << pos << s_fieldRx.cap( 0 ) << s_fieldRx.cap( 2 ) << s_fieldRx.cap( 4 ) << s_fieldRx.cap( 5 );
- term.setField( stripQuotes( s_fieldRx.cap( 2 ) ) );
- term.addSubTerm( Term( createLiteral( stripQuotes( s_fieldRx.cap( 5 ) ) ) ) );
- QString comparator = s_fieldRx.cap( 4 );
- term.setType( Term::ComparisonTerm );
- term.setComparator( fieldTypeRelationFromString( comparator ) );
- pos += s_fieldRx.matchedLength();
+ if( stripQuotes ( s_fieldRx.cap( 2 ) ).compare( QString( "inFolder" ), Qt::CaseInsensitive ) == 0 ) {
+ QUrl path = QUrl::fromLocalFile( s_fieldRx.cap( 5 ) );
+ kDebug() << "found include path" << path;
+ final.addFolderLimit( path, positiveTerm( s_fieldRx.cap( 1 ) ) );
+ pos += s_fieldRx.matchedLength();
+ }
+ else {
+ term.setField( stripQuotes( s_fieldRx.cap( 2 ) ) );
+ term.setPositive( positiveTerm( s_fieldRx.cap( 1 ) ) );
+ term.addSubTerm( Term( createLiteral( stripQuotes( s_fieldRx.cap( 5 ) ) ) ) );
+ QString comparator = s_fieldRx.cap( 4 );
+ term.setType( Term::ComparisonTerm );
+ term.setComparator( fieldTypeRelationFromString( comparator ) );
+ pos += s_fieldRx.matchedLength();
+ }
}
else if ( s_plainTermRx.indexIn( query, pos ) == pos ) {
- // FIXME: honour the +-
QString value = stripQuotes( s_plainTermRx.cap( 2 ) );
if ( d->orKeywords.contains( value.toLower() ) ) {
inOrBlock = true;
@@ -233,7 +252,7 @@
}
else {
kDebug() << "matched literal at" << pos << value;
- term = Term( Soprano::LiteralValue( value ) );
+ term = Term( Soprano::LiteralValue( value ), positiveTerm(s_plainTermRx.cap( 1 ) ) );
}
pos += s_plainTermRx.matchedLength();
}
@@ -265,15 +284,17 @@
}
if ( terms.count() == 1 ) {
- return terms[0];
+ final.setTerm( terms[0] );
+ return final;
}
else if ( terms.count() > 0 ) {
Term t;
t.setType( Term::AndTerm );
t.setSubTerms( terms );
- return t;
+ final.setTerm( t );
+ return final;
}
else {
- return Term();
+ return final;
}
}
diff -Nru kdebase-runtime-4.3.2/nepomuk/libnepomukquery/term.cpp kdebase-runtime-4.3.2-new/nepomuk/libnepomukquery/term.cpp
--- kdebase-runtime-4.3.2/nepomuk/libnepomukquery/term.cpp 2009-02-04 19:18:10.000000000 +0100
+++ kdebase-runtime-4.3.2-new/nepomuk/libnepomukquery/term.cpp 2009-10-26 09:52:22.000000000 +0100
@@ -28,12 +28,14 @@
class Nepomuk::Search::Term::Private : public QSharedData
{
public:
- Private( Type t = InvalidTerm, Comparator c = Equal )
+ Private( Type t = InvalidTerm, bool p = true, Comparator c = Equal )
: type( t ),
+ positive( p ),
comparator( c ) {
}
Type type;
+ bool positive;
Comparator comparator;
Soprano::LiteralValue value;
QUrl resource;
@@ -55,8 +57,8 @@
}
-Nepomuk::Search::Term::Term( const Soprano::LiteralValue& value )
- : d( new Private( LiteralTerm ) )
+Nepomuk::Search::Term::Term( const Soprano::LiteralValue& value, bool isPositive )
+ : d( new Private( LiteralTerm, isPositive ) )
{
d->value = value;
}
@@ -69,24 +71,24 @@
}
-Nepomuk::Search::Term::Term( const QString& field, const Soprano::LiteralValue& value, Comparator c )
- : d( new Private( ComparisonTerm, c ) )
+Nepomuk::Search::Term::Term( const QString& field, const Soprano::LiteralValue& value, bool isPositive, Comparator c )
+ : d( new Private( ComparisonTerm, isPositive, c ) )
{
d->field = field;
d->subTerms.append( Term( value ) );
}
-Nepomuk::Search::Term::Term( const QUrl& field, const Soprano::LiteralValue& value, Comparator c )
- : d( new Private( ComparisonTerm, c ) )
+Nepomuk::Search::Term::Term( const QUrl& field, const Soprano::LiteralValue& value, bool isPositive, Comparator c )
+ : d( new Private( ComparisonTerm, isPositive, c ) )
{
d->property = field;
d->subTerms.append( Term( value ) );
}
-Nepomuk::Search::Term::Term( const QUrl& field, const QUrl& resource )
- : d( new Private( ComparisonTerm ) )
+Nepomuk::Search::Term::Term( const QUrl& field, const QUrl& resource, bool isPositive )
+ : d( new Private( ComparisonTerm, isPositive ) )
{
d->property = field;
d->subTerms.append( Term( resource ) );
@@ -139,6 +141,12 @@
}
+bool Nepomuk::Search::Term::positive() const
+{
+ return d->positive;
+}
+
+
Nepomuk::Search::Term::Type Nepomuk::Search::Term::type() const
{
return d->type;
@@ -181,6 +189,12 @@
}
+void Nepomuk::Search::Term::setPositive( bool positive )
+{
+ d->positive = positive;
+}
+
+
void Nepomuk::Search::Term::setType( Type type )
{
d->type = type;
@@ -312,6 +326,8 @@
default:
break;
}
+ if( !term.positive() )
+ dbg << "( negative )";
if ( term.type() == Nepomuk::Search::Term::ComparisonTerm ) {
if ( term.property().isValid() ) {
dbg << "Property" << term.property();
@@ -340,12 +356,13 @@
{
switch( term.type() ) {
case Nepomuk::Search::Term::LiteralTerm:
- return qHash( term.value().toString() );
+ return( qHash( term.value().toString() )<<8 | ( uint )term.positive() );
case Nepomuk::Search::Term::ComparisonTerm:
- return( qHash( term.property().isValid() ? term.property().toString() : term.field() )<<16 |
- qHash( term.subTerms().first() )<<8 |
- ( uint )term.comparator() );
+ return( qHash( term.property().isValid() ? term.property().toString() : term.field() )<<24 |
+ qHash( term.subTerms().first() )<<16 |
+ ( uint )term.comparator()<<8 |
+ ( uint )term.positive() );
case Nepomuk::Search::Term::AndTerm:
case Nepomuk::Search::Term::OrTerm: {
diff -Nru kdebase-runtime-4.3.2/nepomuk/libnepomukquery/term.h kdebase-runtime-4.3.2-new/nepomuk/libnepomukquery/term.h
--- kdebase-runtime-4.3.2/nepomuk/libnepomukquery/term.h 2008-10-30 15:13:02.000000000 +0100
+++ kdebase-runtime-4.3.2-new/nepomuk/libnepomukquery/term.h 2009-10-26 09:52:22.000000000 +0100
@@ -107,7 +107,7 @@
/**
* Construct a literal term.
*/
- Term( const Soprano::LiteralValue& value );
+ Term( const Soprano::LiteralValue& value, bool isPositive = true );
/**
* Construct a resource term.
@@ -121,7 +121,7 @@
* types are converted to string.
* \param comparator The Comparator to use
*/
- Term( const QString& field, const Soprano::LiteralValue& value, Comparator c = Contains );
+ Term( const QString& field, const Soprano::LiteralValue& value, bool isPositive = true, Comparator c = Contains );
/**
* Construct a Contains ComparisonTerm term.
@@ -130,14 +130,14 @@
* types are converted to string.
* \param comparator The Comparator to use
*/
- Term( const QUrl& field, const Soprano::LiteralValue& value, Comparator c = Contains );
+ Term( const QUrl& field, const Soprano::LiteralValue& value, bool isPositive = true, Comparator c = Contains );
/**
* Construct an EqualityTerm term.
* \param field The exact field to match
* \param value The resource that should be matched.
*/
- Term( const QUrl& field, const QUrl& resource );
+ Term( const QUrl& field, const QUrl& resource, bool isPositive = true );
/**
* Destructor
@@ -158,6 +158,11 @@
* \return \p true if the Term is valid.
*/
bool isValid() const;
+
+ /**
+ * \return \p true is the Term is positive
+ */
+ bool positive() const;
/**
* \return the Term type.
@@ -208,6 +213,11 @@
* \sa setSubTerms, addSubTerm
*/
QList<Term> subTerms() const;
+
+ /**
+ * Sets whether or not this term is positive
+ */
+ void setPositive( bool );
/**
* Set the type of the Term
diff -Nru kdebase-runtime-4.3.2/nepomuk/services/queryservice/CMakeLists.txt kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/CMakeLists.txt
--- kdebase-runtime-4.3.2/nepomuk/services/queryservice/CMakeLists.txt 2009-07-21 17:18:36.000000000 +0200
+++ kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/CMakeLists.txt 2009-10-26 09:52:22.000000000 +0100
@@ -2,8 +2,6 @@
include(SopranoAddOntology)
-add_definitions(-DKDE_DEFAULT_DEBUG_AREA=300104)
-
include_directories(
${QT_INCLUDES}
${KDE4_INCLUDES}
@@ -17,6 +15,7 @@
searchthread.cpp
folder.cpp
folderconnection.cpp
+ dateparser.cpp
${nepomuk_SOURCE_DIR}/libnepomukquery/result.cpp
${nepomuk_SOURCE_DIR}/libnepomukquery/query.cpp
${nepomuk_SOURCE_DIR}/libnepomukquery/term.cpp
@@ -24,6 +23,12 @@
${nepomuk_SOURCE_DIR}/libnepomukquery/dbusoperators.cpp
)
+#find_file(NFO_TRIG_SOURCE
+# nfo.trig
+# PATHS "${KDE4_DATA_INSTALL_DIR}/.." "${KDE4_DATA_INSTALL_DIR}" ENV XDG_DATA_DIRS
+# PATH_SUFFIXES "apps/nepomuk/ontologies"
+# NO_DEFAULT_PATH
+# )
soprano_add_ontology(queryservice_SRCS
${nepomukontologies_SOURCE_DIR}/nfo.trig
"NFO"
diff -Nru kdebase-runtime-4.3.2/nepomuk/services/queryservice/dateparser.cpp kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/dateparser.cpp
--- kdebase-runtime-4.3.2/nepomuk/services/queryservice/dateparser.cpp 1970-01-01 01:00:00.000000000 +0100
+++ kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/dateparser.cpp 2009-10-26 09:52:22.000000000 +0100
@@ -0,0 +1,356 @@
+/*
+* This file is part of the Nepomuk KDE project.
+* Copyright (c) 2009 Adam Kidder <thekidder@gmail.com>
+* Copyright (c) 2009 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 "dateparser.h"
+
+#include <KDebug>
+
+#include <QtCore/QLocale>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVector>
+
+
+namespace {
+ //represents a time difference from the current time, to represent relative dates
+ struct time_difference
+ {
+ time_difference() : seconds(0), minutes(0), hours(0), days(0), weeks(0), months(0), years(0) {}
+ int seconds, minutes, hours, days, weeks, months, years;
+ };
+
+ struct format
+ {
+ format() : pos(0) {}
+ format(const QRegExp& r, const QStringList& f) : regex(r), pos(0), useRelativeDate(false), formats(f) {}
+ format(const QRegExp& r, const time_difference& d, bool dr = false) : regex(r), pos(0), useRelativeDate(true), difference(d), dynamicRelative(dr) {}
+ QRegExp regex;
+ int pos;
+
+ bool useRelativeDate;
+ time_difference difference;
+ bool dynamicRelative;
+ QStringList formats;
+ };
+
+ struct date_string
+ {
+ QDate date;
+ unsigned int pos;
+ unsigned int length;
+ };
+}
+
+class Nepomuk::Search::DateParser::Private
+{
+public:
+ Private(const QString& text, unsigned int flags) :
+ m_text(text), m_locale(QLocale::English), m_flags(flags) {
+ //TODO: we are english-only here!
+ QStringList longMonthNames;
+ QStringList shortMonthNames;
+ for ( int i = 1; i <= 12; ++i ) {
+ longMonthNames << m_locale.monthName( i, QLocale::LongFormat );
+ shortMonthNames << m_locale.monthName( i, QLocale::ShortFormat );
+ }
+
+ // DD.MM.YYYY
+ format date1( QRegExp( "\\b\\d{1,2}\\.\\d{1,2}\\.\\d{4,4}\\b" ), QStringList("d.M.yyyy") );
+
+ // DD.MM.YY
+ format date2( QRegExp( "\\b\\d{1,2}\\.\\d{1,2}\\.\\d{2,2}\\b" ), QStringList("d.M.yy") );
+
+ // MM/DD/YYYY
+ format date3( QRegExp( "\\b\\d{1,2}/\\d{1,2}/\\d{4,4}\\b" ), QStringList("M/d/yyyy") );
+
+ // YYYY-MM-DD
+ format date13(QRegExp( "\\b\\d{4,4}-\\d{1,2}-\\d{1,2}\\b" ), QStringList("yyyy-M-d") );
+
+ // MM/DD/YY
+ format date4( QRegExp( "\\b\\d{1,2}/\\d{1,2}/\\d{2,2}\\b" ), QStringList("M/d/yy") );
+
+ // January MM [YYYY] (no word boundry at the end for 'st' or 'nd' or 'th') (also excluding ranges)
+ format date5( QRegExp( QString( "\\b(%1)\\s\\d{1,2}(?!(\\d|\\s?-\\s?\\d))(\\s\\d{4,4})?" ).arg( longMonthNames.join( "|" ) ) ),
+ QStringList("MMMM d") << QString("MMMM d yyyy") );
+
+ // January, MM [YYYY] (no word boundry at the end for 'st' or 'nd' or 'th') (also excluding ranges)
+ format date6( QRegExp( QString( "\\b(%1),\\s?\\d{1,2}(?!(\\d|\\s?-\\s?\\d))(\\s\\d{4,4})?" ).arg( longMonthNames.join( "|" ) ) ),
+ QStringList("MMMM, d") << QString("MMMM,d") << QString("MMMM, d yyyy") << QString("MMMM,d yyyy") );
+
+ // FIXME: trueg: IMHO something like "yesterday" should result in a range if not used with < or >.
+
+ //TODO: english only again!
+ time_difference days;
+ days.days = -1;
+ format date7( QRegExp( QString( "\\b(yesterday)\\b" ) ), days );
+
+ format date8( QRegExp( QString( "\\b(\\d{1,3}) (day)s? ago\\b" ) ), days, true );
+
+ time_difference weeks;
+ weeks.weeks = -1;
+ format date9( QRegExp( QString( "\\ba week ago\\b" ) ), weeks );
+
+ format date10( QRegExp( QString( "\\b(\\d{1,3}) (week)s? ago\\b" ) ), weeks, true );
+
+ time_difference months;
+ months.months = -1;
+ format date11( QRegExp( QString( "\\ba month ago\\b" ) ), months );
+
+ format date12( QRegExp( QString( "\\b(\\d{1,3}) (month)s? ago\\b" ) ), months, true );
+
+ m_regexes.push_back( date1 );
+ m_regexes.push_back( date2 );
+ m_regexes.push_back( date3 );
+ m_regexes.push_back( date4 );
+ m_regexes.push_back( date5 );
+ m_regexes.push_back( date6 );
+ m_regexes.push_back( date7 );
+ m_regexes.push_back( date8 );
+ m_regexes.push_back( date9 );
+ m_regexes.push_back( date10);
+ m_regexes.push_back( date11);
+ m_regexes.push_back( date12);
+ m_regexes.push_back( date13);
+ }
+
+
+ bool hasDate() {
+ if(!m_dates.empty()) return true;
+
+ while(m_dates.empty() && !finishedParsing())
+ {
+ parseAllRegexes();
+ }
+
+ if(!m_dates.empty()) return true;
+ return false;
+ }
+
+
+ QDate getDate() {
+ if( !m_dates.isEmpty() )
+ return m_dates.first().date;
+ else
+ return QDate();
+ }
+
+ void next() {
+ m_dates.pop_front();
+ }
+
+ unsigned int length() const {
+ if( !m_dates.isEmpty() )
+ return m_dates.first().length;
+ else
+ return 0;
+ }
+
+ unsigned int pos() const {
+ if( !m_dates.isEmpty() )
+ return m_dates.first().pos;
+ else
+ return 0;
+ }
+ int dateObject;
+
+private:
+ bool finishedParsing() {
+ foreach(format r, m_regexes) {
+ if(r.pos != -1) return false;
+ }
+ return true;
+ }
+
+
+ void parseAllRegexes() {
+ QVector<format>::iterator it ;
+ for(it = m_regexes.begin(); it != m_regexes.end(); ++it) {
+ it->pos = it->regex.indexIn(m_text, it->pos);
+ if( it->pos == -1 )
+ continue;
+ if( !it->useRelativeDate && (m_flags & AbsoluteDates) ) {
+ foreach(QString format, it->formats) {
+ QDate date = m_locale.toDate( it->regex.cap( 0 ), format );
+ if(date.isValid()) {
+ if(!format.contains( "yy" ) )
+ date.setDate( QDate::currentDate().year(), date.month(), date.day() );
+ kDebug() << "Found absolute date:" << date;
+ date_string dateObject;
+ dateObject.date = date;
+ dateObject.pos = it->pos;
+ dateObject.length = it->regex.matchedLength();
+ m_dates.append( dateObject );
+ break;
+ }
+ }
+ }
+ else if( m_flags & RelativeDates) {
+ int amount = 1;
+ if( it->dynamicRelative ) {
+ amount = it->regex.cap( 1 ).toInt();
+ kDebug() << "dynamic relative date, amount is" << amount << it->regex.cap( 1 );
+ }
+ QDate current( QDate::currentDate() );
+ current = current.addDays( it->difference.days * amount );
+ current = current.addDays( it->difference.weeks * 7 * amount );
+ current = current.addMonths( it->difference.months * amount );
+ current = current.addYears( it->difference.years * amount );
+
+ kDebug() << "Found relative date:" << current << it->regex.pattern();
+ date_string dateObject;
+ dateObject.date = current;
+ dateObject.pos = it->pos;
+ dateObject.length = it->regex.matchedLength();
+ m_dates.append( dateObject );
+ }
+ }
+ }
+
+
+ const QString& m_text;
+ QLocale m_locale;
+ QVector<format> m_regexes;
+ QList<date_string> m_dates;
+ unsigned int m_flags;
+};
+
+
+
+Nepomuk::Search::DateParser::DateParser(const QString& text, unsigned int flags) :
+ d( new Private(text, flags) ) {
+}
+
+
+Nepomuk::Search::DateParser::~DateParser() {
+ delete d;
+}
+
+bool Nepomuk::Search::DateParser::hasDate() {
+ return d->hasDate();
+}
+
+QDate Nepomuk::Search::DateParser::getDate() {
+ return d->getDate();
+}
+
+void Nepomuk::Search::DateParser::next() {
+ d->next();
+}
+
+unsigned int Nepomuk::Search::DateParser::pos() const {
+ return d->pos();
+}
+
+unsigned int Nepomuk::Search::DateParser::length() const {
+ return d->length();
+}
+
+class Nepomuk::Search::TimeParser::Private
+{
+public:
+ Private(const QString& text) : m_text(text), m_locale(QLocale::English) {
+ // hh:mm[pm|am]
+ format time1( QRegExp( "\\b\\d{1,2}\\:\\d{2,2}\\s?(pm|am|AM|PM)?\\b" ), QStringList("h:map") << QString("h:m ap") );
+
+ // hh:mm
+ format time2( QRegExp( "\\b\\d{1,2}\\:\\d{2,2}\\b(?!\\s?(pm|am|AM|PM))\\b" ), QStringList("h:m") );
+
+ m_regexes.push_back( time1 );
+ m_regexes.push_back( time2 );
+ }
+
+
+ bool hasTime() {
+ if(!m_times.empty()) return true;
+
+ while(m_times.empty() && !finishedParsing())
+ {
+ parseAllRegexes();
+ }
+
+ if(!m_times.empty()) return true;
+ return false;
+ }
+
+
+ QTime next() {
+ return m_times.takeFirst();
+ }
+private:
+ bool finishedParsing() {
+ foreach(format r, m_regexes) {
+ if(r.pos != -1) return false;
+ }
+ return true;
+ }
+
+
+ void parseAllRegexes() {
+ QVector<format>::iterator it ;
+ for(it = m_regexes.begin(); it != m_regexes.end(); ++it) {
+ it->pos = it->regex.indexIn(m_text, it->pos);
+ if( !it->useRelativeDate ) {
+ foreach(QString format, it->formats) {
+ QTime time = m_locale.toTime( it->regex.cap( 0 ), format );
+ if(time.isValid()) {
+ kDebug() << "Found time:" << time;
+ m_times.append( time );
+ break;
+ }
+ }
+ }
+ else {
+ QTime current( QTime::currentTime() );
+ current.addSecs( it->difference.seconds );
+ current.addSecs( it->difference.minutes * 60 );
+ current.addSecs( it->difference.hours * 60 * 60 );
+
+ kDebug() << "Found time:" << current;
+ m_times.append( current );
+ break;
+ }
+ }
+ }
+
+
+ const QString& m_text;
+ QLocale m_locale;
+ QVector<format> m_regexes;
+ QList<QTime> m_times;
+};
+
+
+
+Nepomuk::Search::TimeParser::TimeParser(const QString& text) : d( new Private(text) ) {
+}
+
+
+Nepomuk::Search::TimeParser::~TimeParser() {
+ delete d;
+}
+
+bool Nepomuk::Search::TimeParser::hasTime() {
+ return d->hasTime();
+}
+
+QTime Nepomuk::Search::TimeParser::next() {
+ return d->next();
+}
diff -Nru kdebase-runtime-4.3.2/nepomuk/services/queryservice/dateparser.h kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/dateparser.h
--- kdebase-runtime-4.3.2/nepomuk/services/queryservice/dateparser.h 1970-01-01 01:00:00.000000000 +0100
+++ kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/dateparser.h 2009-10-26 09:52:22.000000000 +0100
@@ -0,0 +1,83 @@
+/*
+* This file is part of the Nepomuk KDE project.
+* Copyright (c) 2009 Adam Kidder <thekidder@gmail.com>
+*
+* 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 <QtCore/QDate>
+#include <QtCore/QTime>
+
+
+namespace Nepomuk {
+ namespace Search {
+ /*DateTimeParser parses a string to extract QDateTime object(s). It is (will be) capable of extracting:
+ * fully qualified date times
+ * times qualified using a specified date
+ * dates qualified with a specified time
+ */
+ class DateTimeParser
+ {
+ public:
+ DateTimeParser(const QString& dateTimeString);
+
+
+ private:
+ const QString& text;
+ };
+
+
+ class DateParser
+ {
+ public:
+ //flags
+ const static unsigned int AbsoluteDates = 0x1;
+ const static unsigned int RelativeDates = 0x2;
+
+ DateParser(const QString& dateString, unsigned int flags = AbsoluteDates | RelativeDates);
+ ~DateParser();
+
+ //true if another date has been found
+ bool hasDate();
+ //advances to the next date
+ void next();
+
+ //next 3 functions only valid if hasDate()
+ QDate getDate();
+ //position of current extracted date
+ unsigned int pos() const;
+ //length of current extracted date string
+ unsigned int length() const;
+ private:
+ class Private;
+ Private* const d;
+ };
+
+ //FIXME: code duplication in DateParser and TimeParser
+ class TimeParser
+ {
+ public:
+ TimeParser(const QString& timeString);
+ ~TimeParser();
+
+ bool hasTime();
+ QTime next();
+ private:
+ class Private;
+ Private* const d;
+ };
+ }
+}
\ No newline at end of file
diff -Nru kdebase-runtime-4.3.2/nepomuk/services/queryservice/searchcore.cpp kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/searchcore.cpp
--- kdebase-runtime-4.3.2/nepomuk/services/queryservice/searchcore.cpp 2009-08-27 10:17:34.000000000 +0200
+++ kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/searchcore.cpp 2009-10-26 09:52:22.000000000 +0100
@@ -31,7 +31,7 @@
{
public:
Private()
- : cutOffScore( 0.0 ),
+ : cutOffScore( 0.0 ), // TODO: make this configurable through the service API
active( false ),
canceled( false ) {
}
diff -Nru kdebase-runtime-4.3.2/nepomuk/services/queryservice/searchcore.h kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/searchcore.h
--- kdebase-runtime-4.3.2/nepomuk/services/queryservice/searchcore.h 2009-08-27 10:17:34.000000000 +0200
+++ kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/searchcore.h 2009-10-26 09:52:22.000000000 +0100
@@ -54,7 +54,7 @@
public Q_SLOTS:
void query( const Query& query );
-
+
void cancel();
/**
diff -Nru kdebase-runtime-4.3.2/nepomuk/services/queryservice/searchthread.cpp kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/searchthread.cpp
--- kdebase-runtime-4.3.2/nepomuk/services/queryservice/searchthread.cpp 2009-07-21 17:18:36.000000000 +0200
+++ kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/searchthread.cpp 2009-10-26 09:52:22.000000000 +0100
@@ -17,6 +17,7 @@
Boston, MA 02110-1301, USA.
*/
+#include "dateparser.h"
#include "searchthread.h"
#include "term.h"
#include "nfo.h"
@@ -43,9 +44,12 @@
#include <Soprano/Vocabulary/Xesam>
#include <KDebug>
+#include <KDateTime>
#include <KRandom>
#include <QtCore/QTime>
+#include <QLatin1String>
+#include <QStringList>
@@ -94,6 +98,24 @@
return es;
}
+ QString createFolderFilterStringSparql( const Nepomuk::Search::SearchNode& node, const QString& varName = QString( "?r" ) )
+ {
+ QStringList positive, negative;
+ QString filter;
+
+ QList<Nepomuk::Search::Query::FolderLimit>::const_iterator it;
+ for( it = node.folderLimits.constBegin(); it != node.folderLimits.constEnd(); ++it ) {
+ QStringList& ref = it->second ? positive : negative;
+ ref.append( QString::fromAscii( it->first.toEncoded( QUrl::StripTrailingSlash ) ) );
+ }
+
+ if( !positive.isEmpty() )
+ filter += QString( " FILTER(REGEX(STR(%1), \"^%2/\")) ." ).arg( varName ).arg( positive.join( "|" ) );
+ if( !negative.isEmpty() )
+ filter += QString( " FILTER(!REGEX(STR(%1), \"^%2/\")) ." ).arg( varName ).arg( negative.join( "|" ) );
+ return filter;
+ }
+
QString luceneQueryEscape( const QUrl& s ) {
return luceneQueryEscape( QString::fromAscii( s.toEncoded() ) );
}
@@ -107,12 +129,35 @@
}
}
+ QString createFolderFilterStringLucene( const Nepomuk::Search::SearchNode& node )
+ {
+ QStringList positive, negative;
+ QString filter;
+
+ QList<Nepomuk::Search::Query::FolderLimit>::const_iterator it;
+ for( it = node.folderLimits.constBegin(); it != node.folderLimits.constEnd(); ++it ) {
+ QStringList& ref = it->second ? positive : negative;
+ QString notTerm = it->second ? QString() : QString( "NOT" );
+ ref.append( QString( "%1 id:%2/*" ).arg( notTerm ).arg( luceneQueryEscape( it->first ) ) );
+ }
+
+ if( !positive.isEmpty() )
+ filter += QString( " AND ( %1) " ).arg( positive.join( " OR " ) );
+ if( !negative.isEmpty() )
+ filter += QString( " AND %1 " ).arg( negative.join( " AND " ) );
+ return filter;
+ }
+
QString createLuceneQuery( const Nepomuk::Search::SearchNode& node ) {
+ const QString notTerm = node.term.positive() ? QLatin1String("") : QLatin1String( "NOT " );
+
+ QString filterString = createFolderFilterStringLucene( node );
+
if ( node.term.type() == Nepomuk::Search::Term::LiteralTerm ) {
- return createLuceneLiteralQuery( luceneQueryEscape( node.term.value().toString() ) );
+ return notTerm + createLuceneLiteralQuery( luceneQueryEscape( node.term.value().toString() ) ) + filterString;
}
else if ( node.term.type() == Nepomuk::Search::Term::ComparisonTerm ) {
- return luceneQueryEscape( node.term.property() ) + ':' + createLuceneLiteralQuery( luceneQueryEscape( node.term.subTerms().first().value().toString() ) );
+ return notTerm + luceneQueryEscape( node.term.property() ) + ':' + createLuceneLiteralQuery( luceneQueryEscape( node.term.subTerms().first().value().toString() ) ) + filterString;
}
else {
Q_ASSERT( node.term.type() == Nepomuk::Search::Term::AndTerm ||
@@ -151,6 +196,24 @@
}
+ Nepomuk::Search::Term::Comparator oppositeComparator( Nepomuk::Search::Term::Comparator c ) {
+ switch( c ) {
+ case Nepomuk::Search::Term::Greater:
+ return Nepomuk::Search::Term::SmallerOrEqual;
+ case Nepomuk::Search::Term::Smaller:
+ return Nepomuk::Search::Term::GreaterOrEqual;
+ case Nepomuk::Search::Term::GreaterOrEqual:
+ return Nepomuk::Search::Term::Smaller;
+ case Nepomuk::Search::Term::SmallerOrEqual:
+ return Nepomuk::Search::Term::Greater;
+ default:
+ kDebug() << "Unknown or invalid comparator:" << comparatorString(c);
+ //to remove warnings we return Contains as default
+ return Nepomuk::Search::Term::Contains;
+ }
+ }
+
+
bool isNumberLiteralValue( const Soprano::LiteralValue& value ) {
return value.isInt() || value.isInt64() || value.isUnsignedInt() || value.isUnsignedInt64() || value.isDouble();
}
@@ -168,11 +231,14 @@
QString createGraphPattern( const Nepomuk::Search::SearchNode& node, int& varCnt, const QString& varName = QString( "?r" ) )
{
+ //TODO: ugly code, refactor :(
switch( node.term.type() ) {
case Nepomuk::Search::Term::ComparisonTerm: {
Nepomuk::Search::Term subTerm( node.term.subTerms().first() );
+ QString filterString = createFolderFilterStringSparql( node );
+
//
// is the subterm (we only support one ATM) a final term (no further subterms)
// -> actually match the literal or resource
@@ -180,11 +246,12 @@
if ( subTerm.type() == Nepomuk::Search::Term::ResourceTerm ||
subTerm.type() == Nepomuk::Search::Term::LiteralTerm ) {
if( node.term.comparator() != Nepomuk::Search::Term::Equal ) {
+ Nepomuk::Search::Term::Comparator c = node.term.positive() ? node.term.comparator() : oppositeComparator( node.term.comparator() );
// For numbers there is no need for quotes + this way we can handle all the xsd decimal types
// FIXME: it may be necessary to escape stuff
QString filter = QString( "?var%1 %2 " )
.arg( ++varCnt )
- .arg( comparatorString( node.term.comparator() ) );
+ .arg( comparatorString( c ) );
if ( isNumberLiteralValue( subTerm.value() ) ) {
filter += subTerm.value().toString();
}
@@ -195,19 +262,31 @@
filter += QString( "^^<%1>" ).arg( prop.literalRangeType().dataTypeUri().toString() );
}
- return wrapInInstanceBaseGraphQuery( QString( "%1 <%2> ?var%3 . FILTER(%4) . " )
+ return wrapInInstanceBaseGraphQuery( QString( "%1 <%2> ?var%3 . FILTER(%4) . %5" )
.arg( varName )
.arg( QString::fromAscii( node.term.property().toEncoded() ) )
.arg( varCnt )
- .arg( filter ) );
+ .arg( filter )
+ .arg( filterString ) );
}
else {
if ( subTerm.type() == Nepomuk::Search::Term::ResourceTerm ) {
- return wrapInInstanceBaseGraphQuery( QString( "%1 <%2> <%3> . " )
- .arg( varName )
- .arg( QString::fromAscii( node.term.property().toEncoded() ) )
- .arg( QString::fromAscii( subTerm.resource().toEncoded() ) ) );
+ QString resourceLiteral( QString::fromAscii( subTerm.resource().toEncoded() ) );
+ QString resource = node.term.positive() ? Soprano::Node::resourceToN3( resourceLiteral ) : QString( "?v" );
+ QString baseTerm = QString( "%1 <%2> %3 . %4" )
+ .arg( varName )
+ .arg( QString::fromAscii( node.term.property().toEncoded() ) )
+ .arg( resource )
+ .arg( filterString );
+ if( node.term.positive() )
+ return wrapInInstanceBaseGraphQuery( baseTerm );
+ else {
+ return QString( " %1 OPTIONAL { %2 } FILTER(!BOUND(?v))" )
+ .arg( wrapInInstanceBaseGraphQuery( QString ( "%1 a ?type . " ).arg( varName ) ) )
+ .arg( wrapInInstanceBaseGraphQuery( baseTerm + QString(" FILTER(?v = <%1>) . ").arg( resourceLiteral ) ) );
+ }
}
+ //TODO: negation, folder filters here
else if ( Nepomuk::Types::Property( node.term.property() ).range().isValid() ) {
return wrapInInstanceBaseGraphQuery( QString( "%1 %2 ?x . " )
.arg( varName )
@@ -230,13 +309,14 @@
// property is defined to range to a plain one.
//
Nepomuk::Types::Property p( node.term.property() );
- return wrapInInstanceBaseGraphQuery( QString( "%1 <%2> \"%3\"^^<%4> . " )
+ return wrapInInstanceBaseGraphQuery( QString( "%1 <%2> \"%3\"^^<%4> . %5" )
.arg( varName )
.arg( QString::fromAscii( node.term.property().toEncoded() ) )
.arg( subTerm.value().toString() )
.arg( p.literalRangeType().dataTypeUri() == Soprano::Vocabulary::RDFS::Literal()
? Soprano::Vocabulary::XMLSchema::string().toString()
- : p.literalRangeType().dataTypeUri().toString() ) );
+ : p.literalRangeType().dataTypeUri().toString() )
+ .arg( filterString ) );
}
}
}
@@ -279,6 +359,57 @@
return QString();
}
+
+
+ QDateTime parseDateTime( const Soprano::LiteralValue& literal ) {
+ //TODO: change to DateTime parser once complete
+ Nepomuk::Search::DateParser date( literal.toString() );
+ if( date.hasDate() )
+ return QDateTime( date.getDate() );
+ else
+ {
+ Nepomuk::Search::TimeParser time( literal.toString() );
+ if(time.hasTime() )
+ return QDateTime(QDate::currentDate(), time.next() );
+ else
+ return QDateTime(); //return invalid datetime
+ }
+ }
+
+
+ Soprano::LiteralValue parseSizeType( const Soprano::LiteralValue& literal ) {
+ const double KiB = 1024.0;
+ const double MiB = KiB * 1024.0;
+ const double GiB = MiB * 1024.0;
+ const double TiB = GiB * 1024.0;
+
+ const double KB = 1000.0;
+ const double MB = KB * 1000.0;
+ const double GB = MB * 1000.0;
+ const double TB = GB * 1000.0;
+
+ QHash<QString, double> sizes;
+ sizes.insert( "KiB", KiB );
+ sizes.insert( "MiB", MiB );
+ sizes.insert( "GiB", GiB );
+ sizes.insert( "TiB", TiB );
+ sizes.insert( "KB", KB );
+ sizes.insert( "MB", MB );
+ sizes.insert( "GB", GB );
+ sizes.insert ("TB", TB );
+
+ QHash<QString, double>::const_iterator i;
+ for (i = sizes.constBegin(); i != sizes.constEnd(); ++i) {
+ QRegExp cur( QString("^([\\d]+.?[\\d]*)[\\s]*%1$").arg( i.key() ) );
+ if( cur.indexIn( literal.toString() ) != -1 ) {
+ double value = cur.cap( 1 ).toDouble();
+ double newValue = value * i.value();
+ kDebug() << "Found value" << value << i.key() << "->" << newValue;
+ return Soprano::LiteralValue( newValue );
+ }
+ }
+ return literal;
+ }
}
@@ -331,12 +462,14 @@
t = optimize( t );
kDebug() << "Optimized query:" << t;
- search( splitLuceneSparql( t ) /*optimize( resolveValues( resolveFields( m_searchTerm ) ) )*/, 1.0, true );
+ Nepomuk::Search::SearchNode temp = splitLuceneSparql( t, m_searchTerm.folderLimits() );
+
+ search( temp /*optimize( resolveValues( resolveFields( m_searchTerm ) ) )*/, 1.0, true );
}
else {
// FIXME: once we have the Soprano query API it should be simple to add the requestProperties here
// for now we do it the hacky way
- QString query = m_searchTerm.sparqlQuery();
+ QString query = tuneQuery( m_searchTerm.sparqlQuery() );
int pos = query.indexOf( QLatin1String( "where" ) );
if ( pos > 0 ) {
query.insert( pos, buildRequestPropertyVariableList() + ' ' );
@@ -346,6 +479,15 @@
}
}
+ //do relative date parsing here
+ DateParser date(query, DateParser::RelativeDates);
+ while( date.hasDate() ) {
+ //TODO: this will likely not work with multiple dates in a query due to changing string length
+ QString replaced = Soprano::Node::literalToN3( QDateTime(date.getDate()) );
+ query.replace( date.pos(), date.length(), replaced );
+ date.next();
+ }
+
sparqlQuery( query, 1.0, true );
}
@@ -480,7 +622,7 @@
QUrl hit = hits.binding( 0 ).uri();
if ( prop.range().uri() == Soprano::Vocabulary::RDFS::Resource() ||
Nepomuk::Resource( hit ).hasType( prop.range().uri() ) ) {
- orTerm.addSubTerm( Term( term.property(), hit ) );
+ orTerm.addSubTerm( Term( term.property(), hit, term.positive() ) );
if ( orTerm.subTerms().count() == MAX_RESOURCES ) {
break;
}
@@ -504,11 +646,43 @@
}
}
- // non-literal term or non-contains term -> handled in SPARQL query
+
else {
- Term newTerm( term );
- newTerm.setSubTerms( QList<Term>() << resolveValues( term.subTerms().first() ) );
- return newTerm;
+ //modify the value for specific ranges
+ QString dateTimeRange = QString("ASK {%1 %2 %3}")
+ .arg( Soprano::Node::resourceToN3( term.property().toString() ) )
+ .arg( Soprano::Node::resourceToN3( Soprano::Vocabulary::RDFS::range().toString() ) )
+ .arg( Soprano::Node::resourceToN3( Soprano::Vocabulary::XMLSchema::dateTime().toString() ) );
+ QString integerRange = QString("ASK {%1 %2 %3}")
+ .arg( Soprano::Node::resourceToN3( term.property().toString() ) )
+ .arg( Soprano::Node::resourceToN3( Soprano::Vocabulary::RDFS::range().toString() ) )
+ .arg( Soprano::Node::resourceToN3( Soprano::Vocabulary::XMLSchema::integer().toString() ) );
+
+ Soprano::QueryResultIterator dtRange = ResourceManager::instance()->mainModel()->executeQuery( dateTimeRange, Soprano::Query::QUERY_LANGUAGE_SPARQL );
+ Soprano::QueryResultIterator intRange = ResourceManager::instance()->mainModel()->executeQuery( integerRange , Soprano::Query::QUERY_LANGUAGE_SPARQL );
+ //look for date properties to parse
+ if( dtRange.boolValue() ) {
+ QDateTime dateTime = parseDateTime( term.subTerms().first().value() );
+ kDebug() << "datetime is" << dateTime;
+ Term newTerm( term.property(), dateTime, term.positive(), term.comparator() );
+ if( dateTime.isValid() )
+ return newTerm;
+ else {
+ Term newTerm( term );
+ newTerm.setSubTerms( QList<Term>() << resolveValues( term.subTerms().first() ) );
+ return newTerm;
+ }
+ }
+ //check for sizes
+ else if( intRange.boolValue() ) {
+ return Term( term.property(), parseSizeType( term.subTerms().first().value() ), term.positive(), term.comparator() );
+ }
+ // non-literal term or non-contains term -> handled in SPARQL query
+ else {
+ Term newTerm( term );
+ newTerm.setSubTerms( QList<Term>() << resolveValues( term.subTerms().first() ) );
+ return newTerm;
+ }
}
}
@@ -549,7 +723,8 @@
}
-Nepomuk::Search::SearchNode Nepomuk::Search::SearchThread::splitLuceneSparql( const Term& term )
+Nepomuk::Search::SearchNode Nepomuk::Search::SearchThread::splitLuceneSparql( const Nepomuk::Search::Term& term,
+ const QList<Nepomuk::Search::Query::FolderLimit>& folderLimits )
{
// Goal: separate the terms into 2 groups: literal and resource which are
// merged with only one AND or OR action. Is that possible?
@@ -562,18 +737,18 @@
switch( term.type() ) {
case Term::LiteralTerm:
- return SearchNode( term, SearchNode::Lucene );
+ return SearchNode( term, SearchNode::Lucene, folderLimits );
case Term::ComparisonTerm:
if ( term.comparator() == Term::Contains &&
term.subTerms().first().type() == Term::LiteralTerm ) {
// no need for subnides here - we only use the subterm's value
- return SearchNode( term, SearchNode::Lucene );
+ return SearchNode( term, SearchNode::Lucene, folderLimits );
}
else {
// all subnodes are resolved and can be handled in a SPARQL query
- SearchNode node( term, SearchNode::Sparql );
- node.subNodes += splitLuceneSparql( term.subTerms().first() );
+ SearchNode node( term, SearchNode::Sparql, folderLimits );
+ node.subNodes += splitLuceneSparql( term.subTerms().first(), folderLimits );
return node;
}
@@ -585,7 +760,7 @@
QList<Term>::const_iterator end( subTerms.constEnd() );
for ( QList<Term>::const_iterator it = subTerms.constBegin();
it != end; ++it ) {
- SearchNode node = splitLuceneSparql( *it );
+ SearchNode node = splitLuceneSparql( *it, folderLimits );
if ( node.type == SearchNode::Lucene ) {
luceneNodes += node;
}
@@ -598,24 +773,24 @@
}
if ( luceneNodes.count() && !sparqlNodes.count() && !unknownNodes.count() ) {
- return SearchNode( term, SearchNode::Lucene, luceneNodes );
+ return SearchNode( term, SearchNode::Lucene, folderLimits, luceneNodes );
}
else if ( !luceneNodes.count() && sparqlNodes.count() && !unknownNodes.count() ) {
- return SearchNode( term, SearchNode::Sparql, sparqlNodes );
+ return SearchNode( term, SearchNode::Sparql, folderLimits, sparqlNodes );
}
else if ( !luceneNodes.count() && !sparqlNodes.count() && unknownNodes.count() ) {
- return SearchNode( term, SearchNode::Unknown, unknownNodes );
+ return SearchNode( term, SearchNode::Unknown, folderLimits, unknownNodes );
}
else {
Term newTerm;
newTerm.setType( term.type() );
SearchNode andNode( newTerm );
if ( luceneNodes.count() )
- andNode.subNodes += SearchNode( term, SearchNode::Lucene, luceneNodes );
+ andNode.subNodes += SearchNode( term, SearchNode::Lucene, folderLimits, luceneNodes );
if ( sparqlNodes.count() )
- andNode.subNodes += SearchNode( term, SearchNode::Sparql, sparqlNodes );
+ andNode.subNodes += SearchNode( term, SearchNode::Sparql, folderLimits, sparqlNodes );
if ( unknownNodes.count() )
- andNode.subNodes += SearchNode( term, SearchNode::Unknown, unknownNodes );
+ andNode.subNodes += SearchNode( term, SearchNode::Unknown, folderLimits, unknownNodes );
return andNode;
}
}
@@ -755,9 +930,10 @@
// we do not search the data itself and do not have to filter
// BUT: What about inference?
- query = QString( "select ?p where { "
+ query = QString( "select distinct ?p where { "
"?p <%1> <%2> . "
"?p <%3> ?label . "
+ "?x ?p ?y . "
"FILTER(REGEX(STR(?label),'%4','i')) . }" )
.arg( Soprano::Vocabulary::RDF::type().toString() )
.arg( Soprano::Vocabulary::RDF::Property().toString() )
@@ -775,8 +951,9 @@
if ( results.isEmpty() ) {
- query = QString( "select ?p where { "
+ query = QString( "select distinct ?p where { "
"?p <%1> <%2> . "
+ "?x ?p ?y . "
"FILTER(REGEX(STR(?p),'%3','i')) . }" )
.arg( Soprano::Vocabulary::RDF::type().toString() )
.arg( Soprano::Vocabulary::RDF::Property().toString() )
@@ -799,7 +976,7 @@
QString Nepomuk::Search::SearchThread::createSparqlQuery( const Nepomuk::Search::SearchNode& node )
{
int varCnt = 0;
- return QString( "select distinct ?r %1 where { %3 %4 }" )
+ return QString( "select distinct ?r %1 where { %3 %2 }" )
.arg( buildRequestPropertyVariableList() )
.arg( createGraphPattern( node, varCnt ) )
.arg( buildRequestPropertyPatterns() );
@@ -965,4 +1142,55 @@
}
}
+
+void Nepomuk::Search::SearchThread::buildPrefixMap()
+{
+ // fixed prefixes
+ m_prefixes.insert( "rdf", Soprano::Vocabulary::RDF::rdfNamespace() );
+ m_prefixes.insert( "rdfs", Soprano::Vocabulary::RDFS::rdfsNamespace() );
+ m_prefixes.insert( "xsd", Soprano::Vocabulary::XMLSchema::xsdNamespace() );
+
+ // get prefixes from nepomuk
+ Soprano::QueryResultIterator it =
+ ResourceManager::instance()->mainModel()->executeQuery( QString( "select ?ns ?ab where { "
+ "?g %1 ?ns . "
+ "?g %2 ?ab . }" )
+ .arg( Soprano::Node::resourceToN3( Soprano::Vocabulary::NAO::hasDefaultNamespace() ) )
+ .arg( Soprano::Node::resourceToN3( Soprano::Vocabulary::NAO::hasDefaultNamespaceAbbreviation() ) ),
+ Soprano::Query::QueryLanguageSparql );
+ while ( it.next() ) {
+ QString ab = it["ab"].toString();
+ QUrl ns = it["ns"].toString();
+ if ( !m_prefixes.contains( ab ) ) {
+ m_prefixes.insert( ab, ns );
+ }
+ }
+}
+
+
+QString Nepomuk::Search::SearchThread::tuneQuery( const QString& query_ )
+{
+ QString query( query_ );
+
+ buildPrefixMap();
+
+ for ( QHash<QString, QUrl>::const_iterator it = m_prefixes.constBegin();
+ it != m_prefixes.constEnd(); ++it ) {
+ QString prefix = it.key();
+ QUrl ns = it.value();
+
+ // very stupid check for the prefix usage
+ if ( query.contains( prefix + ':' ) ) {
+ // if the prefix is not defined add it
+ if ( !query.contains( QRegExp( QString( "[pP][rR][eE][fF][iI][xX]\\s*%1\\s*:\\s*<%2>" )
+ .arg( prefix )
+ .arg( QRegExp::escape( ns.toString() ) ) ) ) ) {
+ query.prepend( QString( "prefix %1: <%2> " ).arg( prefix ).arg( ns.toString() ) );
+ }
+ }
+ }
+
+ return query;
+}
+
#include "searchthread.moc"
diff -Nru kdebase-runtime-4.3.2/nepomuk/services/queryservice/searchthread.h kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/searchthread.h
--- kdebase-runtime-4.3.2/nepomuk/services/queryservice/searchthread.h 2008-09-18 14:25:44.000000000 +0200
+++ kdebase-runtime-4.3.2-new/nepomuk/services/queryservice/searchthread.h 2009-10-26 09:52:22.000000000 +0100
@@ -47,14 +47,19 @@
Sparql
};
- SearchNode( const Term& t, Type tt = Unknown, const QList<SearchNode>& sub = QList<SearchNode>() )
+ SearchNode( const Term& t,
+ Type tt = Unknown,
+ const QList<Nepomuk::Search::Query::FolderLimit>& l = QList<Nepomuk::Search::Query::FolderLimit>(),
+ const QList<SearchNode>& sub = QList<SearchNode>() )
: term(t),
type(tt),
+ folderLimits(l),
subNodes(sub) {
}
-
+
Term term;
Type type;
+ QList<Nepomuk::Search::Query::FolderLimit> folderLimits;
QList<SearchNode> subNodes;
};
@@ -112,7 +117,7 @@
* Try to split the query into two (or more) subqueries, one of which will be
* executed against the lucene index and one against the soprano store.
*/
- SearchNode splitLuceneSparql( const Term& term );
+ SearchNode splitLuceneSparql( const Term& term, const QList<Nepomuk::Search::Query::FolderLimit>& folderLimits );
QList<QUrl> matchFieldName( const QString& field );
QHash<QUrl, Result> search( const SearchNode& node, double baseScore, bool reportResults = false );
@@ -128,12 +133,25 @@
QString createSparqlQuery( const SearchNode& node );
+ /**
+ * Fill m_prefixes with values from the Nepomuk db.
+ */
+ void buildPrefixMap();
+
+ /**
+ * Insert missing prefix statements into the query.
+ */
+ QString tuneQuery( const QString& query_ );
+
Query m_searchTerm;
double m_cutOffScore;
// status
int m_numResults;
bool m_canceled;
+
+ // cache of all prefixes that are supported
+ QHash<QString, QUrl> m_prefixes;
};
}
}