~ubuntu-branches/ubuntu/raring/plasma-mobile/raring-proposed

« back to all changes in this revision

Viewing changes to components/metadatamodel/metadatamodel.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2012-07-17 12:04:43 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20120717120443-q3ig9u2fnltx67yg
Tags: 2.0+git2012071701-0ubuntu1
* New upstream snapshot
* Remove build-dep on kde-runtime-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
*/
19
19
 
20
20
#include "metadatamodel.h"
21
 
#include "resourcewatcher.h"
 
21
#include "../../nepomuklegacy/resourcewatcher.h"
 
22
 
 
23
#include <cmath>
22
24
 
23
25
#include <QDBusConnection>
24
26
#include <QDBusServiceWatcher>
28
30
#include <KIcon>
29
31
#include <KImageCache>
30
32
#include <KMimeType>
 
33
#include <KService>
31
34
#include <KIO/PreviewJob>
32
35
 
33
36
#include <soprano/vocabulary.h>
34
37
 
35
38
#include <Nepomuk/File>
 
39
#include <Nepomuk/Tag>
 
40
#include <Nepomuk/Variant>
 
41
 
36
42
#include <Nepomuk/Query/AndTerm>
 
43
#include <Nepomuk/Query/OrTerm>
37
44
#include <Nepomuk/Query/NegationTerm>
38
45
#include <Nepomuk/Query/ResourceTerm>
39
 
#include <Nepomuk/Tag>
40
 
#include <Nepomuk/Variant>
41
 
#include <nepomuk/comparisonterm.h>
42
 
#include <nepomuk/literalterm.h>
43
 
#include <nepomuk/queryparser.h>
44
 
#include <nepomuk/resourcetypeterm.h>
45
 
#include <nepomuk/standardqueries.h>
46
 
 
47
 
#include <nepomuk/nfo.h>
48
 
#include <nepomuk/nie.h>
49
 
 
50
 
#include "kext.h"
51
 
 
 
46
#include <Nepomuk/Query/ComparisonTerm>
 
47
#include <Nepomuk/Query/LiteralTerm>
 
48
#include <Nepomuk/Query/QueryParser>
 
49
#include <Nepomuk/Query/ResourceTypeTerm>
 
50
#include <Nepomuk/Query/StandardQuery>
 
51
 
 
52
#include "kao.h"
 
53
 
 
54
using namespace Nepomuk::Vocabulary;
 
55
using namespace Soprano::Vocabulary;
52
56
 
53
57
MetadataModel::MetadataModel(QObject *parent)
54
58
    : AbstractMetadataModel(parent),
55
 
      m_queryClient(0),
56
 
      m_screenshotSize(180, 120)
 
59
      m_runningClients(0),
 
60
      m_countQueryClient(0),
 
61
      m_limit(0),
 
62
      m_pageSize(30),
 
63
      m_scoreResources(false),
 
64
      m_thumbnailSize(180, 120),
 
65
      m_thumbnailerPlugins(new QStringList(KIO::PreviewJob::availablePlugins()))
57
66
{
58
 
    m_queryTimer = new QTimer(this);
59
 
    m_queryTimer->setSingleShot(true);
60
 
    connect(m_queryTimer, SIGNAL(timeout()),
61
 
            this, SLOT(doQuery()));
62
 
 
63
67
    m_newEntriesTimer = new QTimer(this);
64
68
    m_newEntriesTimer->setSingleShot(true);
65
69
    connect(m_newEntriesTimer, SIGNAL(timeout()),
75
79
 
76
80
    m_watcher = new Nepomuk::ResourceWatcher(this);
77
81
 
78
 
    m_watcher->addProperty(QUrl("http://www.semanticdesktop.org/ontologies/2007/08/15/nao#numericRating"));
79
 
    connect(m_watcher, SIGNAL(propertyAdded(Nepomuk::Resource, Nepomuk::Types::Property, QVariant)),
80
 
            this, SLOT(propertyChanged(Nepomuk::Resource, Nepomuk::Types::Property, QVariant)));
 
82
    m_watcher->addProperty(NAO::numericRating());
 
83
    connect(m_watcher, SIGNAL(propertyAdded(Nepomuk::Resource,Nepomuk::Types::Property,QVariant)),
 
84
            this, SLOT(propertyChanged(Nepomuk::Resource,Nepomuk::Types::Property,QVariant)));
81
85
 
82
86
 
83
87
    QHash<int, QByteArray> roleNames;
 
88
    roleNames[Qt::DisplayRole] = "display";
 
89
    roleNames[Qt::DecorationRole] = "decoration";
84
90
    roleNames[Label] = "label";
85
91
    roleNames[Description] = "description";
86
92
    roleNames[Types] = "types";
113
119
 
114
120
void MetadataModel::setQuery(const Nepomuk::Query::Query &query)
115
121
{
116
 
    m_queryTimer->stop();
117
122
    m_query = query;
118
123
 
119
124
    if (Nepomuk::Query::QueryServiceClient::serviceAvailable()) {
120
 
        doQuery();
 
125
        askRefresh();
121
126
    }
122
127
}
123
128
 
128
133
 
129
134
void MetadataModel::setQueryString(const QString &query)
130
135
{
131
 
    if (query == m_queryString) {
 
136
    if (query == m_queryString || query == "nepomuk") {
132
137
        return;
133
138
    }
134
139
 
135
140
    m_queryString = query;
136
 
    m_queryTimer->start(0);
 
141
    askRefresh();
137
142
    emit queryStringChanged();
138
143
}
139
144
 
142
147
    return m_queryString;
143
148
}
144
149
 
 
150
void MetadataModel::setLimit(int limit)
 
151
{
 
152
    if (limit == m_limit) {
 
153
        return;
 
154
    }
 
155
 
 
156
    m_limit = limit;
 
157
    askRefresh();
 
158
    emit limitChanged();
 
159
}
 
160
 
 
161
int MetadataModel::limit() const
 
162
{
 
163
    return m_limit;
 
164
}
 
165
 
 
166
void MetadataModel::setScoreResources(bool score)
 
167
{
 
168
    if (m_scoreResources == score) {
 
169
        return;
 
170
    }
 
171
 
 
172
    m_scoreResources = score;
 
173
    askRefresh();
 
174
    emit scoreResourcesChanged();
 
175
}
 
176
 
 
177
bool MetadataModel::scoreResources() const
 
178
{
 
179
    return m_scoreResources;
 
180
}
 
181
 
 
182
void MetadataModel::setLazyLoading(bool lazy)
 
183
{
 
184
    //lazy loading depends from the page zise, that is not directly user controllable
 
185
    if (lazy == (m_pageSize > 0)) {
 
186
        return;
 
187
    }
 
188
 
 
189
    //TODO: a way to control this? maybe from the available memory?
 
190
    m_pageSize = lazy ? 30 : -1;
 
191
    askRefresh();
 
192
    emit lazyLoadingChanged();
 
193
}
 
194
 
 
195
bool MetadataModel::lazyLoading() const
 
196
{
 
197
    return (m_pageSize > 0);
 
198
}
 
199
 
145
200
 
146
201
 
147
202
void MetadataModel::setSortBy(const QVariantList &sortBy)
153
208
    }
154
209
 
155
210
    m_sortBy = stringList;
156
 
    m_queryTimer->start(0);
 
211
    askRefresh();
157
212
    emit sortByChanged();
158
213
}
159
214
 
