2
Copyright 2011 Marco Martin <notmart@gmail.com>
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
License as published by the Free Software Foundation; either
7
version 2 of the License, or (at your option) any later version.
9
This library 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 GNU
12
Library General Public License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to
16
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
Boston, MA 02110-1301, USA.
20
#include "metadatatimelinemodel.h"
25
#include <KCalendarSystem>
27
#include <soprano/vocabulary.h>
29
#include <Nepomuk/File>
30
#include <Nepomuk/Query/AndTerm>
31
#include <Nepomuk/Query/ResourceTerm>
32
#include <Nepomuk/Tag>
33
#include <Nepomuk/Variant>
34
#include <nepomuk/comparisonterm.h>
35
#include <nepomuk/literalterm.h>
36
#include <nepomuk/queryparser.h>
37
#include <nepomuk/resourcetypeterm.h>
38
#include <nepomuk/standardqueries.h>
40
#include <nepomuk/nfo.h>
41
#include <nepomuk/nie.h>
46
MetadataTimelineModel::MetadataTimelineModel(QObject *parent)
47
: AbstractMetadataModel(parent),
51
QHash<int, QByteArray> roleNames;
52
roleNames[LabelRole] = "label";
53
roleNames[YearRole] = "year";
54
roleNames[MonthRole] = "month";
55
roleNames[DayRole] = "day";
56
roleNames[CountRole] = "count";
57
setRoleNames(roleNames);
61
MetadataTimelineModel::~MetadataTimelineModel()
66
void MetadataTimelineModel::setLevel(MetadataTimelineModel::Level level)
68
if (m_level == level) {
77
MetadataTimelineModel::Level MetadataTimelineModel::level() const
83
QString MetadataTimelineModel::description() const
85
if (m_results.isEmpty()) {
89
//TODO: manage cases where start and enddate cover more than one year/month
92
return i18n("All years");
94
return KGlobal::locale()->calendar()->yearString(startDate(), KCalendarSystem::LongFormat);
97
return i18nc("Month and year, such as March 2007", "%1 %2", KGlobal::locale()->calendar()->monthName(startDate(), KCalendarSystem::LongName), KGlobal::locale()->calendar()->yearString(startDate(), KCalendarSystem::LongFormat));
102
void MetadataTimelineModel::doQuery()
104
QDeclarativePropertyMap *parameters = qobject_cast<QDeclarativePropertyMap *>(extraParameters());
112
if (m_level >= Month) {
113
monthQuery = "bif:month(?label)";
117
if (m_level >= Day) {
118
dayQuery = "bif:dayofmonth(?label)";
123
QString query = QString("select distinct bif:year(?label) as ?year %1 as ?month %2 as ?day count(*) as ?count where { ?r nie:lastModified ?label ").arg(monthQuery).arg(dayQuery);
126
if (!resourceType().isEmpty()) {
127
QString type = resourceType();
128
bool negation = false;
129
if (type.startsWith('!')) {
130
type = type.remove(0, 1);
134
query += " . FILTER(!bif:exists((select (1) where { ?r rdf:type " + type + " . }))) ";
136
query += " . ?r rdf:type " + type;
139
if (type != "nfo:Bookmark") {
140
//FIXME: remove bookmarks if not explicitly asked for
141
query += " . FILTER(!bif:exists((select (1) where { ?r a <http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Bookmark> . }))) ";
145
if (!mimeTypeStrings().isEmpty()) {
148
foreach (QString type, mimeTypeStrings()) {
149
bool negation = false;
154
if (type.startsWith('!')) {
155
type = type.remove(0, 1);
159
query += " { . FILTER(!bif:exists((select (1) where { ?r nie:mimeType \"" + type + "\"^^<http://www.w3.org/2001/XMLSchema#string> . }))) } ";
161
query += " { ?r nie:mimeType \"" + type + "\"^^<http://www.w3.org/2001/XMLSchema#string> . } ";
167
if (parameters && parameters->size() > 0) {
168
foreach (const QString &key, parameters->keys()) {
169
QString parameter = parameters->value(key).toString();
170
bool negation = false;
171
if (parameter.startsWith('!')) {
172
parameter = parameter.remove(0, 1);
177
query += " . FILTER(!bif:exists((select (1) where { ?r " + key + " ?mimeType . FILTER(bif:contains(?mimeType, \"'" + parameter + "'\")) . }))) ";
179
query += " . ?r " + key + " ?mimeType . FILTER(bif:contains(?mimeType, \"'" + parameter + "'\")) ";
184
if (!activityId().isEmpty()) {
185
QString activity = activityId();
186
bool negation = false;
187
if (activity.startsWith('!')) {
188
activity = activity.remove(0, 1);
191
Nepomuk::Resource acRes(activity, Nepomuk::Vocabulary::KAO::Activity());
194
query += ". FILTER(!bif:exists((select (1) where { <" + acRes.resourceUri().toString() + "> <http://www.semanticdesktop.org/ontologies/2007/08/15/nao#isRelated> ?r . }))) ";
196
query += " . <" + acRes.resourceUri().toString() + "> nao:isRelated ?r ";
200
//this is an AND set of tags.. should be allowed OR as well?
201
foreach (const QString &tag, tagStrings()) {
202
QString individualTag = tag;
203
bool negation = false;
205
if (individualTag.startsWith('!')) {
206
individualTag = individualTag.remove(0, 1);
211
query += ". FILTER(!bif:exists((select (1) where { ?r nao:hasTag ?tagSet \
212
. ?tagSet ?tagLabel ?tag \
213
. ?tagLabel <http://www.w3.org/2000/01/rdf-schema#subPropertyOf> <http://www.w3.org/2000/01/rdf-schema#label> \
214
. FILTER(bif:contains(?tag, \"'"+individualTag+"'\"))}))) ";
216
query += ". ?r nao:hasTag ?tagSet \
217
. ?tagSet ?tagLabel ?tag \
218
. ?tagLabel <http://www.w3.org/2000/01/rdf-schema#subPropertyOf> <http://www.w3.org/2000/01/rdf-schema#label> \
219
. FILTER(bif:contains(?tag, \"'"+individualTag+"'\")) ";
223
if (startDate().isValid() || endDate().isValid()) {
224
if (startDate().isValid()) {
225
query += ". ?r <http://www.semanticdesktop.org/ontologies/2007/01/19/nie#lastModified> ?v2 . FILTER(?v2>\"" + startDate().toString(Qt::ISODate) + "\"^^<http://www.w3.org/2001/XMLSchema#dateTime>) ";
227
if (endDate().isValid()) {
228
query += ". ?r <http://www.semanticdesktop.org/ontologies/2007/01/19/nie#lastModified> ?v2 . FILTER(?v2<\"" + endDate().toString(Qt::ISODate) + "\"^^<http://www.w3.org/2001/XMLSchema#dateTime>) ";
232
if (minimumRating() > 0) {
233
query += " . ?r nao:numericRating ?rating filter (?rating >=" + QString::number(minimumRating()) + ") ";
236
if (maximumRating() > 0) {
237
query += " . ?r nao:numericRating ?rating filter (?rating <=" + QString::number(maximumRating()) + ") ";
240
//user visibility is too slow
241
//query += " . FILTER(bif:exists((select (1) where { ?r a [ <http://www.semanticdesktop.org/ontologies/2007/08/15/nao#userVisible> \"true\"^^<http://www.w3.org/2001/XMLSchema#boolean> ] . }))) }";
244
//Group by construction
245
query += " group by bif:year(?label) ";
246
if (m_level >= Month) {
247
query += " bif:month(?label) ";
249
if (m_level >= Day) {
250
query += " bif:dayofmonth(?label) ";
252
query += " order by ?year ?month ?day ";
254
kDebug() << "Performing the Sparql query" << query;
260
emit totalCountChanged();
261
emit descriptionChanged();
264
m_queryClient->close();
266
delete m_queryClient;
267
m_queryClient = new Nepomuk::Query::QueryServiceClient(this);
269
connect(m_queryClient, SIGNAL(newEntries(QList<Nepomuk::Query::Result>)),
270
this, SLOT(newEntries(QList<Nepomuk::Query::Result>)));
271
connect(m_queryClient, SIGNAL(entriesRemoved(QList<QUrl>)),
272
this, SLOT(entriesRemoved(QList<QUrl>)));
273
connect(m_queryClient, SIGNAL(finishedListing()), this, SLOT(finishedListing()));
275
m_queryClient->sparqlQuery(query);
278
void MetadataTimelineModel::newEntries(const QList< Nepomuk::Query::Result > &entries)
280
QVector<QHash<Roles, int> > results;
281
QVariantList categories;
282
foreach (const Nepomuk::Query::Result &res, entries) {
284
int count = res.additionalBinding(QLatin1String("count")).variant().toInt();
285
int year = res.additionalBinding(QLatin1String("year")).variant().toInt();
286
int month = res.additionalBinding(QLatin1String("month")).variant().toInt();
287
int day = res.additionalBinding(QLatin1String("day")).variant().toInt();
289
QHash<Roles, int> resHash;
290
resHash[YearRole] = year;
291
resHash[MonthRole] = month;
292
resHash[DayRole] = day;
293
resHash[CountRole] = count;
295
m_totalCount += count;
299
if (results.count() > 0) {
300
beginInsertRows(QModelIndex(), m_results.count(), m_results.count()+results.count());
301
m_results << results;
302
m_categories << categories;
305
emit totalCountChanged();
306
emit descriptionChanged();
310
void MetadataTimelineModel::entriesRemoved(const QList<QUrl> &urls)
312
//FIXME: we don't have urls here
316
emit totalCountChanged();
319
void MetadataTimelineModel::finishedListing()
326
QVariant MetadataTimelineModel::data(const QModelIndex &index, int role) const
328
if (!index.isValid() || index.column() != 0 ||
329
index.row() < 0 || index.row() >= m_results.count()){
333
const QHash<Roles, int> row = m_results[index.row()];
335
if (role == LabelRole) {
338
return row.value(YearRole);
340
return KGlobal::locale()->calendar()->monthName(row.value(MonthRole), row.value(YearRole), KCalendarSystem::LongName);
343
return row.value(DayRole);
346
return row.value((Roles)role);
349
#include "metadatatimelinemodel.moc"