From 8e8bcdd599a5273d7873f58b827d4b6b525993de Mon Sep 17 00:00:00 2001 From: Damien Caliste Date: Thu, 11 Feb 2016 22:20:50 +0100 Subject: [PATCH] [office] Use Tracker as a tag provider. --- CMakeLists.txt | 1 + models/documentlistmodel.cpp | 42 ++++++--- models/documentlistmodel.h | 4 +- models/trackertagprovider.cpp | 159 ++++++++++++++++++++++++++++++++++ models/trackertagprovider.h | 53 ++++++++++++ 5 files changed, 246 insertions(+), 13 deletions(-) create mode 100644 models/trackertagprovider.cpp create mode 100644 models/trackertagprovider.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 840d1b5d..dfc18437 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ set(sailfishoffice_SRCS dbusadaptor.cpp models/filtermodel.cpp models/tagsthread.cpp + models/trackertagprovider.cpp models/taglistmodel.cpp models/documentlistmodel.cpp models/documentproviderlistmodel.cpp diff --git a/models/documentlistmodel.cpp b/models/documentlistmodel.cpp index f2dea67d..988c321a 100644 --- a/models/documentlistmodel.cpp +++ b/models/documentlistmodel.cpp @@ -49,6 +49,7 @@ class DocumentListModel::Private QList entries; QHash roles; TagsThread *tagsThread; // To delegate tag storage with SQL backend. + TrackerTagProvider trackerTag; TagListModel tagsModel; // A QML list of all tags. QHash> tags; // The association tag <-> [set of filenames] }; @@ -56,13 +57,16 @@ class DocumentListModel::Private DocumentListModel::DocumentListModel(QObject *parent) : QAbstractListModel(parent), d(new Private) { - d->tagsThread = new TagsThread( this ); - connect( d->tagsThread, &TagsThread::jobFinished, this, &DocumentListModel::jobFinished ); + // d->tagsThread = new TagsThread(this); + // connect(d->tagsThread, &TagsThread::jobFinished, + // this, &DocumentListModel::jobFinished); + connect(&d->trackerTag, &TrackerTagProvider::tagLoaded, + this, &DocumentListModel::tagLoaded); } DocumentListModel::~DocumentListModel() { - delete d->tagsThread; + // delete d->tagsThread; } QVariant DocumentListModel::data(const QModelIndex &index, int role) const @@ -121,9 +125,10 @@ void DocumentListModel::addTag(const QString &path, const QString &tag) return; // This path has already this tag. files.insert(path); - TagsThreadJob *job = new TagsThreadJob(path, TagsThreadJob::TaskAddTags); - job->tags.append(tag); - d->tagsThread->queueJob(job); + // TagsThreadJob *job = new TagsThreadJob(path, TagsThreadJob::TaskAddTags); + // job->tags.append(tag); + // d->tagsThread->queueJob(job); + d->trackerTag.addTag(path, tag); d->tagsModel.addItem(tag); notifyForPath(path); } @@ -136,9 +141,10 @@ void DocumentListModel::removeTag(const QString &path, const QString &tag) files.remove(path); if (files.empty()) d->tags.remove(tag); - TagsThreadJob *job = new TagsThreadJob(path, TagsThreadJob::TaskRemoveTags); - job->tags.append(tag); - d->tagsThread->queueJob(job); + // TagsThreadJob *job = new TagsThreadJob(path, TagsThreadJob::TaskRemoveTags); + // job->tags.append(tag); + // d->tagsThread->queueJob(job); + d->trackerTag.removeTag(path, tag); d->tagsModel.removeItem(tag); notifyForPath(path); } @@ -191,7 +197,8 @@ void DocumentListModel::addItem(QString name, QString path, QString type, int si entry.fileRead = lastRead; entry.mimeType = mimeType; entry.documentClass = static_cast(mimeTypeToDocumentClass(mimeType)); - d->tagsThread->queueJob(new TagsThreadJob(path, TagsThreadJob::TaskLoadTags)); + d->trackerTag.loadTags(path); + //d->tagsThread->queueJob(new TagsThreadJob(path, TagsThreadJob::TaskLoadTags)); int index = 0; for (; index < d->entries.count(); ++index) { @@ -217,7 +224,7 @@ void DocumentListModel::removeItemsDirty() void DocumentListModel::removeAt(int index) { if (index > -1 && index < d->entries.count()) { - d->tagsThread->cancelJobsForPath(d->entries.at(index).filePath); + // d->tagsThread->cancelJobsForPath(d->entries.at(index).filePath); beginRemoveRows(QModelIndex(), index, index); d->entries.removeAt(index); endRemoveRows(); @@ -226,7 +233,7 @@ void DocumentListModel::removeAt(int index) void DocumentListModel::clear() { - d->tagsThread->cancelAllJobs(); + // d->tagsThread->cancelAllJobs(); beginResetModel(); d->entries.clear(); endResetModel(); @@ -246,6 +253,17 @@ void DocumentListModel::jobFinished(TagsThreadJob *job) job->deleteLater(); } +void DocumentListModel::tagLoaded(const QString &path, const QList &tags) +{ + for (QList::const_iterator tag = tags.begin(); + tag != tags.end(); tag++) { + QSet &files = d->tags[*tag]; + files.insert(path); + d->tagsModel.addItem(*tag); + } + notifyForPath(path); +} + int DocumentListModel::mimeTypeToDocumentClass(QString mimeType) const { DocumentClass documentClass = UnknownDocument; diff --git a/models/documentlistmodel.h b/models/documentlistmodel.h index 70c5d7ef..31f59a29 100644 --- a/models/documentlistmodel.h +++ b/models/documentlistmodel.h @@ -23,6 +23,7 @@ #include #include "tagsthread.h" +#include "trackertagprovider.h" #include "taglistmodel.h" class DocumentListModelPrivate; @@ -76,8 +77,9 @@ class DocumentListModel : public QAbstractListModel Q_INVOKABLE void addTag(const QString &path, const QString &tag); Q_INVOKABLE void removeTag(const QString &path, const QString &tag); -public Q_SLOTS: +private Q_SLOTS: void jobFinished(TagsThreadJob* job); + void tagLoaded(const QString &path, const QList &tags); Q_SIGNALS: void tagsChanged(); diff --git a/models/trackertagprovider.cpp b/models/trackertagprovider.cpp new file mode 100644 index 00000000..82596867 --- /dev/null +++ b/models/trackertagprovider.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2016 Damien Caliste + * Contact: Damien Caliste + * + * 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 the Free Software Foundation; version 2 only. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "trackertagprovider.h" + +#include +#include +#include + +//The Tracker driver to use. +static const QString trackerDriver{"QTRACKER"}; + +class TrackerTagProvider::Private { +public: + Private() + : connection(new QSparqlConnection(trackerDriver)) + { + } + + ~Private() { + delete connection; + } + + QSparqlConnection *connection; +}; + +TrackerTagProvider::TrackerTagProvider(QObject *parent) + : QObject(parent) + , d(new Private()) +{ +} + +TrackerTagProvider::~TrackerTagProvider() +{ + delete d; +} + +void TrackerTagProvider::loadTags(const QString &path) +{ + QSparqlQuery q(QString("SELECT ?label WHERE {" + " ?f nie:isStoredAs ?p ; nao:hasTag ?tag ." + " ?p nie:url '%1' ." + " ?tag a nao:Tag ; nao:prefLabel ?label ." + "} ORDER BY ASC(?label)").arg(QString(path).replace('\'', "\\\'"))); + QSparqlResult* result = d->connection->exec(q); + result->setProperty("path", QVariant(path)); + connect(result, &QSparqlResult::finished, this, &TrackerTagProvider::loadTagFinished); +} + +void TrackerTagProvider::addTag(const QString &path, const QString &tag) +{ + // First, check if tag exists. + QSparqlQuery q(QString("SELECT ?tag WHERE {" + " ?tag a nao:Tag ; nao:prefLabel '%1' ." + "} ORDER BY ASC(?label)").arg(QString(tag).replace('\'', "\\\'"))); + QSparqlResult* result = d->connection->exec(q); + result->setProperty("path", QVariant(path)); + result->setProperty("tag", QVariant(tag)); + connect(result, &QSparqlResult::finished, this, &TrackerTagProvider::existTagFinished); +} + +void TrackerTagProvider::addExistingTag(const QString &path, const QString &tag) +{ + QSparqlQuery q(QString("INSERT {" + " ?f nao:hasTag ?tag" + "} WHERE {" + " ?f nie:isStoredAs ?p ." + " ?p nie:url '%1' ." + " ?tag nao:prefLabel '%2'" + "}").arg(QString(path).replace('\'', "\\\'")).arg(QString(tag).replace('\'', "\\\'")), QSparqlQuery::InsertStatement); + QSparqlResult* result = d->connection->exec(q); + connect(result, &QSparqlResult::finished, this, &TrackerTagProvider::addTagFinished); +} + +void TrackerTagProvider::addNewTag(const QString &path, const QString &tag) +{ + QSparqlQuery q(QString("INSERT {" + " _:tag a nao:Tag ; nao:prefLabel '%2' ." + " ?f nao:hasTag _:tag" + "} WHERE {" + " ?f nie:isStoredAs ?p ." + " ?p nie:url '%1' ." + "}").arg(QString(path).replace('\'', "\\\'")).arg(QString(tag).replace('\'', "\\\'")), QSparqlQuery::InsertStatement); + QSparqlResult* result = d->connection->exec(q); + connect(result, &QSparqlResult::finished, this, &TrackerTagProvider::addTagFinished); +} + +void TrackerTagProvider::removeTag(const QString &path, const QString &tag) +{ + QSparqlQuery q(QString("DELETE {" + " ?f nao:hasTag ?tag" + "} WHERE {" + " ?f nie:isStoredAs ?p ." + " ?p nie:url '%1' ." + " ?tag nao:prefLabel '%2' ." + "}").arg(QString(path).replace('\'', "\\\'")).arg(QString(tag).replace('\'', "\\\'")), QSparqlQuery::DeleteStatement); + QSparqlResult* result = d->connection->exec(q); + connect(result, &QSparqlResult::finished, this, &TrackerTagProvider::removeTagFinished); +} + +void TrackerTagProvider::loadTagFinished() +{ + QSparqlResult *r = qobject_cast(sender()); + QList tags; + + if (!r->hasError()) { + while (r->next()) { + tags.append(r->binding(0).value().toString()); + } + + emit tagLoaded(r->property("path").toString(), tags); + } + + r->deleteLater(); +} + +void TrackerTagProvider::existTagFinished() +{ + QSparqlResult *r = qobject_cast(sender()); + + if (!r->hasError()) { + if (r->next()) { + addExistingTag(r->property("path").toString(), r->property("tag").toString()); + } else { + addNewTag(r->property("path").toString(), r->property("tag").toString()); + } + } + + r->deleteLater(); +} + +void TrackerTagProvider::addTagFinished() +{ + QSparqlResult *r = qobject_cast(sender()); + + r->deleteLater(); +} + +void TrackerTagProvider::removeTagFinished() +{ + QSparqlResult *r = qobject_cast(sender()); + + r->deleteLater(); +} diff --git a/models/trackertagprovider.h b/models/trackertagprovider.h new file mode 100644 index 00000000..9148309f --- /dev/null +++ b/models/trackertagprovider.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 Damien Caliste + * Contact: Damien Caliste + * + * 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 the Free Software Foundation; version 2 only. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TRACKERTAGPROVIDER_H +#define TRACKERTAGPROVIDER_H + +#include + +class TrackerTagProvider : public QObject +{ + Q_OBJECT + +public: + TrackerTagProvider(QObject *parent = 0); + ~TrackerTagProvider(); + + void loadTags(const QString &path); + void addTag(const QString &path, const QString &tag); + void removeTag(const QString &path, const QString &tag); + +signals: + void tagLoaded(const QString &path, const QList &tags); + +private Q_SLOTS: + void loadTagFinished(); + void existTagFinished(); + void addTagFinished(); + void removeTagFinished(); + +private: + class Private; + Private *d; + + void addNewTag(const QString &path, const QString &tag); + void addExistingTag(const QString &path, const QString &tag); +}; + +#endif