169
224
    }
170
225
 
171
226
    m_sortOrder = sortOrder;
172
 
    m_queryTimer->start(0);
 
227
    askRefresh();
173
228
    emit sortOrderChanged();
174
229
}
175
230
 
183
238
{
184
239
    int index = -1;
185
240
    int i = 0;
186
 
    Nepomuk::Resource resToFind(resourceUri);
 
241
    Nepomuk::Resource resToFind = Nepomuk::Resource::fromResourceUri(resourceUri);
187
242
 
188
243
    foreach (const Nepomuk::Resource &res, m_resources) {
189
244
        if (res == resToFind) {
204
259
 
205
260
    //check if really all properties to build the query are null
206
261
    if (m_queryString.isEmpty() && resourceType().isEmpty() &&
207
 
        mimeType().isEmpty() && activityId().isEmpty() &&
 
262
        mimeTypeStrings().isEmpty() && activityId().isEmpty() &&
208
263
        tagStrings().size() == 0 && !startDate().isValid() &&
209
264
        !endDate().isValid() && minimumRating() <= 0 &&
210
265
        maximumRating() <= 0 && parameters->size() == 0) {
211
266
        return;
212
267
    }
213
 
    setStatus(Waiting);
214
268
    m_query = Nepomuk::Query::Query();
215
 
    m_query.setQueryFlags(Nepomuk::Query::Query::WithoutFullTextExcerpt);
 
269
    m_query.setQueryFlags(Nepomuk::Query::Query::WithoutFullTextExcerpt|Nepomuk::Query::Query::NoResultRestrictions);
216
270
    Nepomuk::Query::AndTerm rootTerm;
217
271
 
218
272
    if (!m_queryString.isEmpty()) {
223
277
        //FIXME: more elegant
224
278
        QString type = resourceType();
225
279
        bool negation = false;
226
 
        if (type.startsWith("!")) {
 
280
        if (type.startsWith('!')) {
227
281
            type = type.remove(0, 1);
228
282
            negation = true;
229
283
        }
232
286
            rootTerm.addSubTerm(Nepomuk::Query::NegationTerm::negateTerm(Nepomuk::Query::ResourceTypeTerm(propertyUrl(type))));
233
287
        } else {
234
288
            rootTerm.addSubTerm(Nepomuk::Query::ResourceTypeTerm(propertyUrl(type)));
235
 
            if (type != "nfo:Bookmark") {
 
289
            /*if (type != "nfo:Bookmark") {
236
290
                //FIXME: remove bookmarks if not explicitly asked for
237
291
                rootTerm.addSubTerm(Nepomuk::Query::NegationTerm::negateTerm(Nepomuk::Query::ResourceTypeTerm(propertyUrl("nfo:Bookmark"))));
238
 
            }
239
 
        }
240
 
    }
241
 
 
242
 
    if (!mimeType().isEmpty()) {
243
 
        QString type = mimeType();
244
 
        bool negation = false;
245
 
        if (type.startsWith("!")) {
246
 
            type = type.remove(0, 1);
247
 
            negation = true;
248
 
        }
249
 
 
250
 
        Nepomuk::Query::ComparisonTerm term(Nepomuk::Vocabulary::NIE::mimeType(), Nepomuk::Query::LiteralTerm(type));
251
 
 
252
 
        if (negation) {
 
292
            }*/
 
293
        }
 
294
        if (resourceType() == "nfo:Archive") {
 
295
            Nepomuk::Query::ComparisonTerm term(Nepomuk::Vocabulary::NIE::mimeType(), Nepomuk::Query::LiteralTerm("application/epub+zip"));
 
296
 
253
297
            rootTerm.addSubTerm(Nepomuk::Query::NegationTerm::negateTerm(term));
254
 
        } else {
255
 
            rootTerm.addSubTerm(term);
256
 
        }
 
298
        }
 
299
    }
 
300
 
 
301
    if (!mimeTypeStrings().isEmpty()) {
 
302
        Nepomuk::Query::OrTerm mimeTerm;
 
303
        foreach (QString type, mimeTypeStrings()) {
 
304
            if (type.isEmpty()) {
 
305
                continue;
 
306
            }
 
307
            bool negation = false;
 
308
            if (type.startsWith('!')) {
 
309
                type = type.remove(0, 1);
 
310
                negation = true;
 
311
            }
 
312
 
 
313
            Nepomuk::Query::ComparisonTerm term(Nepomuk::Vocabulary::NIE::mimeType(), Nepomuk::Query::LiteralTerm(type), Nepomuk::Query::ComparisonTerm::Equal);
 
314
 
 
315
            if (negation) {
 
316
                mimeTerm.addSubTerm(Nepomuk::Query::NegationTerm::negateTerm(term));
 
317
            } else {
 
318
                mimeTerm.addSubTerm(term);
 
319
            }
 
320
        }
 
321
        rootTerm.addSubTerm(mimeTerm);
257
322
    }
258
323
 
259
324
 
260
325
    if (parameters && parameters->size() > 0) {
261
326
        foreach (const QString &key, parameters->keys()) {
262
327
            QString parameter = parameters->value(key).toString();
 
328
            if (parameter.isEmpty()) {
 
329
                continue;
 
330
            }
263
331
            bool negation = false;
264
 
            if (parameter.startsWith("!")) {
 
332
            if (parameter.startsWith('!')) {
265
333
                parameter = parameter.remove(0, 1);
266
334
                negation = true;
267
335
            }
268
336
 
269
337
            //FIXME: Contains should work, but doesn't match for file names
270
 
            Nepomuk::Query::ComparisonTerm term(propertyUrl(key), Nepomuk::Query::LiteralTerm(parameter), Nepomuk::Query::ComparisonTerm::Regexp);
 
338
            // we must prepend and append "*" to the file name for the default Nepomuk match type (Contains) really work.
 
339
            Nepomuk::Query::ComparisonTerm term(propertyUrl(key), Nepomuk::Query::LiteralTerm(parameter));
271
340
 
272
341
            if (negation) {
273
342
                rootTerm.addSubTerm(Nepomuk::Query::NegationTerm::negateTerm(term));
281
350
    if (!activityId().isEmpty()) {
282
351
        QString activity = activityId();
283
352
        bool negation = false;
284
 
        if (activity.startsWith("!")) {
 
353
        if (activity.startsWith('!')) {
285
354
            activity = activity.remove(0, 1);
286
355
            negation = true;
287
356
        }
288
357
        kDebug() << "Asking for resources of activity" << activityId();
289
 
        Nepomuk::Resource acRes(activity, Nepomuk::Vocabulary::KEXT::Activity());
 
358
        Nepomuk::Resource acRes(activity, Nepomuk::Vocabulary::KAO::Activity());
290
359
        Nepomuk::Query::ComparisonTerm term(Soprano::Vocabulary::NAO::isRelated(), Nepomuk::Query::ResourceTerm(acRes));
291
360
        term.setInverted(true);
292
361
        if (negation) {
299
368
    foreach (const QString &tag, tagStrings()) {
300
369
        QString individualTag = tag;
301
370
        bool negation = false;
302
 
        if (individualTag.startsWith("!")) {
 
371
        if (individualTag.startsWith('!')) {
303
372
            individualTag = individualTag.remove(0, 1);
304
373
            negation = true;
305
374
        }
306
375
        Nepomuk::Query::ComparisonTerm term( Soprano::Vocabulary::NAO::hasTag(),
307
 
                                    Nepomuk::Query::LiteralTerm(individualTag));
 
376
                                    Nepomuk::Query::ResourceTerm(Nepomuk::Tag(individualTag)));
308
377
        if (negation) {
309
378
            rootTerm.addSubTerm(Nepomuk::Query::NegationTerm::negateTerm(term));
310
379
        } else {
328
397
        rootTerm.addSubTerm(term);
329
398
    }
330
399
 
 
400
    if (m_scoreResources) {
 
401
        QString activity = activityId();
 
402
        if (activity.startsWith('!')) {
 
403
            activity = activity.remove(0, 1);
 
404
        }
 
405
 
 
406
        Nepomuk::Query::ComparisonTerm term = Nepomuk::Query::ComparisonTerm(propertyUrl("kao:targettedResource"), Nepomuk::Query::Term());
 
407
        term.setVariableName("c");
 
408
        term.setInverted(true);
 
409
 
 
410
        Nepomuk::Query::AndTerm andTerm = Nepomuk::Query::AndTerm();
 
411
        Nepomuk::Query::ResourceTypeTerm typeTerm(KAO::ResourceScoreCache());
 
412
        andTerm.addSubTerm(typeTerm);
 
413
        if (!activity.isEmpty()) {
 
414
            Nepomuk::Query::ComparisonTerm usedActivityTerm(propertyUrl("kao:usedActivity"),
 
415
                                        Nepomuk::Query::ResourceTerm(Nepomuk::Resource(activity, Nepomuk::Vocabulary::KAO::Activity()))
 
416
                                                           );
 
417
            andTerm.addSubTerm(usedActivityTerm);
 
418
        }
 
419
        Nepomuk::Query::ComparisonTerm cachedScoreTerm(propertyUrl("kao:cachedScore"),
 
420
                                        Nepomuk::Query::Term());
 
421
        cachedScoreTerm.setVariableName("score");
 
422
        cachedScoreTerm.setSortWeight(1, Qt::DescendingOrder);
 
423
        andTerm.addSubTerm(cachedScoreTerm);
 
424
 
 
425
        term.setSubTerm(andTerm);
 
426
        rootTerm.addSubTerm(term);
 
427
    }
 
428
 
 
429
    //bind directly some properties, to avoid calling hyper inefficient resource::property
 
430
    /*{
 
431
        m_query.addRequestProperty(Nepomuk::Query::Query::RequestProperty(NIE::url()));
 
432
        m_query.addRequestProperty(Nepomuk::Query::Query::RequestProperty(NAO::hasSymbol()));
 
433
        m_query.addRequestProperty(Nepomuk::Query::Query::RequestProperty(NIE::mimeType()));
 
434
        m_query.addRequestProperty(Nepomuk::Query::Query::RequestProperty(NAO::description()));
 
435
        m_query.addRequestProperty(Nepomuk::Query::Query::RequestProperty(Xesam::description()));
 
436
        m_query.addRequestProperty(Nepomuk::Query::Query::RequestProperty(RDFS::comment()));
 
437
    }*/
331
438
 
332
439
    int weight = m_sortBy.length() + 1;
333
440
    foreach (const QString &sortProperty, m_sortBy) {
 
441
        if (sortProperty.isEmpty()) {
 
442
            continue;
 
443
        }
334
444
        Nepomuk::Query::ComparisonTerm sortTerm(propertyUrl(sortProperty), Nepomuk::Query::Term());
335
445
        sortTerm.setSortWeight(weight, m_sortOrder);
336
446
        rootTerm.addSubTerm(sortTerm);
347
457
    endResetModel();
348
458
    emit countChanged();
349
459
 
350
 
    delete m_queryClient;
351
 
    m_queryClient = new Nepomuk::Query::QueryServiceClient(this);
352
 
 
353
 
    connect(m_queryClient, SIGNAL(newEntries(const QList<Nepomuk::Query::Result> &)),
354
 
            this, SLOT(newEntries(const QList<Nepomuk::Query::Result> &)));
355
 
    connect(m_queryClient, SIGNAL(entriesRemoved(const QList<QUrl> &)),
356
 
            this, SLOT(entriesRemoved(const QList<QUrl> &)));
357
 
    connect(m_queryClient, SIGNAL(finishedListing()), this, SLOT(finishedListing()));
358
 
 
359
 
    /*FIXME: safe without limit?
360
 
    if (limit > RESULT_LIMIT || limit <= 0) {
361
 
        m_query.setLimit(RESULT_LIMIT);
362
 
    }
363
 
    */
364
 
 
365
 
    m_queryClient->query(m_query);
 
460
    delete m_countQueryClient;
 
461
    //qDeleteAll is broken in 4.8
 
462
    foreach (Nepomuk::Query::QueryServiceClient *client, m_queryClients) {
 
463
        delete client;
 
464
    }
 
465
    m_queryClients.clear();
 
466
    m_pagesForClient.clear();
 
467
    m_validIndexForPage.clear();
 
468
    m_queryClientsHistory.clear();
 
469
    m_cachedResources.clear();
 
470
    m_runningClients = 0;
 
471
    m_countQueryClient = new Nepomuk::Query::QueryServiceClient(this);
 
472
 
 
473
    connect(m_countQueryClient, SIGNAL(newEntries(QList<Nepomuk::Query::Result>)),
 
474
            this, SLOT(countQueryResult(QList<Nepomuk::Query::Result>)));
 
475
 
 
476
    if (m_limit > 0) {
 
477
        m_query.setLimit(m_limit);
 
478
    }
 
479
 
 
480
    m_countQueryClient->sparqlQuery(m_query.toSparqlQuery(Nepomuk::Query::Query::CreateCountQuery));
 
481
 
 
482
    //if page size is invalid, fetch all
 
483
    if (m_pageSize < 1) {
 
484
        fetchResultsPage(0);
 
485
    }
 
486
 
 
487
    //FIXME
 
488
    // Nepomuk::Query::QueryServiceClient does not emit finishedListing signal when there is no new entries (no matches).
 
489
    QTimer::singleShot(5000, this, SLOT(finishedListing()));
 
490
}
 
491
 
 
492
void MetadataModel::fetchResultsPage(int page)
 
493
{
 
494
    Nepomuk::Query::QueryServiceClient *client = new Nepomuk::Query::QueryServiceClient(this);
 
495
 
 
496
    m_queryClients[page] = client;
 
497
    m_pagesForClient[client] = page;
 
498
    m_validIndexForPage[page] = 0;
 
499
 
 
500
    Nepomuk::Query::Query pageQuery(m_query);
 
501
    if (m_pageSize > 0) {
 
502
        pageQuery.setOffset(m_pageSize*page);
 
503
        pageQuery.setLimit(m_pageSize);
 
504
    }
 
505
 
 
506
    client->query(pageQuery);
 
507
 
 
508
    connect(client, SIGNAL(newEntries(QList<Nepomuk::Query::Result>)),
 
509
            this, SLOT(newEntries(QList<Nepomuk::Query::Result>)));
 
510
    connect(client, SIGNAL(entriesRemoved(QList<QUrl>)),
 
511
            this, SLOT(entriesRemoved(QList<QUrl>)));
 
512
    connect(client, SIGNAL(finishedListing()), this, SLOT(finishedListing()));
 
513
 
 
514
    m_queryClientsHistory << client;
 
515
    ++m_runningClients;
 
516
}
 
517
 
 
518
void MetadataModel::countQueryResult(const QList< Nepomuk::Query::Result > &entries)
 
519
{
 
520
    setRunning(true);
 
521
    //this should be always 1
 
522
    foreach (const Nepomuk::Query::Result &res, entries) {
 
523
        int count = res.additionalBinding(QLatin1String("cnt")).variant().toInt();
 
524
 
 
525
        if (count < m_resources.size()) {
 
526
            beginRemoveRows(QModelIndex(), count-1, m_resources.size()-1);
 
527
            m_resources.resize(count);
 
528
            endRemoveRows();
 
529
        } else if (count > m_resources.size()) {
 
530
            beginInsertRows(QModelIndex(), m_resources.size(), count-1);
 
531
            m_resources.resize(count);
 
532
            endInsertRows();
 
533
        }
 
534
    }
366
535
}
367
536
 
368
537
void MetadataModel::newEntries(const QList< Nepomuk::Query::Result > &entries)
369
538
{
370
 
    setStatus(Running);
371
 
    foreach (Nepomuk::Query::Result res, entries) {
 
539
    const int page = m_pagesForClient.value(qobject_cast<Nepomuk::Query::QueryServiceClient *>(sender()));
 
540
 
 
541
    foreach (const Nepomuk::Query::Result &res, entries) {
372
542
        //kDebug() << "Result!!!" << res.resource().genericLabel() << res.resource().type();
373
543
        //kDebug() << "Result label:" << res.genericLabel();
374
 
        m_resourcesToInsert << res.resource();
 
544
 
 
545
        Nepomuk::Resource resource = res.resource();
 
546
        if (resource.property(propertyUrl("nie:url")).toString().isEmpty()) {
 
547
            continue;
 
548
        }
 
549
        m_resourcesToInsert[page] << resource;
 
550
 
 
551
        //pre-popuplating of the cache to avoid accessing properties directly
 
552
        //label is a bit too complex to take from query
 
553
        if (resource.hasType(Nepomuk::Vocabulary::NFO::PaginatedTextDocument())) { // pdf files
 
554
            m_cachedResources[resource][Label] = resource.property(Nepomuk::Vocabulary::NFO::fileName()).toString();
 
555
            //kDebug() << "Using label" << m_cachedResources[resource][Label] << "instead of" << resource.genericLabel();
 
556
        } else {
 
557
            m_cachedResources[resource][Label] = resource.genericLabel();
 
558
        }
 
559
 
 
560
        m_cachedResources[resource][Description] = resource.description();
 
561
 
 
562
        m_cachedResources[resource][Url] = resource.property(propertyUrl("nie:url")).toString();
 
563
 
 
564
        QStringList types;
 
565
        foreach (const QUrl &u, resource.types()) {
 
566
            types << u.toString();
 
567
        }
 
568
        m_cachedResources[resource][Types] = types;
 
569
 
 
570
        if (!resource.symbols().isEmpty()) {
 
571
            m_cachedResources[resource][Icon] = resource.symbols().first();
 
572
        } else {
 
573
            //if it's an application, fetch the icon from the desktop file
 
574
            Nepomuk::Types::Class resClass(resource.resourceType());
 
575
            if (resClass.label() == "Application") {
 
576
                KService::Ptr serv = KService::serviceByDesktopPath(m_cachedResources[resource][Url].toUrl().path());
 
577
                if (serv) {
 
578
                    m_cachedResources[resource][Icon] = serv->icon();
 
579
                } else {
 
580
                    m_cachedResources[resource][Icon] = KMimeType::iconNameForUrl(m_cachedResources[resource][Url].toString());
 
581
                }
 
582
            } else {
 
583
                m_cachedResources[resource][Icon] = KMimeType::iconNameForUrl(m_cachedResources[resource][Url].toString());
 
584
            }
 
585
        }
 
586
 
 
587
        //those seems to not be possible avoiding to access the resource
 
588
        m_cachedResources[resource][ClassName] = resource.className();
 
589
        m_cachedResources[resource][ResourceType] = resource.resourceType();
 
590
        m_cachedResources[resource][IsFile] = resource.isFile();
 
591
       // m_cachedResources[resource][MimeType] = resource.mimeType();
 
592
        m_cachedResources[resource][MimeType] = resource.property(propertyUrl("nfo:mimeType")).toString();
 
593
 
 
594
        //FIXME: The most complicated of all, this should really be simplified
 
595
        {
 
596
            //FIXME: a more elegant way is needed
 
597
            QString genericClassName = m_cachedResources.value(resource).value(ClassName).toString();
 
598
            //FIXME: most bookmarks are Document too, so Bookmark wins
 
599
            if (m_cachedResources.value(resource).value(Label).value<QList<QUrl> >().contains(NFO::Bookmark())) {
 
600
                m_cachedResources[resource][GenericClassName] = "Bookmark";
 
601
 
 
602
            } else {
 
603
                Nepomuk::Types::Class resClass(resource.resourceType());
 
604
                foreach (const Nepomuk::Types::Class &parentClass, resClass.parentClasses()) {
 
605
                    const QString label = parentClass.label();
 
606
                    if (label == "Document" ||
 
607
                        label == "Audio" ||
 
608
                        label == "Video" ||
 
609
                        label == "Image" ||
 
610
                        label == "Contact") {
 
611
                        genericClassName = label;
 
612
                        break;
 
613
                    //two cases where the class is 2 levels behind the level of generalization we want
 
614
                    } else if (parentClass.label() == "RasterImage") {
 
615
                        genericClassName = "Image";
 
616
                    } else if (parentClass.label() == "TextDocument") {
 
617
                        genericClassName = "Document";
 
618
                    }
 
619
                }
 
620
                m_cachedResources[resource][GenericClassName] = genericClassName;
 
621
            }
 
622
        }
375
623
    }
376
624
 
377
 
    if (!m_newEntriesTimer->isActive()) {
 
625
    if (!m_newEntriesTimer->isActive() && !m_resourcesToInsert[page].isEmpty()) {
378
626
        m_newEntriesTimer->start(200);
379
627
    }
380
628
}
381
629
 
382
630
void MetadataModel::newEntriesDelayed()
383
631
{
384
 
    beginInsertRows(QModelIndex(), m_resources.count(), m_resources.count()+m_resourcesToInsert.count()-1);
385
 
 
386
 
    m_watcher->stop();
387
 
 
388
 
    foreach (Nepomuk::Resource res, m_resourcesToInsert) {
389
 
        //kDebug() << "Result!!!" << res.resource().genericLabel() << res.resource().type();
390
 
        //kDebug() << "Result label:" << res.genericLabel();
391
 
        m_uriToResourceIndex[res.resourceUri()] = m_resources.count();
392
 
        m_resources << res;
393
 
        m_watcher->addResource(res);
394
 
    }
395
 
 
396
 
    m_watcher->start();
397
 
 
 
632
    if (m_resourcesToInsert.isEmpty()) {
 
633
        return;
 
634
    }
 
635
 
 
636
    m_elapsedTime.start();
 
637
    QHash<int, QList<Nepomuk::Resource> >::const_iterator i;
 
638
    for (i = m_resourcesToInsert.constBegin(); i != m_resourcesToInsert.constEnd(); ++i) {
 
639
        const QList<Nepomuk::Resource> resourcesToInsert = i.value();
 
640
 
 
641
        m_watcher->stop();
 
642
 
 
643
        int pageStart = 0;
 
644
        if (m_pageSize > 0) {
 
645
            pageStart = i.key() * m_pageSize;
 
646
        }
 
647
        int startOffset = m_validIndexForPage.value(i.key());
 
648
        int offset = startOffset;
 
649
 
 
650
        //if new result arrive on an already running query, they may arrive before countQueryResult
 
651
        if (m_resources.size() < pageStart + startOffset + 1) {
 
652
            beginInsertRows(QModelIndex(), m_resources.size(), pageStart + startOffset);
 
653
            m_resources.resize(pageStart + startOffset + 1);
 
654
            endInsertRows();
 
655
        }
 
656
        //this happens only when m_validIndexForPage has been invalidate by row removal
 
657
        if (!m_validIndexForPage.contains(i.key()) && m_resources[pageStart + startOffset].isValid()) {
 
658
            while (startOffset < m_resources.size() && m_resources[pageStart + startOffset].isValid()) {
 
659
                ++startOffset;
 
660
                ++offset;
 
661
            }
 
662
        }
 
663
 
 
664
        foreach (const Nepomuk::Resource &res, resourcesToInsert) {
 
665
            //kDebug() << "Result!!!" << res.genericLabel() << res.type();
 
666
            //kDebug() << "Page:" << i.key() << "Index:"<< pageStart + offset;
 
667
 
 
668
            m_uriToResourceIndex[res.resourceUri()] = pageStart + offset;
 
669
            //there can be new results before the count query gets updated
 
670
            if (pageStart + offset < m_resources.size()) {
 
671
                m_resources[pageStart + offset] = res;
 
672
                m_watcher->addResource(res);
 
673
                ++offset;
 
674
            } else {
 
675
                beginInsertRows(QModelIndex(), m_resources.size(), pageStart + offset);
 
676
                m_resources.resize(pageStart + offset + 1);
 
677
                m_resources[pageStart + offset] = res;
 
678
                m_watcher->addResource(res);
 
679
                ++offset;
 
680
                endInsertRows();
 
681
            }
 
682
        }
 
683
 
 
684
        m_validIndexForPage[i.key()] = offset;
 
685
 
 
686
        m_watcher->start();
 
687
        emit dataChanged(createIndex(pageStart + startOffset, 0),
 
688
                         createIndex(pageStart + startOffset + resourcesToInsert.count()-1, 0));
 
689
    }
 
690
    kDebug() << "Elapsed time populating the model" << m_elapsedTime.elapsed();
398
691
    m_resourcesToInsert.clear();
399
 
 
400
 
    endInsertRows();
401
 
    emit countChanged();
402
692
}
403
693
 
404
694
void MetadataModel::propertyChanged(Nepomuk::Resource res, Nepomuk::Types::Property prop, QVariant val)
429
719
        prevIndex = index;
430
720
    }
431
721
 
 
722
    //all the page indexes may be invalid now
 
723
    m_validIndexForPage.clear();
 
724
 
432
725
    QMap<int, int>::const_iterator i = toRemove.constEnd();
433
726
 
434
727
    while (i != toRemove.constBegin()) {
453
746
 
454
747
void MetadataModel::finishedListing()
455
748
{
456
 
    setStatus(Idle);
 
749
    m_runningClients = qMax(m_runningClients - 1, 0);
 
750
 
 
751
    if (m_runningClients <= 0) {
 
752
        setRunning(false);
 
753
 
 
754
        if (m_queryClientsHistory.count() > 10) {
 
755
            for (int i = 0; i < m_queryClientsHistory.count() - 10; ++i) {
 
756
                Nepomuk::Query::QueryServiceClient *client = m_queryClientsHistory.first();
 
757
                m_queryClientsHistory.pop_front();
 
758
 
 
759
                int page = m_pagesForClient.value(client);
 
760
                m_queryClients.remove(page);
 
761
                m_pagesForClient.remove(client);
 
762
                delete client;
 
763
            }
 
764
        }
 
765
    }
457
766
}
458
767
 
459
768
 
467
776
 
468
777
    const Nepomuk::Resource &resource = m_resources[index.row()];
469
778
 
 
779
 
 
780
    if (!resource.isValid() && m_pageSize > 0 && !m_queryClients.contains(floor(index.row()/m_pageSize))) {
 
781
        //HACK
 
782
        const_cast<MetadataModel *>(this)->fetchResultsPage(floor(index.row()/m_pageSize));
 
783
        return QVariant();
 
784
    //m_pageSize <= 0, means fetch all
 
785
    } else if (!resource.isValid() && !m_queryClients.contains(0)) {
 
786
        //HACK
 
787
        const_cast<MetadataModel *>(this)->fetchResultsPage(0);
 
788
        return QVariant();
 
789
    } else if (!resource.isValid()) {
 
790
        return QVariant();
 
791
    }
 
792
 
 
793
    //We're lucky: was cached
 
794
    if (m_cachedResources.value(resource).contains(role)) {
 
795
        return m_cachedResources.value(resource).value(role);
 
796
    }
 
797
 
470
798
    switch (role) {
471
799
    case Qt::DisplayRole:
472
800
    case Label:
473
 
        return resource.genericLabel();
474
 
    case Description:
475
 
        return resource.genericDescription();
476
 
    case Types: {
477
 
        QStringList types;
478
 
        foreach (const QUrl &u, resource.types()) {
479
 
            types << u.toString();
480
 
        }
481
 
        return types;
482
 
    }
483
 
    case ClassName:
484
 
        return resource.className();
485
 
    case GenericClassName: {
486
 
        //FIXME: a more elegant way is needed
487
 
        QString genericClassName = resource.className();
488
 
        //FIXME: most bookmarks are Document too, so Bookmark wins
489
 
        if (resource.types().contains(QUrl::fromEncoded("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Bookmark"))) {
490
 
            return "Bookmark";
491
 
        }
492
 
        Nepomuk::Types::Class resClass(resource.resourceType());
493
 
        foreach (Nepomuk::Types::Class parentClass, resClass.parentClasses()) {
494
 
            if (parentClass.label() == "Document" ||
495
 
                parentClass.label() == "Audio" ||
496
 
                parentClass.label() == "Video" ||
497
 
                parentClass.label() == "Image" ||
498
 
                parentClass.label() == "Contact") {
499
 
                genericClassName = parentClass.label();
500
 
                break;
501
 
            //two cases where the class is 2 levels behind the level of generalization we want
502
 
            } else if (parentClass.label() == "RasterImage") {
503
 
                genericClassName = "Image";
504
 
            } else if (parentClass.label() == "TextDocument") {
505
 
                genericClassName = "Document";
506
 
            }
507
 
        }
508
 
        return genericClassName;
509
 
    }
510
 
    case Qt::DecorationRole: {
511
 
        QString icon = resource.genericIcon();
512
 
        if (icon.isEmpty() && resource.isFile()) {
513
 
            KUrl url = resource.toFile().url();
514
 
            if (!url.isEmpty()) {
515
 
                icon = KMimeType::iconNameForUrl(url);
516
 
            }
517
 
        }
518
 
        if (icon.isEmpty()) {
519
 
            // use resource types to find a suitable icon.
520
 
            //TODO
521
 
            icon = retrieveIconName(QStringList(resource.className()));
522
 
            //kDebug() << "symbol" << icon;
523
 
        }
524
 
        if (icon.split(",").count() > 1) {
525
 
            kDebug() << "More than one icon!" << icon;
526
 
            icon = icon.split(",").last();
527
 
        }
528
 
        return KIcon(icon);
529
 
    }
 
801
        return m_cachedResources.value(resource).value(Label);
 
802
    case Qt::DecorationRole: 
 
803
        return KIcon(m_cachedResources.value(resource).value(Icon).toString());
530
804
    case HasSymbol:
531
 
    case Icon: {
532
 
        QString icon = resource.genericIcon();
533
 
        if (icon.isEmpty() && resource.isFile()) {
534
 
            KUrl url = resource.toFile().url();
535
 
            if (!url.isEmpty()) {
536
 
                icon = KMimeType::iconNameForUrl(url);
537
 
            }
538
 
        }
539
 
        if (icon.isEmpty()) {
540
 
            // use resource types to find a suitable icon.
541
 
            //TODO
542
 
            icon = retrieveIconName(QStringList(resource.className()));
543
 
            //kDebug() << "symbol" << icon;
544
 
        }
545
 
        if (icon.split(",").count() > 1) {
546
 
            kDebug() << "More than one icon!" << icon;
547
 
            icon = icon.split(",").last();
548
 
        }
549
 
        return icon;
550
 
    }
551
 
    case Thumbnail:
552
 
        if (resource.isFile() && resource.toFile().url().isLocalFile()) {
553
 
            KUrl file(resource.toFile().url());
554
 
            QImage preview = QImage(m_screenshotSize, QImage::Format_ARGB32_Premultiplied);
 
805
    case Icon:
 
806
        return m_cachedResources.value(resource).value(Icon).toString();
 
807
    case Thumbnail: {
 
808
        KUrl url(m_cachedResources.value(resource).value(Url).toString());
 
809
        if (m_cachedResources.value(resource).value(IsFile).toBool() && url.isLocalFile()) {
 
810
            QImage preview = QImage(m_thumbnailSize, QImage::Format_ARGB32_Premultiplied);
555
811
 
556
 
            if (m_imageCache->findImage(file.prettyUrl(), &preview)) {
 
812
            if (m_imageCache->findImage(url.prettyUrl(), &preview)) {
557
813
                return preview;
558
814
            }
559
815
 
560
816
            m_previewTimer->start(100);
561
 
            const_cast<MetadataModel *>(this)->m_filesToPreview[file] = QPersistentModelIndex(index);
 
817
            const_cast<MetadataModel *>(this)->m_filesToPreview[url] = QPersistentModelIndex(index);
562
818
        }
563
819
        return QVariant();
564
 
    case IsFile:
565
 
        return resource.isFile();
 
820
    }
566
821
    case Exists:
567
822
        return resource.exists();
568
823
    case Rating:
569
824
        return resource.rating();
570
825
    case NumericRating:
571
 
        return resource.property(QUrl("http://www.semanticdesktop.org/ontologies/2007/08/15/nao#numericRating")).toString();
 
826
        return resource.property(NAO::numericRating()).toString();
572
827
    case Symbols:
573
828
        return resource.symbols();
574
829
    case ResourceUri:
575
830
        return resource.resourceUri();
576
 
    case ResourceType:
577
 
        return resource.resourceType();
578
 
    case MimeType:
579
 
        return resource.property(QUrl("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#mimeType")).toString();
580
 
    case Url: {
581
 
        if (resource.isFile() && resource.toFile().url().isLocalFile()) {
582
 
            return resource.toFile().url().prettyUrl();
583
 
        } else {
584
 
            return resource.property(QUrl("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#url")).toString();
585
 
        }
586
 
    }
587
831
    case Topics: {
588
832
        QStringList topics;
589
833
        foreach (const Nepomuk::Resource &u, resource.topics()) {
617
861
    }
618
862
}
619
863
 
 
864
QVariantHash MetadataModel::get(int row) const
 
865
{
 
866
    QModelIndex idx = index(row, 0);
 
867
    QVariantHash hash;
 
868
 
 
869
    QHash<int, QByteArray>::const_iterator i;
 
870
    for (i = roleNames().constBegin(); i != roleNames().constEnd(); ++i) {
 
871
        hash[i.value()] = data(idx, i.key());
 
872
    }
 
873
 
 
874
    return hash;
 
875
}
620
876
 
621
877
void MetadataModel::delayedPreview()
622
878
{
638
894
    }
639
895
 
640
896
    if (list.size() > 0) {
641
 
        KIO::PreviewJob* job = KIO::filePreview(list, m_screenshotSize);
642
 
        job->setIgnoreMaximumSize(true);
 
897
 
 
898
 
 
899
        KIO::PreviewJob* job = KIO::filePreview(list, m_thumbnailSize, m_thumbnailerPlugins);
 
900
        //job->setIgnoreMaximumSize(true);
643
901
        kDebug() << "Created job" << job;
644
 
        connect(job, SIGNAL(gotPreview(const KFileItem&, const QPixmap&)),
645
 
                this, SLOT(showPreview(const KFileItem&, const QPixmap&)));
646
 
        connect(job, SIGNAL(failed(const KFileItem&)),
647
 
                this, SLOT(previewFailed(const KFileItem&)));
 
902
        connect(job, SIGNAL(gotPreview(KFileItem,QPixmap)),
 
903
                this, SLOT(showPreview(KFileItem,QPixmap)));
 
904
        connect(job, SIGNAL(failed(KFileItem)),
 
905
                this, SLOT(previewFailed(KFileItem)));
648
906
    }
649
907
 
650
908
    m_filesToPreview.clear();
679
937
    endResetModel();
680
938
}
681
939
 
 
940
void MetadataModel::setThumbnailSize(const QSize& size)
 
941
{
 
942
    m_thumbnailSize = size;
 
943
    emit thumbnailSizeChanged();
 
944
}
 
945
 
 
946
QSize MetadataModel::thumbnailSize() const
 
947
{
 
948
    return m_thumbnailSize;
 
949
}
 
950
 
682
951
#include "metadatamodel.moc"