Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAllTagResourceModel Class Reference

#include <KisTagResourceModel.h>

+ Inheritance diagram for KisAllTagResourceModel:

Classes

struct  Private
 

Public Types

enum  Columns {
  TagId = KisAbstractResourceModel::BrokenStatusMessage + 1 , ResourceId , Tag , Resource ,
  ResourceActive , TagActive , ResourceStorageActive , ResourceName ,
  TagName
}
 

Public Member Functions

int columnCount (const QModelIndex &parent=QModelIndex()) const override
 
QVariant data (const QModelIndex &index, int role) const override
 Note: only role is significant, column is not.
 
QVariant headerData (int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
 
int isResourceTagged (const KisTagSP tag, const int resourceId) override
 isResourceTagged
 
QHash< int, QByteArray > roleNames () const override
 
int rowCount (const QModelIndex &parent=QModelIndex()) const override
 
bool tagResources (const KisTagSP tag, const QVector< int > &resourceIds) override
 
bool untagResources (const KisTagSP tag, const QVector< int > &resourceId) override
 
 ~KisAllTagResourceModel () override
 
- Public Member Functions inherited from KisAbstractTagResourceModel
virtual ~KisAbstractTagResourceModel ()
 

Private Slots

void addStorage (const QString &location)
 
void removeStorage (const QString &location)
 
void slotResourceActiveStateChanged (const QString &resourceType, int resourceId)
 

Private Member Functions

void closeQuery ()
 
QString createQuery (bool onlyAchieve=true, bool returnADbIndexToo=false)
 
 KisAllTagResourceModel (const QString &resourceType, QObject *parent=0)
 
bool resetQuery ()
 

Private Attributes

Private *const d
 

Friends

class KisResourceModelProvider
 
class KisTagResourceModel
 
class TestTagResourceModel
 

Detailed Description

Definition at line 37 of file KisTagResourceModel.h.

Member Enumeration Documentation

◆ Columns

Constructor & Destructor Documentation

◆ KisAllTagResourceModel()

KisAllTagResourceModel::KisAllTagResourceModel ( const QString & resourceType,
QObject * parent = 0 )
private

TODO: connect to beginExternalResourceImport() and beginExternalResourceRemove as well. It seems to work without them somehow, but I guess it is just a coincidence or UB

Definition at line 30 of file KisTagResourceModel.cpp.

31 : QAbstractTableModel(parent)
32 , d(new Private())
33{
34 d->resourceType = resourceType;
35 resetQuery();
36
37 connect(KisResourceLocator::instance(), SIGNAL(storageAdded(const QString&)), this, SLOT(addStorage(const QString&)));
38 connect(KisResourceLocator::instance(), SIGNAL(storageRemoved(const QString&)), this, SLOT(removeStorage(const QString&)));
39 connect(KisStorageModel::instance(), SIGNAL(storageEnabled(const QString&)), this, SLOT(addStorage(const QString&)));
40 connect(KisStorageModel::instance(), SIGNAL(storageDisabled(const QString&)), this, SLOT(removeStorage(const QString&)));
41 connect(KisResourceLocator::instance(), SIGNAL(resourceActiveStateChanged(const QString&, int)), this, SLOT(slotResourceActiveStateChanged(const QString&, int)));
42
48}
void removeStorage(const QString &location)
void slotResourceActiveStateChanged(const QString &resourceType, int resourceId)
void addStorage(const QString &location)
static KisResourceLocator * instance()
static KisStorageModel * instance()

References addStorage(), d, KisResourceLocator::instance(), KisStorageModel::instance(), removeStorage(), resetQuery(), KisAllTagResourceModel::Private::resourceType, and slotResourceActiveStateChanged().

◆ ~KisAllTagResourceModel()

KisAllTagResourceModel::~KisAllTagResourceModel ( )
override

Definition at line 50 of file KisTagResourceModel.cpp.

51{
52 delete d;
53}

References d.

Member Function Documentation

◆ addStorage

void KisAllTagResourceModel::addStorage ( const QString & location)
privateslot

Definition at line 511 of file KisTagResourceModel.cpp.

512{
513 Q_UNUSED(location);
514 beginInsertRows(QModelIndex(), rowCount(), rowCount());
515 resetQuery();
516 endInsertRows();
517}
int rowCount(const QModelIndex &parent=QModelIndex()) const override

References resetQuery(), and rowCount().

◆ closeQuery()

void KisAllTagResourceModel::closeQuery ( )
private

Definition at line 711 of file KisTagResourceModel.cpp.

712{
713 d->query.clear();
714}

References d, and KisAllTagResourceModel::Private::query.

◆ columnCount()

int KisAllTagResourceModel::columnCount ( const QModelIndex & parent = QModelIndex()) const
override

Definition at line 91 of file KisTagResourceModel.cpp.

92{
93 if (parent.isValid()) {
94 return 0;
95 }
96
97 return d->columnCount;
98}
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:327

References KisAllTagResourceModel::Private::columnCount, and d.

◆ createQuery()

QString KisAllTagResourceModel::createQuery ( bool onlyAchieve = true,
bool returnADbIndexToo = false )
private

Definition at line 552 of file KisTagResourceModel.cpp.

553{
554 QString query = QString("WITH initial_selection AS (\n"
555 " SELECT tags.id\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( // include r_t row id
563 ) + (onlyActive ? QString("") : QString(", resource_tags.active as resource_tags_pair_active\n")) + QString( // include r_t row active info
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( // make sure only active tags are used
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"
577 ")\n"
578 "SELECT \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");
606
607 return query;
608}

◆ data()

QVariant KisAllTagResourceModel::data ( const QModelIndex & index,
int role ) const
override

Note: only role is significant, column is not.

Definition at line 100 of file KisTagResourceModel.cpp.

101{
102 QVariant v;
103
104 if (!index.isValid()) { return v; }
105 if (index.row() > rowCount()) { return v; }
106 if (index.column() > d->columnCount) { return v;}
107
108 bool pos = const_cast<KisAllTagResourceModel*>(this)->d->query.seek(index.row());
109 if (!pos) {return v;}
110
111 if (role < Qt::UserRole + TagId && index.column() < TagId) {
112 return KisResourceQueryMapper::variantFromResourceQuery(d->query, index.column(), role, true);
113 }
114
115 if (role == Qt::FontRole) {
116 return QFont();
117 }
118
119 if (index.column() >= TagId) {
120 // trick to get the correct value without writing everything again
121 // this is used for example in case of sorting
122 role = Qt::UserRole + index.column();
123 }
124
125 // These are not shown, but needed for the filter
126 switch(role) {
127 case Qt::UserRole + TagId:
128 {
129 v = d->query.value("tag_id");
130 break;
131 }
132 case Qt::UserRole + ResourceId:
133 {
134 v = d->query.value("resource_id");
135 break;
136 }
137 case Qt::UserRole + Tag:
138 {
139 KisTagSP tag = KisResourceLocator::instance()->tagForUrl(d->query.value("tag_url").toString(), d->resourceType);
140 v = QVariant::fromValue(tag);
141 break;
142 }
143 case Qt::UserRole + Resource:
144 {
145 v = QVariant::fromValue(KisResourceLocator::instance()->resourceForId(d->query.value("resource_id").toInt()));
146 break;
147 }
148 case Qt::UserRole + ResourceActive:
149 {
150 v = d->query.value("resource_active");
151 break;
152 }
153 case Qt::UserRole + TagActive:
154 {
155 v = d->query.value("tag_active");
156 break;
157 }
158 case Qt::UserRole + ResourceStorageActive:
159 {
160 v = d->query.value("resource_storage_active");
161 break;
162 }
163 case Qt::UserRole + ResourceName:
164 {
165 v = d->query.value("resource_name");
166 break;
167 }
168 case Qt::UserRole + TagName:
169 {
170 v = d->query.value("translated_name");
171 if (v.isNull()) {
172 v = d->query.value("tag_name");
173 }
174 break;
175 }
176
177 default:
178 ;
179 }
180 return v;
181}
qreal v
KisTagSP tagForUrl(const QString &tagUrl, const QString resourceType)
tagForUrl create a tag from the database
static QVariant variantFromResourceQuery(const QSqlQuery &query, int column, int role, bool useResourcePrefix)
variantFromResourceQuery returns a QVariant for the given column and or role

References KisAllTagResourceModel::Private::columnCount, d, KisResourceLocator::instance(), KisAllTagResourceModel::Private::query, Resource, ResourceActive, ResourceId, ResourceName, ResourceStorageActive, KisAllTagResourceModel::Private::resourceType, rowCount(), Tag, TagActive, KisResourceLocator::tagForUrl(), TagId, TagName, v, and KisResourceQueryMapper::variantFromResourceQuery().

◆ headerData()

QVariant KisAllTagResourceModel::headerData ( int section,
Qt::Orientation orientation,
int role = Qt::DisplayRole ) const
override

Definition at line 612 of file KisTagResourceModel.cpp.

613{
614 if (orientation != Qt::Horizontal) {
615 return {};
616 }
617 if (role != Qt::DisplayRole) {
618 return {};
619 }
620
621 switch (section) {
623 return i18n("Id");
625 return i18n("Storage ID");
627 return i18n("Name");
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");
647 return i18n("Tags");
649 return i18n("Large Thumbnail");
651 return i18n("Dirty");
653 return i18n("Metadata");
654 default:
655 role = Qt::UserRole + section;
656 break;
657 }
658
659 switch (role) {
660 case Qt::UserRole + KisAllTagResourceModel::TagId:
661 return i18n("Tag ID");
662 case Qt::UserRole + KisAllTagResourceModel::ResourceId:
663 return i18n("Resource ID");
664 case Qt::UserRole + KisAllTagResourceModel::Tag:
665 return i18n("Tag Url");
666 case Qt::UserRole + KisAllTagResourceModel::Resource:
667 return i18n("Resource");
668 case Qt::UserRole + ResourceActive:
669 return i18n("Resource Active");
670 case Qt::UserRole + TagActive:
671 return i18n("Tag Active");
672 case Qt::UserRole + ResourceStorageActive:
673 return i18n("Storage Active");
674 case Qt::UserRole + ResourceName:
675 return i18n("Resource Name");
676 case Qt::UserRole + TagName:
677 return i18n("Tag File Name");
678 default:
679 break;
680 }
681
682 return {};
683}
@ 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.
@ StorageActive
Whether the current resource's storage is active.

References KisAbstractResourceModel::Dirty, KisAbstractResourceModel::Filename, KisAbstractResourceModel::Id, KisAbstractResourceModel::LargeThumbnail, KisAbstractResourceModel::Location, KisAbstractResourceModel::MD5, KisAbstractResourceModel::MetaData, KisAbstractResourceModel::Name, Resource, KisAbstractResourceModel::ResourceActive, ResourceActive, ResourceId, ResourceName, ResourceStorageActive, KisAbstractResourceModel::ResourceType, KisAbstractResourceModel::Status, KisAbstractResourceModel::StorageActive, KisAbstractResourceModel::StorageId, Tag, TagActive, TagId, TagName, KisAbstractResourceModel::Tags, KisAbstractResourceModel::Thumbnail, and KisAbstractResourceModel::Tooltip.

◆ isResourceTagged()

int KisAllTagResourceModel::isResourceTagged ( const KisTagSP tag,
const int resourceId )
overridevirtual

isResourceTagged

Parameters
tagthe tag to check
resourceIdthe id of the resource to check
Returns
-1 if the resource was never tagged before, 0 if the resource was tagged, but then untagged, 1 if the resource is already tagged

Implements KisAbstractTagResourceModel.

Definition at line 481 of file KisTagResourceModel.cpp.

482{
483 QSqlQuery query;
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");
488
489 if (!r) {
490 qWarning() << "Could not prepare bool KisAllTagResourceModel::checkResourceTaggedState query" << query.lastError();
491 return false;
492 }
493
494 query.bindValue(":resource_id", resourceId);
495 query.bindValue(":tag_id", tag->id());
496
497 if (!query.exec()) {
498 qWarning() << "Could not execute is resource tagged with a specific tag query" << query.boundValues() << query.lastError();
499 return false;
500 }
501
502 r = query.first();
503 if (!r) {
504 // Resource was not tagged
505 return -1;
506 }
507
508 return query.value(0).toInt() > 0;
509}

◆ removeStorage

void KisAllTagResourceModel::removeStorage ( const QString & location)
privateslot

Definition at line 519 of file KisTagResourceModel.cpp.

520{
521 Q_UNUSED(location);
522 beginRemoveRows(QModelIndex(), rowCount(), rowCount());
523 resetQuery();
524 endRemoveRows();
525}

References resetQuery(), and rowCount().

◆ resetQuery()

bool KisAllTagResourceModel::resetQuery ( )
private

Definition at line 716 of file KisTagResourceModel.cpp.

717{
718 bool r = d->query.prepare(createQuery(true));
719
720 if (!r) {
721 qWarning() << "Could not prepare KisAllTagResourcesModel query" << d->query.lastError();
722 }
723
724 d->query.bindValue(":resource_type", d->resourceType);
725 d->query.bindValue(":language", KisTag::currentLocale());
726
727 r = d->query.exec();
728
729 if (!r) {
730 qWarning() << "Could not execute KisAllTagResourcesModel query" << d->query.lastError();
731 }
732
733 d->cachedRowCount = -1;
734
735 return r;
736}
QString createQuery(bool onlyAchieve=true, bool returnADbIndexToo=false)
static QString currentLocale()
Definition KisTag.cpp:84

References KisAllTagResourceModel::Private::cachedRowCount, createQuery(), KisTag::currentLocale(), d, KisAllTagResourceModel::Private::query, and KisAllTagResourceModel::Private::resourceType.

◆ roleNames()

QHash< int, QByteArray > KisAllTagResourceModel::roleNames ( ) const
override

Definition at line 686 of file KisTagResourceModel.cpp.

687{
688 QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
689 roles[Qt::UserRole + KisAbstractResourceModel::Id] = "id";
690 roles[Qt::UserRole + KisAbstractResourceModel::StorageId] = "storageId";
691 roles[Qt::UserRole + KisAbstractResourceModel::Name] = "name";
692 roles[Qt::UserRole + KisAbstractResourceModel::Filename] = "filename";
693 //roles[Qt::UserRole + Tooltip] = "tooltip";
694 roles[Qt::UserRole + KisAbstractResourceModel::Thumbnail] = "thumbnail";
695 roles[Qt::UserRole + KisAbstractResourceModel::Status] = "status";
696 roles[Qt::UserRole + KisAbstractResourceModel::Location] = "location";
697 roles[Qt::UserRole + KisAbstractResourceModel::ResourceType] = "resourcetype";
698 roles[Qt::UserRole + KisAbstractResourceModel::MD5] = "md5";
699 roles[Qt::UserRole + KisAbstractResourceModel::Tags] = "tags";
700 roles[Qt::UserRole + KisAbstractResourceModel::LargeThumbnail] = "largethumbnail";
701 roles[Qt::UserRole + KisAbstractResourceModel::Dirty] = "dirty";
702 roles[Qt::UserRole + KisAbstractResourceModel::MetaData] = "metadata";
703 roles[Qt::UserRole + KisAbstractResourceModel::ResourceActive] = "resourceactive";
704 roles[Qt::UserRole + KisAbstractResourceModel::StorageActive] = "storageactive";
705 roles[Qt::UserRole + KisAbstractResourceModel::BrokenStatus] = "brokenstatus";
706 roles[Qt::UserRole + KisAbstractResourceModel::BrokenStatusMessage] = "brokenstatusmessage";
707
708 return roles;
709}
@ BrokenStatus
Whether the resource is broken (bool)

References KisAbstractResourceModel::BrokenStatus, KisAbstractResourceModel::BrokenStatusMessage, KisAbstractResourceModel::Dirty, KisAbstractResourceModel::Filename, KisAbstractResourceModel::Id, KisAbstractResourceModel::LargeThumbnail, KisAbstractResourceModel::Location, KisAbstractResourceModel::MD5, KisAbstractResourceModel::MetaData, KisAbstractResourceModel::Name, KisAbstractResourceModel::ResourceActive, KisAbstractResourceModel::ResourceType, KisAbstractResourceModel::Status, KisAbstractResourceModel::StorageActive, KisAbstractResourceModel::StorageId, KisAbstractResourceModel::Tags, and KisAbstractResourceModel::Thumbnail.

◆ rowCount()

int KisAllTagResourceModel::rowCount ( const QModelIndex & parent = QModelIndex()) const
override

Definition at line 55 of file KisTagResourceModel.cpp.

56{
57 if (parent.isValid()) {
58 return 0;
59 }
60
61 if (d->cachedRowCount < 0) {
62 QSqlQuery q;
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"
65 ", resources\n"
66 ", resource_types\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");
71
72 if (!r) {
73 qWarning() << "Could not execute resource/tags rowcount query" << q.lastError();
74 return 0;
75 }
76
77 q.bindValue(":resource_type", d->resourceType);
78
79 if (!q.exec()) {
80 qWarning() << "Could not execute resource/tags rowcount query" << q.lastError();
81 return 0;
82 }
83
84 q.first();
85
86 const_cast<KisAllTagResourceModel*>(this)->d->cachedRowCount = q.value(0).toInt();
87 }
88 return d->cachedRowCount;
89}

References KisAllTagResourceModel::Private::cachedRowCount, d, and KisAllTagResourceModel::Private::resourceType.

◆ slotResourceActiveStateChanged

void KisAllTagResourceModel::slotResourceActiveStateChanged ( const QString & resourceType,
int resourceId )
privateslot

The model has multiple rows for every resource, one row per tag, so we need to notify about the changes in all the tags

Definition at line 527 of file KisTagResourceModel.cpp.

528{
529 if (resourceType != d->resourceType) return;
530 if (resourceId < 0) return;
531
532 resetQuery();
533
536 QVector<QModelIndex> indexes;
537
538 for (int i = 0; i < rowCount(); ++i) {
539 const QModelIndex idx = this->index(i, 0);
540 KIS_ASSERT_RECOVER(idx.isValid()) { continue; }
541
542 if (idx.data(Qt::UserRole + KisAllTagResourceModel::ResourceId).toInt() == resourceId) {
543 indexes << idx;
544 }
545 }
546
547 Q_FOREACH(const QModelIndex &index, indexes) {
548 Q_EMIT dataChanged(index, index, {Qt::CheckStateRole, Qt::UserRole + KisAllTagResourceModel::ResourceActive});
549 }
550}
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55

References d, KIS_ASSERT_RECOVER, resetQuery(), ResourceActive, ResourceId, KisAllTagResourceModel::Private::resourceType, and rowCount().

◆ tagResources()

bool KisAllTagResourceModel::tagResources ( const KisTagSP tag,
const QVector< int > & resourceIds )
overridevirtual

Implements KisAbstractTagResourceModel.

Definition at line 183 of file KisTagResourceModel.cpp.

184{
185 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(tag && tag->valid() && tag->id() >= 0, false);
186
187 // notes for performance:
188 // the only two costly parts are:
189 // - executing the query constructed by createQuery()
190 // - running endInsertRows() (because it updates all the views and filter proxies etc...)
191
192 QVector<int> resourceIdsToAdd;
193 QVector<int> resourceIdsToUpdate;
194
195 // looks expensive but actually isn't
196 for (int i = 0; i < resourceIds.count(); i++) {
197 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(resourceIds[i] >= 0, false);
198 int taggedState = isResourceTagged(tag, resourceIds[i]);
199 switch (taggedState) {
200 case -1:
201 // never tagged
202 resourceIdsToAdd.append(resourceIds[i]);
203 break;
204 case 0:
205 // tagged but then untagged
206 resourceIdsToUpdate.append(resourceIds[i]);
207 break;
208 case 1:
209 // it means the resource is already tagged; do nothing
210 break;
211 }
212 }
213
214 if (resourceIdsToAdd.isEmpty() && resourceIdsToUpdate.isEmpty()) {
215 // Is already tagged, let's do nothing
216 return true;
217 }
218
219 int howManyTimesBeginInsertedCalled = 0;
220
221 if (resourceIdsToUpdate.count() > 0) {
222
223 QSqlQuery allIndices;
224 if (!allIndices.prepare(createQuery(false, true))) {
225 qWarning() << "Could not prepare tagResource-allIndices query" << allIndices.lastError();
226 }
227
228 allIndices.bindValue(":resource_type", d->resourceType);
229 allIndices.bindValue(":language", KisTag::currentLocale());
230
231 if (!allIndices.exec()) {
232 qWarning() << "Could not execute tagResource-allIndices query" << allIndices.lastError();
233 }
234
235 int activesRowId = -1;
236 int lastActiveRowId = -1;
237
238 // needed for beginInsertRows calculations
239 QMap<int, int> resourcesCountForLastActiveRowId;
240
241 while (allIndices.next()) {
242 bool isActive = allIndices.value("resource_tags_pair_active").toBool();
243 if (isActive) {
244 activesRowId++;
245 lastActiveRowId = activesRowId;
246 } else {
247 bool variantSuccess = true;
248 int rowTagId = allIndices.value("tag_id").toInt(&variantSuccess);
249 KIS_SAFE_ASSERT_RECOVER(variantSuccess) { rowTagId = -1; }
250 int rowResourceId = allIndices.value("resource_id").toInt(&variantSuccess);
251 KIS_SAFE_ASSERT_RECOVER(variantSuccess) { rowResourceId = -1; }
252 if (rowTagId == tag->id() && resourceIdsToUpdate.contains(rowResourceId)) {
253 if (!resourcesCountForLastActiveRowId.contains(lastActiveRowId)) {
254 resourcesCountForLastActiveRowId[lastActiveRowId] = 1;
255 } else {
256 resourcesCountForLastActiveRowId[lastActiveRowId] = resourcesCountForLastActiveRowId[lastActiveRowId] + 1;
257 }
258 }
259 }
260 }
261
262 Q_FOREACH(const int key, resourcesCountForLastActiveRowId.keys()) {
263 // when having multiple beginInsertRows:
264 // let's say you have this model:
265 // 0 A
266 // 1 A
267 // 2 A
268 // <- put 2 Bs here
269 // 3 A
270 // <- put one B here
271 // 4 A
272 // and you want to add the two Bs and then add another B
273 // then the signals should be:
274 // beginRemoveRows(3, 4) <- new indices of the two Bs
275 // beginRemoveRows(4, 4) <- new index of the one B ignoring the action before
276
277
278 beginInsertRows(QModelIndex(), key + 1, key + resourcesCountForLastActiveRowId[key]);
279 howManyTimesBeginInsertedCalled++;
280 }
281
282 // Resource was tagged, then untagged. Tag again;
283 QSqlQuery q;
284
285 if (!q.prepare("UPDATE resource_tags\n"
286 "SET active = 1\n"
287 "WHERE resource_id = :resource_id\n"
288 "AND tag_id = :tag_id")) {
289
290
291 qWarning() << "Could not prepare update resource_tags to active statement" << q.lastError();
292
293 return false;
294 }
295
296 QVariantList resourceIdsVariants;
297 QVariantList tagIdVariants;
298
299 for (int i = 0; i < resourceIdsToUpdate.count(); i++) {
300 resourceIdsVariants << QVariant(resourceIdsToUpdate[i]);
301 tagIdVariants << QVariant(tag->id());
302 }
303
304 q.bindValue(":resource_id", resourceIdsVariants);
305 q.bindValue(":tag_id", tagIdVariants);
306
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++) {
310 endInsertRows();
311 }
312 return false;
313 }
314
315 }
316
317 if (resourceIdsToAdd.count() > 0) {
318
319 beginInsertRows(QModelIndex(), rowCount(), rowCount() + resourceIdsToAdd.count() - 1);
320 howManyTimesBeginInsertedCalled++;
321
322 // Resource was never tagged before, insert it. The active column is DEFAULT 1
323 QSqlQuery q;
324
325
326 QString values;
327 for (int i = 0; i < resourceIdsToAdd.count(); i++) {
328 if (i > 0) {
329 values.append(", ");
330 }
331 values.append("(?, ?, ?)");
332 }
333
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++) {
339 endInsertRows();
340 }
341 return false;
342 }
343
344 for (int i = 0; i < resourceIdsToAdd.count(); i++) {
345 q.addBindValue(resourceIdsToAdd[i]);
346 q.addBindValue(tag->id());
347 q.addBindValue(true);
348
349 }
350
351 if (!q.exec()) {
352 qWarning() << "Could not execute insert into resource tags statement" << q.boundValues() << q.lastError();
353 for (int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
354 endInsertRows();
355 }
356 return false;
357 }
358 }
359
360 resetQuery();
361
362 for (int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
363 endInsertRows();
364 }
365
366 return true;
367}
int isResourceTagged(const KisTagSP tag, const int resourceId) override
isResourceTagged
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129

