Skip to content

Commit

Permalink
[office] Use Tracker as a tag provider.
Browse files Browse the repository at this point in the history
  • Loading branch information
dcaliste committed Feb 23, 2016
1 parent 924013e commit 201db9e
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 13 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
42 changes: 30 additions & 12 deletions models/documentlistmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,24 @@ class DocumentListModel::Private
QList<DocumentListModelEntry> entries;
QHash<int, QByteArray> roles;
TagsThread *tagsThread; // To delegate tag storage with SQL backend.
TrackerTagProvider trackerTag;
TagListModel tagsModel; // A QML list of all tags.
QHash<QString, QSet<QString>> tags; // The association tag <-> [set of filenames]
};

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
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand Down Expand Up @@ -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<DocumentClass>(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) {
Expand All @@ -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();
Expand All @@ -226,7 +233,7 @@ void DocumentListModel::removeAt(int index)

void DocumentListModel::clear()
{
d->tagsThread->cancelAllJobs();
// d->tagsThread->cancelAllJobs();
beginResetModel();
d->entries.clear();
endResetModel();
Expand All @@ -246,6 +253,17 @@ void DocumentListModel::jobFinished(TagsThreadJob *job)
job->deleteLater();
}

void DocumentListModel::tagLoaded(const QString &path, const QList<QString> &tags)
{
for (QList<QString>::const_iterator tag = tags.begin();
tag != tags.end(); tag++) {
QSet<QString> &files = d->tags[*tag];
files.insert(path);
d->tagsModel.addItem(*tag);
}
notifyForPath(path);
}

int DocumentListModel::mimeTypeToDocumentClass(QString mimeType) const
{
DocumentClass documentClass = UnknownDocument;
Expand Down
4 changes: 3 additions & 1 deletion models/documentlistmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <qdatetime.h>

#include "tagsthread.h"
#include "trackertagprovider.h"
#include "taglistmodel.h"

class DocumentListModelPrivate;
Expand Down Expand Up @@ -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<QString> &tags);

Q_SIGNALS:
void tagsChanged();
Expand Down
159 changes: 159 additions & 0 deletions models/trackertagprovider.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* Copyright (C) 2016 Damien Caliste
* Contact: Damien Caliste <[email protected]>
*
* 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 <QSparqlConnection>
#include <QSparqlResult>
#include <QSparqlError>

//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<QSparqlResult*>(sender());
QList<QString> 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<QSparqlResult*>(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<QSparqlResult*>(sender());

r->deleteLater();
}

void TrackerTagProvider::removeTagFinished()
{
QSparqlResult *r = qobject_cast<QSparqlResult*>(sender());

r->deleteLater();
}
53 changes: 53 additions & 0 deletions models/trackertagprovider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (C) 2016 Damien Caliste
* Contact: Damien Caliste <[email protected]>
*
* 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 <QtCore/QObject>

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<QString> &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

0 comments on commit 201db9e

Please sign in to comment.