~ubuntu-branches/ubuntu/natty/kdebase-runtime/natty-proposed

« back to all changes in this revision

Viewing changes to nepomuk/kioslaves/search/kio_nepomuksearch.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2010-11-24 11:07:10 UTC
  • mto: (0.8.7 upstream)
  • mto: This revision was merged to the branch mainline in revision 129.
  • Revision ID: james.westby@ubuntu.com-20101124110710-6dbsyw0yh21qvn82
Tags: upstream-4.5.80
ImportĀ upstreamĀ versionĀ 4.5.80

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
#include "kio_nepomuksearch.h"
20
20
#include "searchfolder.h"
21
 
#include "nfo.h"
22
 
#include "nie.h"
23
 
#include "pimo.h"
24
21
#include "nepomuksearchurltools.h"
 
22
#include "standardqueries.h"
 
23
#include "resourcestat.h"
25
24
 
26
25
#include <QtCore/QFile>
27
26
 
37
36
#include <KMimeType>
38
37
#include <KStandardDirs>
39
38
#include <KFileItem>
40
 
#include <KDirNotify>
41
39
 
42
40
#include <Nepomuk/Thing>
43
41
#include <Nepomuk/ResourceManager>
54
52
#include <Soprano/Vocabulary/NRL>
55
53
#include <Soprano/Vocabulary/NAO>
56
54
#include <Soprano/Vocabulary/XMLSchema>
 
55
#include <Nepomuk/Vocabulary/NFO>
 
56
#include <Nepomuk/Vocabulary/NIE>
 
57
#include <Nepomuk/Vocabulary/PIMO>
57
58
 
58
59
#include <sys/types.h>
59
60
#include <unistd.h>
67
68
        uds.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
68
69
        uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1( "inode/directory" ) );
69
70
        uds.insert( KIO::UDSEntry::UDS_ICON_OVERLAY_NAMES, QLatin1String( "nepomuk" ) );
70
 
        uds.insert( KIO::UDSEntry::UDS_NAME, Nepomuk::resourceUriToUdsName( url ) );
 
71
        uds.insert( KIO::UDSEntry::UDS_DISPLAY_TYPE, i18n( "Query folder" ) );
 
72
        uds.insert( KIO::UDSEntry::UDS_NAME, Nepomuk::Query::Query::titleFromQueryUrl( url ) );
71
73
        uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, Nepomuk::Query::Query::titleFromQueryUrl( url ) );
72
 
        uds.insert( KIO::UDSEntry::UDS_URL, url.url() );
 
74
        if ( url.hasQueryItem( QLatin1String( "resource" ) ) ) {
 
75
            Nepomuk::addGenericNepomukResourceData( Nepomuk::Resource( KUrl( url.queryItemValue( QLatin1String( "resource" ) ) ) ), uds );
 
76
        }
 
77
        Nepomuk::Query::Query query = Nepomuk::Query::Query::fromQueryUrl( url );
 
78
        if ( query.isValid() )
 
79
            uds.insert( KIO::UDSEntry::UDS_NEPOMUK_QUERY, query.toString() );
73
80
        return uds;
74
81
    }
75
82
 
76
 
 
77
 
    /**
78
 
     * Empty if the path only contains the query.
79
 
     */
80
 
    QString fileNameFromUrl( const KUrl& url ) {
81
 
        if ( url.hasQueryItem( QLatin1String( "sparql" ) ) ||
82
 
             url.hasQueryItem( QLatin1String( "query" ) ) ||
83
 
             url.hasQueryItem( QLatin1String( "encodedquery" ) ) ||
84
 
             url.directory() != QLatin1String( "/" ) ) {
85
 
            return url.fileName();
86
 
        }
87
 
        else {
88
 
            return QString();
89
 
        }
90
 
    }
91
 
 
92
83
    bool isRootUrl( const KUrl& url ) {
93
84
        const QString path = url.path(KUrl::RemoveTrailingSlash);
94
85
        return( !url.hasQuery() &&
95
86
                ( path.isEmpty() || path == QLatin1String("/") ) );
96
87
    }
 
88
 
 
89
    // a query folder has a non-empty path with a single section and a query parameter
 
90
    // Example: nepomuksearch:/My Query?query=foobar
 
91
    bool isQueryFolder( const KUrl& url ) {
 
92
        return( url.hasQuery() &&
 
93
                url.directory() == QLatin1String("/") );
 
94
    }
 
95
 
 
96
    // Legacy query URLs look like: nepomuksearch:/?query=xyz&title=foobar
 
97
    // i.e. an empty path and a query, new URLs have their title as path
 
98
    bool isLegacyQueryUrl( const KUrl& url ) {
 
99
        const QString path = url.path(KUrl::RemoveTrailingSlash);
 
100
        return( url.hasQuery() &&
 
101
                ( path.isEmpty() || path == QLatin1String("/") ) );
 
102
    }
 