References createQuery(), KisTag::currentLocale(), d, isResourceTagged(), KIS_SAFE_ASSERT_RECOVER, KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, resetQuery(), KisAllTagResourceModel::Private::resourceType, and rowCount().

◆ untagResources()

bool KisAllTagResourceModel::untagResources ( const KisTagSP tag,
const QVector< int > & resourceId )
overridevirtual

Implements KisAbstractTagResourceModel.

Definition at line 369 of file KisTagResourceModel.cpp.

370{
371 if (!tag || !tag->valid()) return false;
372 if (!d->query.isSelect()) return false;
373 if (rowCount() < 1) return false;
374
375 int beginRemoveRowsCount = 0;
376
377 QSqlQuery q;
378
379 if (!q.prepare("UPDATE resource_tags\n"
380 "SET active = 0\n"
381 "WHERE tag_id = :tag_id\n"
382 "AND resource_id = :resource_id")) {
383 qWarning() << "Could not prepare untagResource-update query" << q.lastError();
384 return false;
385 }
386
387 QSqlQuery allIndices;
388 if (!allIndices.prepare(createQuery(true, true))) {
389 qWarning() << "Could not prepare untagResource-allIndices query " << allIndices.lastError();
390 }
391
392 allIndices.bindValue(":resource_type", d->resourceType);
393 allIndices.bindValue(":language", KisTag::currentLocale());
394
395 if (!allIndices.exec()) {
396 qCritical() << "Could not exec untagResource-allIndices query " << allIndices.lastError();
397 }
398
399 int activesRowId = -1;
400 int lastActiveRowId = -1;
401
402 // needed for beginInsertRows indices calculations
403 QMap<int, int> resourcesCountForLastActiveRowId;
404
405 while (allIndices.next()) {
406 bool variantSuccess = true;
407
408 bool isActive = true; // all of them are active!
409 KIS_SAFE_ASSERT_RECOVER(variantSuccess) { isActive = false; }
410
411 int rowTagId = allIndices.value("tag_id").toInt(&variantSuccess);
412 KIS_SAFE_ASSERT_RECOVER(variantSuccess) { rowTagId = -1; }
413 int rowResourceId = allIndices.value("resource_id").toInt(&variantSuccess);
414 KIS_SAFE_ASSERT_RECOVER(variantSuccess) { rowResourceId = -1; }
415
416 bool willStayActive = isActive && (rowTagId != tag->id() || !resourceIds.contains(rowResourceId));
417 activesRowId++;
418 if (willStayActive) {
419 lastActiveRowId = activesRowId;
420 } else if (isActive) {
421 // means we're removing it
422 if (!resourcesCountForLastActiveRowId.contains(lastActiveRowId)) {
423 resourcesCountForLastActiveRowId[lastActiveRowId] = 0;
424 }
425 resourcesCountForLastActiveRowId[lastActiveRowId]++;
426 }
427 }
428
429 Q_FOREACH(const int key, resourcesCountForLastActiveRowId.keys()) {
430 // when having multiple beginRemoveRows:
431 // let's say you have this model:
432 // 0 A
433 // 1 A
434 // 2 A
435 // 3 *B*
436 // 4 *B*
437 // 5 A
438 // 6 *B*
439 // 7 A
440 // and you want to remove all Bs
441 // then the signals should be:
442 // beginRemoveRows(3, 4) <- first two indices in the obvious way
443 // beginRemoveRows(4, 4) <- next index as if the first action was already done
444 // (so `5 A` already became `3 A`, so the *B* is `4 B`, not `6 B`)
445
446 beginRemoveRows(QModelIndex(), key + 1, key + resourcesCountForLastActiveRowId[key]);
447 beginRemoveRowsCount++;
448 }
449
450 QSqlDatabase::database().transaction();
451 for (int i = 0; i < resourceIds.count(); i++) {
452 int resourceId = resourceIds[i];
453
454 if (resourceId < 0) continue;
455 if (isResourceTagged(tag, resourceId) < 1) continue;
456
457 q.bindValue(":tag_id", tag->id());
458 q.bindValue(":resource_id", resourceId);
459
460 if (!q.exec()) {
461 qWarning() << "Could not execute untagResource-update query" << q.lastError() << q.boundValues();
462 for (int i = 0; i < beginRemoveRowsCount; i++) {
463 endRemoveRows();
464 }
465 QSqlDatabase::database().rollback();
466 return false;
467 }
468 }
469 QSqlDatabase::database().commit();
470
471 if (beginRemoveRowsCount > 0) {
472 resetQuery();
473 for (int i = 0; i < beginRemoveRowsCount; i++) {
474 endRemoveRows();
475 }
476 }
477
478 return true;
479}

References createQuery(), KisTag::currentLocale(), d, isResourceTagged(), KIS_SAFE_ASSERT_RECOVER, KisAllTagResourceModel::Private::query, resetQuery(), KisAllTagResourceModel::Private::resourceType, and rowCount().

Friends And Related Symbol Documentation

◆ KisResourceModelProvider

friend class KisResourceModelProvider
friend

Definition at line 44 of file KisTagResourceModel.h.

◆ KisTagResourceModel

friend class KisTagResourceModel
friend

Definition at line 46 of file KisTagResourceModel.h.

◆ TestTagResourceModel

friend class TestTagResourceModel
friend

Definition at line 45 of file KisTagResourceModel.h.

Member Data Documentation

◆ d

Private* const KisAllTagResourceModel::d
private

Definition at line 97 of file KisTagResourceModel.h.


The documentation for this class was generated from the following files: