2 Copyright (C) 2008 by Sebastian Trueg <trueg at kde.org>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include "kio_nepomuksearch.h"
20 #include "searchfolder.h"
22 #include <QtCore/QFile>
27 #include <KApplication>
28 #include <KCmdLineArgs>
29 #include <kio/global.h>
33 #include <Nepomuk/Resource>
34 #include <Nepomuk/ResourceManager>
35 #include <Nepomuk/Variant>
36 #include "queryparser.h"
38 #include <Soprano/Vocabulary/RDF>
39 #include <Soprano/Vocabulary/Xesam>
41 #include <sys/types.h>
46 KIO::UDSEntry
statDefaultSearchFolder( const QString
& name
) {
48 uds
.insert( KIO::UDSEntry::UDS_NAME
, name
);
49 uds
.insert( KIO::UDSEntry::UDS_ACCESS
, 0700 );
50 uds
.insert( KIO::UDSEntry::UDS_USER
, KUser().loginName() );
51 uds
.insert( KIO::UDSEntry::UDS_FILE_TYPE
, S_IFDIR
);
52 uds
.insert( KIO::UDSEntry::UDS_MIME_TYPE
, QString::fromLatin1( "inode/directory" ) );
56 // do not cache more than SEARCH_CACHE_MAX search folders at the same time
57 const int SEARCH_CACHE_MAX
= 5;
61 Nepomuk::SearchProtocol::SearchProtocol( const QByteArray
& poolSocket
, const QByteArray
& appSocket
)
62 : KIO::ForwardingSlaveBase( "nepomuksearch", poolSocket
, appSocket
)
64 // FIXME: load default searches from config
68 addDefaultSearch( i18n( "All Music Files" ), Search::Term( Soprano::Vocabulary::RDF::type(),
69 Soprano::Vocabulary::Xesam::Music() ) );
73 QDateTime
today( QDate::currentDate(), QTime(), Qt::UTC
);
74 term
.setType( Search::Term::AndTerm
);
75 term
.addSubTerm( Search::Term( Soprano::Vocabulary::RDF::type(), Soprano::Vocabulary::Xesam::File() ) );
76 term
.addSubTerm( Search::Term( Soprano::Vocabulary::Xesam::sourceModified(), today
, Search::Term::GreaterOrEqual
) );
77 addDefaultSearch( i18n( "Today's Files" ), term
);
80 term
= Search::Term();
81 term
.setType( Search::Term::AndTerm
);
82 term
.addSubTerm( Search::Term( Soprano::Vocabulary::RDF::type(), Soprano::Vocabulary::Xesam::File() ) );
83 QDateTime
yesterday( today
);
84 yesterday
.addDays( -1 );
85 term
.addSubTerm( Search::Term( Soprano::Vocabulary::Xesam::sourceModified(), yesterday
, Search::Term::GreaterOrEqual
) );
86 term
.addSubTerm( Search::Term( Soprano::Vocabulary::Xesam::sourceModified(), today
, Search::Term::Smaller
) );
87 addDefaultSearch( i18n( "Yesterday's Files" ), term
);
89 // select the 10 most recent files:
90 addDefaultSearch( i18n( "Recent Files" ),
91 Search::Query( "select distinct ?r where { "
92 "?r a <http://freedesktop.org/standards/xesam/1.0/core#File> . ?r "
93 "<http://freedesktop.org/standards/xesam/1.0/core#sourceModified> ?date . "
94 "} ORDER BY DESC(?date) LIMIT 10" ) );
98 Nepomuk::SearchProtocol::~SearchProtocol()
103 void Nepomuk::SearchProtocol::addDefaultSearch( const QString
& name
, const Search::Query
& q
)
105 Search::Query
query( q
);
106 query
.addRequestProperty( Soprano::Vocabulary::Xesam::url(), true );
107 m_defaultSearches
.insert( name
, query
);
111 Nepomuk::SearchFolder
* Nepomuk::SearchProtocol::extractSearchFolder( const KUrl
& url
)
113 QString name
= url
.path().section( '/', 0, 0, QString::SectionSkipEmpty
);
114 kDebug() << url
<< name
;
115 if ( SearchFolder
* sf
= getDefaultQueryFolder( name
) ) {
116 kDebug() << "-----> is default search folder";
119 else if ( SearchFolder
* sf
= getQueryResults( name
) ) {
120 kDebug() << "-----> is on-the-fly search folder";
124 kDebug() << "-----> does not exist.";
130 void Nepomuk::SearchProtocol::listDir( const KUrl
& url
)
135 // Root dir: * list default searches: "all music files", "recent files"
136 // * list configuration entries: "create new default search"
138 // Root dir with query:
139 // * execute the query (cached) and list its results
142 // * Look for a default search and execute that
145 if ( url
.path() == "/" ) {
148 else if ( url
.directory() == "/" &&
149 m_defaultSearches
.contains( url
.fileName() ) ) {
150 // the default search name is the folder name
151 listDefaultSearch( url
.fileName() );
154 // lets create an on-the-fly search
155 listQuery( url
.fileName() );
160 void Nepomuk::SearchProtocol::get( const KUrl
& url
)
163 ForwardingSlaveBase::get( url
);
167 void Nepomuk::SearchProtocol::put( const KUrl
& url
, int permissions
, KIO::JobFlags flags
)
169 kDebug() << url
<< permissions
<< flags
;
170 // this will work only for existing files (ie. overwrite to allow saving of opened files)
171 ForwardingSlaveBase::put( url
, permissions
, flags
);
175 void Nepomuk::SearchProtocol::mimetype( const KUrl
& url
)
179 if ( url
.path() == "/" ) {
180 mimeType( QString::fromLatin1( "inode/directory" ) );
183 else if ( url
.directory() == "/" &&
184 m_defaultSearches
.contains( url
.fileName() ) ) {
185 mimeType( QString::fromLatin1( "inode/directory" ) );
189 ForwardingSlaveBase::mimetype( url
);
194 void Nepomuk::SearchProtocol::stat( const KUrl
& url
)
198 if ( url
.path() == "/" ) {
199 if ( url
.queryItems().isEmpty() ) {
202 // stat the root path
205 uds
.insert( KIO::UDSEntry::UDS_NAME
, QString::fromLatin1( "/" ) );
206 uds
.insert( KIO::UDSEntry::UDS_ICON_NAME
, QString::fromLatin1( "nepomuk" ) );
207 uds
.insert( KIO::UDSEntry::UDS_FILE_TYPE
, S_IFDIR
);
208 uds
.insert( KIO::UDSEntry::UDS_MIME_TYPE
, QString::fromLatin1( "inode/directory" ) );
214 kDebug() << "query folder:" << url
.queryItemValue("query");
217 // stat a query folder
220 uds
.insert( KIO::UDSEntry::UDS_NAME
, url
.fileName() );
221 uds
.insert( KIO::UDSEntry::UDS_FILE_TYPE
, S_IFDIR
);
222 uds
.insert( KIO::UDSEntry::UDS_MIME_TYPE
, QString::fromLatin1( "inode/directory" ) );
228 else if ( url
.directory() == "/" ) {
229 if ( SearchFolder
* sf
= extractSearchFolder( url
) ) {
230 KIO::UDSEntry uds
= statDefaultSearchFolder( sf
->name() );
231 Q_ASSERT( !uds
.stringValue( KIO::UDSEntry::UDS_NAME
).isEmpty() );
236 error( KIO::ERR_DOES_NOT_EXIST
, url
.url() );
239 else if ( SearchFolder
* folder
= extractSearchFolder( url
) ) {
240 folder
->stat( url
.fileName() );
243 error( KIO::ERR_DOES_NOT_EXIST
, url
.url() );
248 bool Nepomuk::SearchProtocol::rewriteUrl( const KUrl
& url
, KUrl
& newURL
)
250 kDebug() << url
<< newURL
;
252 if ( SearchFolder
* folder
= extractSearchFolder( url
) ) {
253 if ( SearchEntry
* entry
= folder
->findEntry( url
.fileName() ) ) {
254 QString localPath
= entry
->entry().stringValue( KIO::UDSEntry::UDS_LOCAL_PATH
);
255 if ( localPath
.isEmpty() ) {
259 newURL
= entry
->resource();
269 void Nepomuk::SearchProtocol::listRoot()
273 listDefaultSearches();
276 listEntry( KIO::UDSEntry(), true );
281 void Nepomuk::SearchProtocol::listActions()
283 // FIXME: manage default searches
287 Nepomuk::SearchFolder
* Nepomuk::SearchProtocol::getQueryResults( const QString
& query
)
289 if ( m_searchCache
.contains( query
) ) {
290 return m_searchCache
[query
];
293 if ( m_searchCache
.count() >= SEARCH_CACHE_MAX
) {
294 QString oldestQuery
= m_searchCacheNameQueue
.dequeue();
295 delete m_searchCache
.take( oldestQuery
);
298 Search::Query q
= Nepomuk::Search::QueryParser::parseQuery( query
);
299 q
.addRequestProperty( Soprano::Vocabulary::Xesam::url(), true );
300 SearchFolder
* folder
= new SearchFolder( query
, q
, this );
301 m_searchCacheNameQueue
.enqueue( query
);
302 m_searchCache
.insert( query
, folder
);
308 Nepomuk::SearchFolder
* Nepomuk::SearchProtocol::getDefaultQueryFolder( const QString
& name
)
310 if ( m_defaultSearchCache
.contains( name
) ) {
311 return m_defaultSearchCache
[name
];
313 else if ( m_defaultSearches
.contains( name
) ) {
314 SearchFolder
* folder
= new SearchFolder( name
, m_defaultSearches
[name
], this );
315 m_defaultSearchCache
.insert( name
, folder
);
324 void Nepomuk::SearchProtocol::listQuery( const QString
& query
)
327 getQueryResults( query
)->list();
331 void Nepomuk::SearchProtocol::listDefaultSearches()
333 for ( QHash
<QString
, Nepomuk::Search::Query
>::const_iterator it
= m_defaultSearches
.constBegin();
334 it
!= m_defaultSearches
.constEnd(); ++it
) {
335 listEntry( statDefaultSearchFolder( it
.key() ), false );
340 void Nepomuk::SearchProtocol::listDefaultSearch( const QString
& name
)
343 if ( m_defaultSearches
.contains( name
) ) {
344 getDefaultQueryFolder( name
)->list();
347 error( KIO::ERR_CANNOT_ENTER_DIRECTORY
, "Unknown default search: " + name
);
354 KDE_EXPORT
int kdemain( int argc
, char **argv
)
356 // necessary to use other kio slaves
357 KComponentData( "kio_nepomuksearch" );
358 QCoreApplication
app( argc
, argv
);
360 if ( Nepomuk::ResourceManager::instance()->init() ) {
361 kError() << "Unable to initialized Nepomuk.";
365 kDebug(7102) << "Starting nepomuksearch slave " << getpid();
367 Nepomuk::SearchProtocol
slave( argv
[2], argv
[3] );
368 slave
.dispatchLoop();
370 kDebug(7102) << "Nepomuksearch slave Done";
376 #include "kio_nepomuksearch.moc"