103
 
 
104
    KUrl convertLegacyQueryUrl( const KUrl& url ) {
 
105
        KUrl newUrl(QLatin1String("nepomuksearch:/") + Nepomuk::Query::Query::titleFromQueryUrl(url));
 
106
        Nepomuk::Query::Query query = Nepomuk::Query::Query::fromQueryUrl(url);
 
107
        if(query.isValid())
 
108
            newUrl.addQueryItem(QLatin1String("encodedquery"), query.toString());
 
109
        else
 
110
            newUrl.addQueryItem(QLatin1String("sparql"), Nepomuk::Query::Query::sparqlFromQueryUrl(url));
 
111
        return newUrl;
 
112
    }
 
113
 
 
114
    Nepomuk::Query::Query rootQuery() {
 
115
        KConfig config( "kio_nepomuksearchrc" );
 
116
        QString queryStr = config.group( "General" ).readEntry( "Root query", QString() );
 
117
        Nepomuk::Query::Query query;
 
118
        if ( queryStr.isEmpty() )
 
119
            query = Nepomuk::lastModifiedFilesQuery();
 
120
        else
 
121
            query = Nepomuk::Query::Query::fromString( queryStr );
 
122
        query.setLimit( config.group( "General" ).readEntry( "Root query limit", 10 ) );
 
123
        return query;
 
124
    }
97
125
    const int s_historyMax = 10;
98
126
}
99
127
 
133
161
{
134
162
    kDebug() << url;
135
163
 
 
164
    // list the root folder
136
165
    if ( isRootUrl( url ) ) {
137
166
        listRoot();
138
167
    }
139
 
    else {
 
168
 
 
169
    // backwards compatibility with pre-4.6 query URLs
 
170
    else if( isLegacyQueryUrl( url ) ) {
 
171
        redirection( convertLegacyQueryUrl(url) );
 
172
        finished();
 
173
    }
 
174
 
 
175
    // list the actual query folders
 
176
    else if( isQueryFolder( url ) ) {
140
177
        if ( !ensureNepomukRunning(false) ) {
141
178
            // we defer the listing to later when Nepomuk is up and running
142
179
            listEntry( KIO::UDSEntry(),  true);
143
180
            finished();
144
181
        }
145
182
        else if ( SearchFolder* folder = getQueryFolder( url ) ) {
 
183
            updateQueryUrlHistory( url );
146
184
            folder->list();
147
185
            listEntry( KIO::UDSEntry(), true );
148
186
            finished();
151
189
            error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl() );
152
190
        }
153
191
    }
 
192
 
 
193
    // listing of query results that are folders
 
194
    else {
 
195
        ForwardingSlaveBase::listDir(url);
 
196
    }
154
197
}
155
198
 
156
199
 
