12#include <QSqlDatabase>
31 : QAbstractTableModel(parent)
57 if (parent.isValid()) {
63 const bool r = q.prepare(
"SELECT COUNT(DISTINCT resource_tags.tag_id || resources.name || resources.filename || resources.md5sum)\n"
64 "FROM resource_tags\n"
67 "WHERE resource_tags.resource_id = resources.id\n"
68 "AND resources.resource_type_id = resource_types.id\n"
69 "AND resource_types.name = :resource_type\n"
70 "AND resource_tags.active = 1\n");
73 qWarning() <<
"Could not execute resource/tags rowcount query" << q.lastError();
80 qWarning() <<
"Could not execute resource/tags rowcount query" << q.lastError();
93 if (parent.isValid()) {
104 if (!index.isValid()) {
return v; }
105 if (index.row() >
rowCount()) {
return v; }
109 if (!pos) {
return v;}
111 if (role < Qt::UserRole +
TagId && index.column() <
TagId) {
115 if (role == Qt::FontRole) {
119 if (index.column() >=
TagId) {
122 role = Qt::UserRole + index.column();
127 case Qt::UserRole +
TagId:
134 v =
d->
query.value(
"resource_id");
137 case Qt::UserRole +
Tag:
140 v = QVariant::fromValue(tag);
150 v =
d->
query.value(
"resource_active");
155 v =
d->
query.value(
"tag_active");
160 v =
d->
query.value(
"resource_storage_active");
165 v =
d->
query.value(
"resource_name");
170 v =
d->
query.value(
"translated_name");
172 v =
d->
query.value(
"tag_name");
196 for (
int i = 0; i < resourceIds.count(); i++) {
199 switch (taggedState) {
202 resourceIdsToAdd.append(resourceIds[i]);
206 resourceIdsToUpdate.append(resourceIds[i]);
214 if (resourceIdsToAdd.isEmpty() && resourceIdsToUpdate.isEmpty()) {
219 int howManyTimesBeginInsertedCalled = 0;
221 if (resourceIdsToUpdate.count() > 0) {
223 QSqlQuery allIndices;
224 if (!allIndices.prepare(
createQuery(
false,
true))) {
225 qWarning() <<
"Could not prepare tagResource-allIndices query" << allIndices.lastError();
231 if (!allIndices.exec()) {
232 qWarning() <<
"Could not execute tagResource-allIndices query" << allIndices.lastError();
235 int activesRowId = -1;
236 int lastActiveRowId = -1;
239 QMap<int, int> resourcesCountForLastActiveRowId;
241 while (allIndices.next()) {
242 bool isActive = allIndices.value(
"resource_tags_pair_active").toBool();
245 lastActiveRowId = activesRowId;
247 bool variantSuccess =
true;
248 int rowTagId = allIndices.value(
"tag_id").toInt(&variantSuccess);
250 int rowResourceId = allIndices.value(
"resource_id").toInt(&variantSuccess);
252 if (rowTagId == tag->id() && resourceIdsToUpdate.contains(rowResourceId)) {
253 if (!resourcesCountForLastActiveRowId.contains(lastActiveRowId)) {
254 resourcesCountForLastActiveRowId[lastActiveRowId] = 1;
256 resourcesCountForLastActiveRowId[lastActiveRowId] = resourcesCountForLastActiveRowId[lastActiveRowId] + 1;
262 Q_FOREACH(
const int key, resourcesCountForLastActiveRowId.keys()) {
278 beginInsertRows(QModelIndex(), key + 1, key + resourcesCountForLastActiveRowId[key]);
279 howManyTimesBeginInsertedCalled++;
285 if (!q.prepare(
"UPDATE resource_tags\n"
287 "WHERE resource_id = :resource_id\n"
288 "AND tag_id = :tag_id")) {
291 qWarning() <<
"Could not prepare update resource_tags to active statement" << q.lastError();
296 QVariantList resourceIdsVariants;
297 QVariantList tagIdVariants;
299 for (
int i = 0; i < resourceIdsToUpdate.count(); i++) {
300 resourceIdsVariants << QVariant(resourceIdsToUpdate[i]);
301 tagIdVariants << QVariant(tag->id());
304 q.bindValue(
":resource_id", resourceIdsVariants);
305 q.bindValue(
":tag_id", tagIdVariants);
307 if (!q.execBatch()) {
308 qWarning() <<
"Could not execute update resource_tags to active statement" << q.lastError();
309 for (
int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
317 if (resourceIdsToAdd.count() > 0) {
319 beginInsertRows(QModelIndex(),
rowCount(),
rowCount() + resourceIdsToAdd.count() - 1);
320 howManyTimesBeginInsertedCalled++;
327 for (
int i = 0; i < resourceIdsToAdd.count(); i++) {
331 values.append(
"(?, ?, ?)");
334 if (!q.prepare(QString(
"INSERT INTO resource_tags\n"
335 "(resource_id, tag_id, active)\n"
336 "VALUES ") + values + QString(
";\n"))) {
337 qWarning() <<
"Could not prepare insert into resource tags statement" << q.lastError();
338 for (
int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
344 for (
int i = 0; i < resourceIdsToAdd.count(); i++) {
345 q.addBindValue(resourceIdsToAdd[i]);
346 q.addBindValue(tag->id());
347 q.addBindValue(
true);
352 qWarning() <<
"Could not execute insert into resource tags statement" << q.boundValues() << q.lastError();
353 for (
int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
362 for (
int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
371 if (!tag || !tag->valid())
return false;
372 if (!
d->
query.isSelect())
return false;
375 int beginRemoveRowsCount = 0;
379 if (!q.prepare(
"UPDATE resource_tags\n"
381 "WHERE tag_id = :tag_id\n"
382 "AND resource_id = :resource_id")) {
383 qWarning() <<
"Could not prepare untagResource-update query" << q.lastError();
387 QSqlQuery allIndices;
388 if (!allIndices.prepare(
createQuery(
true,
true))) {
389 qWarning() <<
"Could not prepare untagResource-allIndices query " << allIndices.lastError();
395 if (!allIndices.exec()) {
396 qCritical() <<
"Could not exec untagResource-allIndices query " << allIndices.lastError();
399 int activesRowId = -1;
400 int lastActiveRowId = -1;
403 QMap<int, int> resourcesCountForLastActiveRowId;
405 while (allIndices.next()) {
406 bool variantSuccess =
true;
408 bool isActive =
true;
411 int rowTagId = allIndices.value(
"tag_id").toInt(&variantSuccess);
413 int rowResourceId = allIndices.value(
"resource_id").toInt(&variantSuccess);
416 bool willStayActive = isActive && (rowTagId != tag->id() || !resourceIds.contains(rowResourceId));
418 if (willStayActive) {
419 lastActiveRowId = activesRowId;
420 }
else if (isActive) {
422 if (!resourcesCountForLastActiveRowId.contains(lastActiveRowId)) {
423 resourcesCountForLastActiveRowId[lastActiveRowId] = 0;
425 resourcesCountForLastActiveRowId[lastActiveRowId]++;
429 Q_FOREACH(
const int key, resourcesCountForLastActiveRowId.keys()) {
446 beginRemoveRows(QModelIndex(), key + 1, key + resourcesCountForLastActiveRowId[key]);
447 beginRemoveRowsCount++;
450 QSqlDatabase::database().transaction();
451 for (
int i = 0; i < resourceIds.count(); i++) {
452 int resourceId = resourceIds[i];
454 if (resourceId < 0)
continue;
457 q.bindValue(
":tag_id", tag->id());
458 q.bindValue(
":resource_id", resourceId);
461 qWarning() <<
"Could not execute untagResource-update query" << q.lastError() << q.boundValues();
462 for (
int i = 0; i < beginRemoveRowsCount; i++) {
465 QSqlDatabase::database().rollback();
469 QSqlDatabase::database().commit();
471 if (beginRemoveRowsCount > 0) {
473 for (
int i = 0; i < beginRemoveRowsCount; i++) {
484 bool r = query.prepare(
"SELECT resource_tags.active\n"
485 "FROM resource_tags\n"
486 "WHERE resource_tags.resource_id = :resource_id\n"
487 "AND resource_tags.tag_id = :tag_id\n");
490 qWarning() <<
"Could not prepare bool KisAllTagResourceModel::checkResourceTaggedState query" << query.lastError();
494 query.bindValue(
":resource_id", resourceId);
495 query.bindValue(
":tag_id", tag->id());
498 qWarning() <<
"Could not execute is resource tagged with a specific tag query" << query.boundValues() << query.lastError();
508 return query.value(0).toInt() > 0;
530 if (resourceId < 0)
return;
538 for (
int i = 0; i <
rowCount(); ++i) {
539 const QModelIndex idx = this->index(i, 0);
547 Q_FOREACH(
const QModelIndex &index, indexes) {
554 QString query = QString(
"WITH initial_selection AS (\n"
556 " , resources.name\n"
557 " , resources.filename\n"
558 " , resources.md5sum\n"
559 " , resource_types.id as resource_type_id\n"
560 " , resource_types.name as resource_type_name\n"
561 " , min(resources.id) as resource_id\n"
562 ) + (returnADbIndexToo ? QString(
", resource_tags.id as resource_tags_row_id\n") : QString(
"")) + QString(
563 ) + (onlyActive ? QString(
"") : QString(
", resource_tags.active as resource_tags_pair_active\n")) + QString(
564 " FROM resource_types\n"
565 " JOIN resource_tags\n ON resource_tags.resource_id = resources.id\n"
566 ) + (onlyActive ? QString(
" AND resource_tags.active = 1\n") : QString(
"")) + QString(
567 " JOIN resources ON resources.resource_type_id = resource_types.id\n"
568 " JOIN tags ON tags.id = resource_tags.tag_id\n"
569 " AND tags.resource_type_id = resource_types.id\n"
570 " WHERE resource_types.name = :resource_type\n"
571 " GROUP BY tags.id\n"
572 " , resources.name\n"
573 " , resources.filename\n"
574 " , resources.md5sum\n"
575 " , resource_types.id\n"
576 " ORDER BY resource_tags.id\n"
579 " initial_selection.id as tag_id\n"
580 ", initial_selection.name as resource_name\n"
581 ", initial_selection.filename as resource_filename\n"
582 ", initial_selection.md5sum as resource_md5sum\n"
583 ", initial_selection.resource_id as resource_id\n"
584 ", tags.url as tag_url"
585 ", tags.active as tag_active"
586 ", tags.name as tag_name"
587 ", tags.comment as tag_comment"
588 ", resources.status as resource_active\n"
589 ", resources.tooltip as resource_tooltip\n"
590 ", resources.status as resource_active\n"
591 ", resources.storage_id as storage_id\n"
592 ", storages.active as resource_storage_active\n"
593 ", storages.location as location\n"
594 ", tag_translations.name as translated_name\n"
595 ", tag_translations.comment as translated_comment\n"
596 ", initial_selection.resource_type_name as resource_type\n"
597 ) + (returnADbIndexToo ? QString(
", initial_selection.resource_tags_row_id as resource_tags_row_id\n") : QString(
"")) + QString(
598 ) + (onlyActive ? QString(
"") : QString(
", initial_selection.resource_tags_pair_active as resource_tags_pair_active\n")) + QString(
599 "FROM initial_selection\n"
600 "JOIN tags ON tags.id = initial_selection.id\n"
601 " AND tags.resource_type_id = initial_selection.resource_type_id\n"
602 "JOIN resources ON resources.id = resource_id\n"
603 "JOIN storages ON storages.id = resources.storage_id\n"
604 "LEFT JOIN tag_translations ON tag_translations.tag_id = initial_selection.id\n"
605 " AND tag_translations.language = :language\n");
614 if (orientation != Qt::Horizontal) {
617 if (role != Qt::DisplayRole) {
625 return i18n(
"Storage ID");
629 return i18n(
"File Name");
631 return i18n(
"Tooltip");
633 return i18n(
"Image");
635 return i18n(
"Status");
637 return i18n(
"Location");
639 return i18n(
"Resource Type");
641 return i18n(
"Active");
643 return i18n(
"Storage Active");
645 return i18n(
"md5sum");
649 return i18n(
"Large Thumbnail");
651 return i18n(
"Dirty");
653 return i18n(
"Metadata");
655 role = Qt::UserRole + section;
661 return i18n(
"Tag ID");
663 return i18n(
"Resource ID");
665 return i18n(
"Tag Url");
667 return i18n(
"Resource");
669 return i18n(
"Resource Active");
671 return i18n(
"Tag Active");
673 return i18n(
"Storage Active");
675 return i18n(
"Resource Name");
677 return i18n(
"Tag File Name");
688 QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
721 qWarning() <<
"Could not prepare KisAllTagResourcesModel query" <<
d->
query.lastError();
730 qWarning() <<
"Could not execute KisAllTagResourcesModel query" <<
d->
query.lastError();
751 : QSortFilterProxyModel(parent)
818 Q_FOREACH(
const KisTagSP tag, tags) {
819 if (tag && tag->valid() && tag->id() > -1) {
830 if (resource->valid() && resource->resourceId() > -1) {
839 QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
840 if (!idx.isValid())
return false;
876 return nameLeft.toLower() < nameRight.toLower();
888 if (
id < 1)
return nullptr;
895 if (!resource || !resource->valid() || resource->resourceId() < 0)
return QModelIndex();
897 for (
int i = 0; i < rowCount(); ++i) {
899 Q_ASSERT(idx.isValid());
904 return QModelIndex();
909 if (resourceId < 0)
return QModelIndex();
910 for (
int i = 0; i < rowCount(); ++i) {
912 Q_ASSERT(idx.isValid());
917 return QModelIndex();
940 return resourceModel.
importResource(filename, device, allowOverwrite, storageId);
960 return resourceModel.
addResource(resource, storageId);
978 if (index.isValid()) {
979 Q_EMIT dataChanged(index, index, {Qt::EditRole});
991 if (index.isValid()) {
992 Q_EMIT dataChanged(index, index, {Qt::EditRole});
1004 if (index.isValid()) {
1005 Q_EMIT dataChanged(index, index, {Qt::EditRole});
1019 if (sourceModel()) {
1020 return sourceModel()->roleNames();
1022 return QAbstractItemModel::roleNames();
float value(const T *src, size_t ch)
@ Status
Whether the resource is active. Duplicate of ResourceActive.
@ ResourceActive
Whether the current resource is active.
@ Dirty
A dirty resource is one that has been modified locally but not saved.
@ LargeThumbnail
A larger thumbnail for displaying in a tooltip. 200x200 or so.
@ MetaData
MetaData is a map of key, value pairs that is associated with this resource.
@ BrokenStatus
Whether the resource is broken (bool)
@ StorageActive
Whether the current resource's storage is active.
KisAllTagResourceModel(const QString &resourceType, QObject *parent=0)
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
void removeStorage(const QString &location)
QHash< int, QByteArray > roleNames() const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
int isResourceTagged(const KisTagSP tag, const int resourceId) override
isResourceTagged
void slotResourceActiveStateChanged(const QString &resourceType, int resourceId)
int columnCount(const QModelIndex &parent=QModelIndex()) const override
~KisAllTagResourceModel() override
void addStorage(const QString &location)
QString createQuery(bool onlyAchieve=true, bool returnADbIndexToo=false)
bool tagResources(const KisTagSP tag, const QVector< int > &resourceIds) override
bool untagResources(const KisTagSP tag, const QVector< int > &resourceId) override
QVariant data(const QModelIndex &index, int role) const override
Note: only role is significant, column is not.
KisTagSP tagForUrl(const QString &tagUrl, const QString resourceType)
tagForUrl create a tag from the database
KoResourceSP resourceForId(int resourceId)
resourceForId returns the resource with the given id, or 0 if no such resource exists....
static KisResourceLocator * instance()
static KisAllTagResourceModel * tagResourceModel(const QString &resourceType)
The KisResourceModel class provides the main access to resources. It is possible to filter the resour...
bool setResourceMetaData(KoResourceSP resource, QMap< QString, QVariant > metadata) override
setResourceMetaData
KoResourceSP importResourceFile(const QString &filename, const bool allowOverwrite, const QString &storageId=QString("")) override
importResourceFile
bool importWillOverwriteResource(const QString &fileName, const QString &storageLocation=QString()) const override
importWillOverwriteResource checks is importing a resource with this filename will overwrite anything
bool reloadResource(KoResourceSP resource) override
reloadResource
bool renameResource(KoResourceSP resource, const QString &name) override
renameResource name the given resource. The resource will have its name field reset,...
bool addResourceDeduplicateFileName(KoResourceSP resource, const QString &storageId=QString("")) override
addResource adds the given resource to the database and storage. If the resource already exists in th...
bool exportResource(KoResourceSP resource, QIODevice *device) override
exportResource exports a resource into a QIODevice
bool updateResource(KoResourceSP resource) override
updateResource creates a new version of the resource in the storage and in the database....
bool addResource(KoResourceSP resource, const QString &storageId=QString("")) override
addResource adds the given resource to the database and storage. If the resource already exists in th...
QModelIndex indexForResource(KoResourceSP resource) const override
indexFromResource
bool setResourceActive(const QModelIndex &index, bool value) override
setResourceActive changes 'active' state of the resource
KoResourceSP importResource(const QString &filename, QIODevice *device, const bool allowOverwrite, const QString &storageId=QString("")) override
importResource imports a resource from a QIODevice
static QVariant variantFromResourceQuery(const QSqlQuery &query, int column, int role, bool useResourcePrefix)
variantFromResourceQuery returns a QVariant for the given column and or role
static KisStorageModel * instance()
bool setResourceMetaData(KoResourceSP resource, QMap< QString, QVariant > metadata) override
setResourceMetaData
void setResourceFilter(ResourceFilter filter) override
QModelIndex indexForResourceId(int resourceId) const override
indexFromResource
bool untagResources(const KisTagSP tag, const QVector< int > &resourceIds) override
bool setResourceActive(const QModelIndex &index, bool value) override
setResourceActive changes 'active' state of the resource
KoResourceSP importResource(const QString &filename, QIODevice *device, const bool allowOverwrite, const QString &storageId=QString()) override
importResource imports a resource from a QIODevice
bool addResource(KoResourceSP resource, const QString &storageId) override
addResource adds the given resource to the database and storage. If the resource already exists in th...
void storageChanged(const QString &location)
void setTagFilter(TagFilter filter)
bool addResourceDeduplicateFileName(KoResourceSP resource, const QString &storageId) override
addResource adds the given resource to the database and storage. If the resource already exists in th...
~KisTagResourceModel() override
KisTagResourceModel(const QString &resourceType, QObject *parent=0)
bool tagResources(const KisTagSP tag, const QVector< int > &resourceIds) override
void setTagsFilter(const QVector< int > tagIds)
QModelIndex indexForResource(KoResourceSP resource) const override
indexFromResource
void setResourcesFilter(const QVector< int > resourceIds)
bool renameResource(KoResourceSP resource, const QString &name) override
renameResource name the given resource. The resource will have its name field reset,...
KoResourceSP importResourceFile(const QString &filename, const bool allowOverwrite, const QString &storageId=QString()) override
importResourceFile
bool reloadResource(KoResourceSP resource) override
reloadResource
int isResourceTagged(const KisTagSP tag, const int resourceId) override
isResourceTagged
bool updateResource(KoResourceSP resource) override
updateResource creates a new version of the resource in the storage and in the database....
QHash< int, QByteArray > roleNames() const override
bool importWillOverwriteResource(const QString &fileName, const QString &storageLocation) const override
importWillOverwriteResource checks is importing a resource with this filename will overwrite anything
KoResourceSP resourceForIndex(QModelIndex index) const override
resourceForIndex returns a properly versioned and id'ed resource object
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
bool exportResource(KoResourceSP resource, QIODevice *device) override
exportResource exports a resource into a QIODevice
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
void setStorageFilter(StorageFilter filter) override
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override
static QString currentLocale()
#define KIS_ASSERT_RECOVER(cond)
#define KIS_SAFE_ASSERT_RECOVER(cond)
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
StorageFilter storageFilter
QVector< int > resourceIds
ResourceFilter resourceFilter
KisAllTagResourceModel * sourceModel