diff --git a/libs/resources/KisTagsResourcesModel.cpp b/libs/resources/KisTagsResourcesModel.cpp index 2aaac6df68..c1e80b0ed7 100644 --- a/libs/resources/KisTagsResourcesModel.cpp +++ b/libs/resources/KisTagsResourcesModel.cpp @@ -1,311 +1,309 @@ /* * Copyright (c) 2019 Agata Cacko * * 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; either version 2 of the License, or * (at your option) any later version. * * 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 "KisTagsResourcesModel.h" #include #include #include #include #include struct KisTagsResourcesModel::Private { QSqlQuery query; QSqlQuery resourcesForTagQuery; QString resourceType; int columnCount {3}; int cachedRowCount {-1}; }; KisTagsResourcesModel::KisTagsResourcesModel(const QString &resourceType, QObject *parent) : QAbstractTableModel(parent) , d(new Private()) { d->resourceType = resourceType; if (!d->resourceType.isEmpty()) { prepareQueries(); } } KisTagsResourcesModel::~KisTagsResourcesModel() { delete d; } int KisTagsResourcesModel::rowCount(const QModelIndex &parent) const { if (!parent.isValid()) return 0; if (d->cachedRowCount < 0) { QSqlQuery q; q.prepare("SELECT count(*)\n" "FROM resource_tags\n" ", resource_types\n" ", tags\n" "WHERE tags.resource_type_id = resource_types.id\n" "AND resource_types.name = :resource_type\n" "AND tags.id = resource_tags.id\n" "AND tags.storage_id in (SELECT id\n" " FROM storages\n" " WHERE active == 1)"); q.bindValue(":resource_type", d->resourceType); q.exec(); q.first(); const_cast(this)->d->cachedRowCount = q.value(0).toInt(); } return d->cachedRowCount; } int KisTagsResourcesModel::columnCount(const QModelIndex &parent) const { if (!parent.isValid()) return 0; return d->columnCount; } QVariant KisTagsResourcesModel::data(const QModelIndex &index, int role) const { QVariant v; if (!index.isValid()) return v; if (index.row() > rowCount()) return v; if (index.column() > d->columnCount) return v; bool pos = const_cast(this)->d->query.seek(index.row()); if (pos) { switch(role) { case Qt::DisplayRole: return QVariant(d->query.value("id").toString() + ": " + d->query.value("resource_id").toString() + ", " + d->query.value("tag_id").toString()); case Qt::ToolTipRole: // fallthrough case Qt::StatusTipRole: // fallthrough case Qt::WhatsThisRole: return QVariant("Tag/Resource relationship: " + d->query.value("id").toString() + ": " + d->query.value("resource_id").toString() + ", " + d->query.value("tag_id").toString()); case Qt::UserRole + Id: return d->query.value("id"); case Qt::UserRole + ResourceId: return d->query.value("resource_id"); case Qt::UserRole + TagId: return d->query.value("tag_id"); default: ; } } return v; } bool KisTagsResourcesModel::tagResource(const KisTagSP tag, const KoResourceSP resource) { if (!tag) return false; if (!tag->valid()) return false; if (tag->id() < 0) return false; + qDebug() << tag << " tag id " << tag->id(); + if (!resource) return false; if (!resource->valid()) return false; if (resource->resourceId() < 0) return false; QSqlQuery q; bool r = q.prepare("INSERT INTO resource_tags\n" "(resource_id, tag_id)\n" "VALUES\n" "( (SELECT id\n" " FROM resources\n" " WHERE id = :resource_id)\n" ", (SELECT id\n" " FROM tags\n" - " WHERE url = :url\n" - " AND name = :name\n" - " AND comment = :comment\n" + " WHERE id = :tag_id\n" " AND resource_type_id = (SELECT id\n" " FROM resource_types\n" " WHERE name = :resource_type" " \n)" " )\n" ")\n"); if (!r) { qWarning() << "Could not prepare insert into resource tags statement" << q.lastError(); return false; } q.bindValue(":resource_id", resource->resourceId()); - q.bindValue(":url", tag->url()); - q.bindValue(":name", tag->name()); - q.bindValue(":comment", tag->comment()); + q.bindValue(":tag_id", tag->id()); q.bindValue(":resource_type", d->resourceType); if (!q.exec()) { qWarning() << "Could not execute insert into resource tags statement" << q.boundValues() << q.lastError(); return false; } return resetQuery(); } bool KisTagsResourcesModel::untagResource(const KisTagSP tag, const KoResourceSP resource) { if (!tag) return false; if (!tag->valid()) return false; if (!tag->id()) return false; if (!resource) return false; if (!resource->valid()) return false; if (resource->resourceId() < 0) return false; // we need to delete an entry in resource_tags QSqlQuery query; bool r = query.prepare("DELETE FROM resource_tags\n" "WHERE resource_id = :resource_id\n" "AND tag_id = :tag_id"); if (!r) { qWarning() << "Could not prepare KisTagsResourcesModel query" << query.lastError(); } query.bindValue(":resource_id", resource->resourceId()); query.bindValue(":tag_id", tag->id()); r = query.exec(); if (!r) { qWarning() << "Could not select tags" << query.lastError(); } return resetQuery(); } QVector KisTagsResourcesModel::tagsForResource(int resourceId) const { d->query.bindValue(":resource_id", resourceId); bool r = d->query.exec(); if (!r) { qWarning() << "Could not select tags for" << resourceId << d->query.lastError() << d->query.boundValues(); } QVector tags; while (d->query.next()) { //qDebug() << d->tagQuery.value(0).toString() << d->tagQuery.value(1).toString() << d->tagQuery.value(2).toString(); KisTagSP tag(new KisTag()); tag->setId(d->query.value("id").toInt()); tag->setUrl(d->query.value("url").toString()); tag->setName(d->query.value("name").toString()); tag->setComment(d->query.value("comment").toString()); tag->setValid(true); tag->setActive(true); tags << tag; } return tags; } QVector KisTagsResourcesModel::resourcesForTag(int tagId) const { d->resourcesForTagQuery.bindValue(":tag_id", tagId); d->resourcesForTagQuery.bindValue(":resource_type", d->resourceType); bool r = d->resourcesForTagQuery.exec(); if (!r) { qWarning() << "Could not select resources for tag " << tagId << d->resourcesForTagQuery.lastError() << d->resourcesForTagQuery.boundValues(); } QVector resources; qDebug() << "it's around: " << d->resourcesForTagQuery.size() << " resources for " << d->resourceType; while (d->resourcesForTagQuery.next()) { qDebug() << "KisTagsResourcesModel::resourcesForTag(int tagId): ### query: " << d->resourcesForTagQuery.value("id").toInt(); KoResourceSP resource = KisResourceLocator::instance()->resourceForId(d->resourcesForTagQuery.value("id").toInt()); resources << resource; } return resources; } void KisTagsResourcesModel::setResourceType(const QString &resourceType) { d->resourceType = resourceType; prepareQueries(); } bool KisTagsResourcesModel::resetQuery() { // KisTagsResourcesModel doesn't actually keep any data, // *but* the fact that the underlying data changed // is needed when some other components use this model. // Example: KisTagFilterResourcesProxyModel beginResetModel(); endResetModel(); return true; } bool KisTagsResourcesModel::prepareQueries() { bool r = d->query.prepare("SELECT tags.id\n" ", tags.url\n" ", tags.name\n" ", tags.comment\n" "FROM tags\n" ", resource_tags\n" "WHERE tags.active > 0\n" // make sure the tag is active "AND tags.id = resource_tags.tag_id\n" // join tags + resource_tags by tag_id "AND resource_tags.resource_id = :resource_id\n"); // make sure we're looking for tags for a specific resource if (!r) { qWarning() << "Could not prepare TagsForResource query" << d->query.lastError(); } r = d->resourcesForTagQuery.prepare("SELECT DISTINCT resources.id\n" "FROM resources\n" ", resource_tags\n" ", storages\n" ", resource_types\n" "WHERE resources.id = resource_tags.resource_id\n" // join resources + resource_tags by resource_id "AND resources.resource_type_id = resource_types.id\n" // join with resource types via resource type id "AND resources.storage_id = storages.id\n" // join with storages via storage id "AND resource_tags.tag_id = :tag_id\n" // must have the tag "AND resource_types.name = :resource_type\n" // the type must match the current type "AND resources.status = 1\n" // must be active itself "AND storages.active = 1"); // must be from active storage if (!r) { qWarning() << "Could not prepare ResourcesForTag query" << d->resourcesForTagQuery.lastError(); } d->cachedRowCount = -1; resetQuery(); return r; }