181
224
{
182
225
    kDebug() << url;
183
226
 
 
227
    // the root url is always a folder
184
228
    if ( isRootUrl( url ) ) {
185
229
        mimeType( QString::fromLatin1( "inode/directory" ) );
186
230
        finished();
187
231
    }
188
 
    else if ( url.directory() == QLatin1String( "/" ) ) {
 
232
 
 
233
    // Query result URLs in the root folder do not include a query
 
234
    // while all query folders do. The latter ones are what we check
 
235
    // for here.
 
236
    else if ( url.directory() == QLatin1String( "/" ) &&
 
237
              url.hasQuery() ) {
189
238
        mimeType( QString::fromLatin1( "inode/directory" ) );
190
239
        finished();
191
240
    }
 
241
 
 
242
    // results are forwarded
192
243
    else {
193
244
        ForwardingSlaveBase::mimetype( url );
194
245
    }
199
250
{
200
251
    kDebug() << url;
201
252
 
 
253
    // the root folder
202
254
    if ( isRootUrl( url ) ) {
203
255
        kDebug() << "Stat root" << url;
204
256
        //
210
262
        uds.insert( KIO::UDSEntry::UDS_ICON_NAME, QString::fromLatin1( "nepomuk" ) );
211
263
        uds.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
212
264
        uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1( "inode/directory" ) );
 
265
        uds.insert( KIO::UDSEntry::UDS_NEPOMUK_QUERY, rootQuery().toString() );
213
266
 
214
267
        statEntry( uds );
215
268
        finished();
216
269
    }
217
 
    else if ( fileNameFromUrl( url ).isEmpty() ) {
 
270
 
 
271
    // query folders
 
272
    else if( isQueryFolder( url ) ) {
218
273
        kDebug() << "Stat search folder" << url;
219
274
        statEntry( statSearchFolder( url ) );
220
275
        finished();
221
276
    }
 
277
 
 
278
    // results are forwarded
222
279
    else {
223
280
        kDebug() << "Stat forward" << url;
224
281
        ForwardingSlaveBase::stat(url);
228
285
 
229
286
void Nepomuk::SearchProtocol::del(const KUrl& url, bool isFile)
230
287
{
231
 
    if ( isFile ) {
232
 
        ForwardingSlaveBase::del( url, isFile );
233
 
    }
234
 
    else {
235
 
        error( KIO::ERR_UNSUPPORTED_ACTION, url.prettyUrl() );
236
 
    }
 
288
    ForwardingSlaveBase::del( url, isFile );
237
289
}
238
290
 
239
291
 
246
298
}
247
299
 
248
300
 
249
 
void Nepomuk::SearchProtocol::prepareUDSEntry( KIO::UDSEntry&, bool ) const
 
301
void Nepomuk::SearchProtocol::prepareUDSEntry( KIO::UDSEntry& uds, bool listing ) const
250
302
{
251
 
    // we already handle UDS_URL in SearchFolder. No need to do anything more here.
 
303
    // for performace reasons we do encode the result's resource URI in the UDS_NAME
 
304
    // Otherwise we would have to re-query for each stat operation
 
305
    // This is simple for "direct" query results (SearchFolder takes care of that)
 
306
    // but a bit harder for items in results that are folders.
 
307
    // In the latter case we get the parent folder's resource URI (which is encoded in
 
308
    // the UDS_NAME) and append the filename.
 
309
    //
 
310
    // Also note that results listed via a SearchFolder will never go through this method
 
311
    // since they are listed directly and not via a forward. Forwarding will only happen
 
312
    // for search results that are folders and for non-listing operations.
 
313
 
 
314
    kDebug() << requestedUrl() << processedUrl() << uds.stringValue(KIO::UDSEntry::UDS_NAME);
 
315
    const QString name = uds.stringValue(KIO::UDSEntry::UDS_NAME);
 
316
    if(name != QLatin1String(".") && name != QLatin1String("..")) {
 
317
        // let the ForwardingSlaveBase create UDS_LOCAL_PATH and mimetype entries
 
318
        // This call depends on the original UDS_NAME which we change below. Thus, it
 
319
        // is important to let ForwardingSlaveBase do its thing before we start ours
 
320
        ForwardingSlaveBase::prepareUDSEntry( uds, listing );
 
321
 
 
322
        // encode the URL in the UDS_NAME to prevent a re-query in stat and friends
 
323
        KUrl resourceUrl(processedUrl());
 
324
        if(listing) {
 
325
            resourceUrl.addPath(name);
 
326
        }
 
327
        uds.insert(KIO::UDSEntry::UDS_NAME, Nepomuk::resourceUriToUdsName(resourceUrl));
 
328
        if ( !uds.contains( KIO::UDSEntry::UDS_DISPLAY_NAME ) ) {
 
329
            uds.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, name);
 
330
        }
 
331
 
 
332
        // There is a trade-off between using UDS_TARGET_URL or not. The advantage is that we get proper
 
333
        // file names in opening applications and non-KDE apps can handle the URLs properly. The downside
 
334
        // is that we lose the context information, i.e. query results cannot be browsed in the opening
 
335
        // application. We decide pro-filenames and pro-non-kde-apps here.
 
336
        if( resourceUrl.isLocalFile() ) {
 
337
            if ( uds.isDir() ) {
 
338
                Query::FileQuery query;
 
339
                query.addIncludeFolder( resourceUrl );
 
340
                uds.insert( KIO::UDSEntry::UDS_NEPOMUK_QUERY, query.toString() );
 
341
            }
 
342
            else {
 
343
                uds.insert( KIO::UDSEntry::UDS_TARGET_URL, resourceUrl.url() );
 
344
            }
 
345
        }
 
346
    }
252
347
}
253
348
 
254
349
 
256
351
{
257
352
    kDebug();
258
353
 
 
354
    // flush
 
355
    listEntry( KIO::UDSEntry(), true );
 
356
 
 
357
    Query::Query query = rootQuery();
 
358
    if ( query.isValid() ) {
 
359
        getQueryFolder( query.toSearchUrl() )->list();
 
360
    }
 
361
 
259
362
    listEntry( KIO::UDSEntry(), true );
260
363
    finished();
261
364
}
263
366
 
264
367
Nepomuk::SearchFolder* Nepomuk::SearchProtocol::getQueryFolder( const KUrl& url )
265
368
{
266
 
    // this is necessary to properly handle user queries which are encoded in the filename in
267
 
    // statSearchFolder(). This is necessary for cases in which UDS_URL is ignored like in
268
 
    // KUrlNavigator's popup menus
269
 
    KUrl normalizedUrl = Nepomuk::udsNameToResourceUri( url.fileName() );
270
 
    if ( normalizedUrl.protocol() != QLatin1String( "nepomuksearch" ) ) {
271
 
        normalizedUrl = url;
272
 
    }
273
 
 
274
 
    // here we strip off the entry's name since that is not part of the query URL
275
 
    if ( url.hasQuery() ) {
276
 
        normalizedUrl.setPath( QLatin1String( "/" ) );
277
 
    }
278
 
    else if ( url.directory() != QLatin1String( "/" ) ) {
279
 
        normalizedUrl.setPath( QLatin1String( "/" ) + url.path().section( '/', 0, 0 ) );
280
 
    }
281
 
 
282
 
    SearchFolder* folder = new SearchFolder( normalizedUrl, this );
283
 
    return folder;
 
369
    return new SearchFolder( url, this );
 
370
}
 
371
 
 
372
 
 
373
void Nepomuk::SearchProtocol::updateQueryUrlHistory( const KUrl& url )
 
374
{
 
375
    //
 
376
    // if the url is already in the history update its timestamp
 
377
    // otherwise remove the last item if we reached the max and then
 
378
    // add the url along with its timestamp
 
379
    //
 
380
    KSharedConfigPtr cfg = KSharedConfig::openConfig( "kio_nepomuksearchrc" );
 
381
    KConfigGroup grp = cfg->group( "Last Queries" );
 
382
 
 
383
    // read config
 
384
    const int cnt = grp.readEntry( "count", 0 );
 
385
    QList<QPair<KUrl, QDateTime> > entries;
 
386
    for ( int i = 0; i < cnt; ++i ) {
 
387
        KUrl u = grp.readEntry( QString::fromLatin1( "query_%1_url" ).arg( i ), QString() );
 
388
        QDateTime t = grp.readEntry( QString::fromLatin1( "query_%1_timestamp" ).arg( i ), QDateTime() );
 
389
        if ( !u.isEmpty() &&
 
390
             t.isValid() &&
 
391
             u != url ) {
 
392
            int pos = 0;
 
393
            while ( entries.count() > pos &&
 
394
                    entries[pos].second < t ) {
 
395
                ++pos;
 
396
            }
 
397
            entries.insert( pos, qMakePair( u, t ) );
 
398
        }
 
399
    }
 
400
    if ( entries.count() >= s_historyMax ) {
 
401
        entries.removeFirst();
 
402
    }
 
403
    entries.append( qMakePair( url, QDateTime::currentDateTime() ) );
 
404
 
 
405
    // write config back
 
406
    grp.deleteGroup();
 
407
    grp = cfg->group( "Last Queries" );
 
408
 
 
409
    for ( int i = 0; i < entries.count(); ++i ) {
 
410
        KUrl u = entries[i].first;
 
411
        QDateTime t = entries[i].second;
 
412
        grp.writeEntry( QString::fromLatin1( "query_%1_url" ).arg( i ), u.url() );
 
413
        grp.writeEntry( QString::fromLatin1( "query_%1_timestamp" ).arg( i ), t );
 
414
    }
 
415
    grp.writeEntry( QLatin1String( "count" ), entries.count() );
 
416
 
 
417
    cfg->sync();
284
418
}
285
419
 
286
420
 
303
437
    }
304
438
}
305
439
 
 
440
 
 
441
#if 0
 
442
void Nepomuk::SearchProtocol::listUserQueries()
 
443
{
 
444
    UserQueryUrlList userQueries;
 
445
    Q_FOREACH( const KUrl& url, userQueries ) {
 
446
        KIO::UDSEntry uds = statSearchFolder( url );
 
447
        uds.insert( KIO::UDSEntry::UDS_DISPLAY_TYPE, i18n( "Saved Query" ) );
 
448
        listEntry( uds, false );
 
449
    }
 
450
}
 
451
void Nepomuk::SearchProtocol::listLastQueries()
 
452
{
 
453
    KSharedConfigPtr cfg = KSharedConfig::openConfig( "kio_nepomuksearchrc" );
 
454
    KConfigGroup grp = cfg->group( "Last Queries" );
 
455
 
 
456
    // read config
 
457
    const int cnt = grp.readEntry( "count", 0 );
 
458
    QList<QPair<KUrl, QDateTime> > entries;
 
459
    for ( int i = 0; i < cnt; ++i ) {
 
460
        KUrl u = grp.readEntry( QString::fromLatin1( "query_%1_url" ).arg( i ), QString() );
 
461
        QDateTime t = grp.readEntry( QString::fromLatin1( "query_%1_timestamp" ).arg( i ), QDateTime() );
 
462
        if ( !u.isEmpty() && t.isValid() )
 
463
            listEntry( statLastQuery( u, t ), false );
 
464
    }
 
465
 
 
466
    listEntry( KIO::UDSEntry(), true );
 
467
    finished();
 
468
}
 
469
#endif
 
470
 
306
471
#include "kio_nepomuksearch.moc"