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
 
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}
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
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(), connect(), 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 517 of file KisTagResourceModel.cpp.

518{
519 Q_UNUSED(location);
520 beginInsertRows(QModelIndex(), rowCount(), rowCount());
521 resetQuery();
522 endInsertRows();
523}
int rowCount(const QModelIndex &parent=QModelIndex()) const override

References resetQuery(), and rowCount().

◆ closeQuery()

void KisAllTagResourceModel::closeQuery ( )
private

Definition at line 691 of file KisTagResourceModel.cpp.

692{
693 d->query.clear();
694}

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 558 of file KisTagResourceModel.cpp.

559{
560 QString query = QString("WITH initial_selection AS (\n"
561 " SELECT tags.id\n"
562 " , resources.name\n"
563 " , resources.filename\n"
564 " , resources.md5sum\n"
565 " , resource_types.id as resource_type_id\n"
566 " , resource_types.name as resource_type_name\n"
567 " , min(resources.id) as resource_id\n"
568 ) + (returnADbIndexToo ? QString(", resource_tags.id as resource_tags_row_id\n") : QString("")) + QString( // include r_t row id
569 ) + (onlyActive ? QString("") : QString(", resource_tags.active as resource_tags_pair_active\n")) + QString( // include r_t row active info
570 " FROM resource_types\n"
571 " JOIN resource_tags\n ON resource_tags.resource_id = resources.id\n"
572 ) + (onlyActive ? QString(" AND resource_tags.active = 1\n") : QString("")) + QString( // make sure only active tags are used
573 " JOIN resources ON resources.resource_type_id = resource_types.id\n"
574 " JOIN tags ON tags.id = resource_tags.tag_id\n"
575 " AND tags.resource_type_id = resource_types.id\n"
576 " WHERE resource_types.name = :resource_type\n"
577 " GROUP BY tags.id\n"
578 " , resources.name\n"
579 " , resources.filename\n"
580 " , resources.md5sum\n"
581 " , resource_types.id\n"
582 " ORDER BY resource_tags.id\n"
583 ")\n"
584 "SELECT \n"
585 " initial_selection.id as tag_id\n"
586 ", initial_selection.name as resource_name\n"
587 ", initial_selection.filename as resource_filename\n"
588 ", initial_selection.md5sum as resource_md5sum\n"
589 ", initial_selection.resource_id as resource_id\n"
590 ", tags.url as tag_url"
591 ", tags.active as tag_active"
592 ", tags.name as tag_name"
593 ", tags.comment as tag_comment"
594 ", resources.status as resource_active\n"
595 ", resources.tooltip as resource_tooltip\n"
596 ", resources.status as resource_active\n"
597 ", resources.storage_id as storage_id\n"
598 ", storages.active as resource_storage_active\n"
599 ", storages.location as location\n"
600 ", tag_translations.name as translated_name\n"
601 ", tag_translations.comment as translated_comment\n"
602 ", initial_selection.resource_type_name as resource_type\n"
603 ) + (returnADbIndexToo ? QString(", initial_selection.resource_tags_row_id as resource_tags_row_id\n") : QString("")) + QString(
604 ) + (onlyActive ? QString("") : QString(", initial_selection.resource_tags_pair_active as resource_tags_pair_active\n")) + QString(
605 "FROM initial_selection\n"
606 "JOIN tags ON tags.id = initial_selection.id\n"
607 " AND tags.resource_type_id = initial_selection.resource_type_id\n"
608 "JOIN resources ON resources.id = resource_id\n"
609 "JOIN storages ON storages.id = resources.storage_id\n"
610 "LEFT JOIN tag_translations ON tag_translations.tag_id = initial_selection.id\n"
611 " AND tag_translations.language = :language\n");
612
613 return query;
614}

◆ 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 618 of file KisTagResourceModel.cpp.

619{
620 if (orientation != Qt::Horizontal) {
621 return {};
622 }
623 if (role != Qt::DisplayRole) {
624 return {};
625 }
626
627 switch (section) {
629 return i18n("Id");
631 return i18n("Storage ID");
633 return i18n("Name");
635 return i18n("File Name");
637 return i18n("Tooltip");
639 return i18n("Image");
641 return i18n("Status");
643 return i18n("Location");
645 return i18n("Resource Type");
647 return i18n("Active");
649 return i18n("Storage Active");
651 return i18n("md5sum");
653 return i18n("Tags");
655 return i18n("Large Thumbnail");
657 return i18n("Dirty");
659 return i18n("Metadata");
660 default:
661 role = Qt::UserRole + section;
662 break;
663 }
664
665 switch (role) {
666 case Qt::UserRole + KisAllTagResourceModel::TagId:
667 return i18n("Tag ID");
668 case Qt::UserRole + KisAllTagResourceModel::ResourceId:
669 return i18n("Resource ID");
670 case Qt::UserRole + KisAllTagResourceModel::Tag:
671 return i18n("Tag Url");
672 case Qt::UserRole + KisAllTagResourceModel::Resource:
673 return i18n("Resource");
674 case Qt::UserRole + ResourceActive:
675 return i18n("Resource Active");
676 case Qt::UserRole + TagActive:
677 return i18n("Tag Active");
678 case Qt::UserRole + ResourceStorageActive:
679 return i18n("Storage Active");
680 case Qt::UserRole + ResourceName:
681 return i18n("Resource Name");
682 case Qt::UserRole + TagName:
683 return i18n("Tag File Name");
684 default:
685 break;
686 }
687
688 return {};
689}
@ 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 487 of file KisTagResourceModel.cpp.

488{
489 QSqlQuery query;
490 bool r = query.prepare("SELECT resource_tags.active\n"
491 "FROM resource_tags\n"
492 "WHERE resource_tags.resource_id = :resource_id\n"
493 "AND resource_tags.tag_id = :tag_id\n");
494
495 if (!r) {
496 qWarning() << "Could not prepare bool KisAllTagResourceModel::checkResourceTaggedState query" << query.lastError();
497 return false;
498 }
499
500 query.bindValue(":resource_id", resourceId);
501 query.bindValue(":tag_id", tag->id());
502
503 if (!query.exec()) {
504 qWarning() << "Could not execute is resource tagged with a specific tag query" << query.boundValues() << query.lastError();
505 return false;
506 }
507
508 r = query.first();
509 if (!r) {
510 // Resource was not tagged
511 return -1;
512 }
513
514 return query.value(0).toInt() > 0;
515}

◆ removeStorage

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

Definition at line 525 of file KisTagResourceModel.cpp.

526{
527 Q_UNUSED(location);
528 beginRemoveRows(QModelIndex(), rowCount(), rowCount());
529 resetQuery();
530 endRemoveRows();
531}

References resetQuery(), and rowCount().

◆ resetQuery()

bool KisAllTagResourceModel::resetQuery ( )
private

Definition at line 696 of file KisTagResourceModel.cpp.

697{
698 bool r = d->query.prepare(createQuery(true));
699
700 if (!r) {
701 qWarning() << "Could not prepare KisAllTagResourcesModel query" << d->query.lastError();
702 }
703
704 d->query.bindValue(":resource_type", d->resourceType);
705 d->query.bindValue(":language", KisTag::currentLocale());
706
707 r = d->query.exec();
708
709 if (!r) {
710 qWarning() << "Could not execute KisAllTagResourcesModel query" << d->query.lastError();
711 }
712
713 d->cachedRowCount = -1;
714
715 return r;
716}
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.

◆ 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 533 of file KisTagResourceModel.cpp.

534{
535 if (resourceType != d->resourceType) return;
536 if (resourceId < 0) return;
537
538 resetQuery();
539
542 QVector<QModelIndex> indexes;
543
544 for (int i = 0; i < rowCount(); ++i) {
545 const QModelIndex idx = this->index(i, 0);
546 KIS_ASSERT_RECOVER(idx.isValid()) { continue; }
547
548 if (idx.data(Qt::UserRole + KisAllTagResourceModel::ResourceId).toInt() == resourceId) {
549 indexes << idx;
550 }
551 }
552
553 Q_FOREACH(const QModelIndex &index, indexes) {
554 Q_EMIT dataChanged(index, index, {Qt::CheckStateRole, Qt::UserRole + KisAllTagResourceModel::ResourceActive});
555 }
556}
#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 int idd = 0;
242
243 while (allIndices.next()) {
244 idd++;
245 bool isActive = allIndices.value("resource_tags_pair_active").toBool();
246 if (isActive) {
247 activesRowId++;
248 lastActiveRowId = activesRowId;
249 } else {
250 bool variantSuccess = true;
251 int rowTagId = allIndices.value("tag_id").toInt(&variantSuccess);
252 KIS_SAFE_ASSERT_RECOVER(variantSuccess) { rowTagId = -1; }
253 int rowResourceId = allIndices.value("resource_id").toInt(&variantSuccess);
254 KIS_SAFE_ASSERT_RECOVER(variantSuccess) { rowResourceId = -1; }
255 if (rowTagId == tag->id() && resourceIdsToUpdate.contains(rowResourceId)) {
256 if (!resourcesCountForLastActiveRowId.contains(lastActiveRowId)) {
257 resourcesCountForLastActiveRowId[lastActiveRowId] = 1;
258 } else {
259 resourcesCountForLastActiveRowId[lastActiveRowId] = resourcesCountForLastActiveRowId[lastActiveRowId] + 1;
260 }
261 }
262 }
263 }
264
265 Q_FOREACH(const int key, resourcesCountForLastActiveRowId.keys()) {
266 // when having multiple beginInsertRows:
267 // let's say you have this model:
268 // 0 A
269 // 1 A
270 // 2 A
271 // <- put 2 Bs here
272 // 3 A
273 // <- put one B here
274 // 4 A
275 // and you want to add the two Bs and then add another B
276 // then the signals should be:
277 // beginRemoveRows(3, 4) <- new indices of the two Bs
278 // beginRemoveRows(4, 4) <- new index of the one B ignoring the action before
279
280
281 beginInsertRows(QModelIndex(), key + 1, key + resourcesCountForLastActiveRowId[key]);
282 howManyTimesBeginInsertedCalled++;
283 }
284
285 // Resource was tagged, then untagged. Tag again;
286 QSqlQuery q;
287
288 if (!q.prepare("UPDATE resource_tags\n"
289 "SET active = 1\n"
290 "WHERE resource_id = :resource_id\n"
291 "AND tag_id = :tag_id")) {
292
293
294 qWarning() << "Could not prepare update resource_tags to active statement" << q.lastError();
295
296 return false;
297 }
298
299 QVariantList resourceIdsVariants;
300 QVariantList tagIdVariants;
301
302 for (int i = 0; i < resourceIdsToUpdate.count(); i++) {
303 resourceIdsVariants << QVariant(resourceIdsToUpdate[i]);
304 tagIdVariants << QVariant(tag->id());
305 }
306
307 q.bindValue(":resource_id", resourceIdsVariants);
308 q.bindValue(":tag_id", tagIdVariants);
309
310 if (!q.execBatch()) {
311 qWarning() << "Could not execute update resource_tags to active statement" << q.lastError();
312 for (int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
313 endInsertRows();
314 }
315 return false;
316 }
317
318 }
319
320 if (resourceIdsToAdd.count() > 0) {
321
322 beginInsertRows(QModelIndex(), rowCount(), rowCount() + resourceIdsToAdd.count() - 1);
323 howManyTimesBeginInsertedCalled++;
324
325 // Resource was never tagged before, insert it. The active column is DEFAULT 1
326 QSqlQuery q;
327
328
329 QString values;
330 for (int i = 0; i < resourceIdsToAdd.count(); i++) {
331 if (i > 0) {
332 values.append(", ");
333 }
334 values.append("(?, ?, ?)");
335 }
336
337 if (!q.prepare(QString("INSERT INTO resource_tags\n"
338 "(resource_id, tag_id, active)\n"
339 "VALUES ") + values + QString(";\n"))) {
340 qWarning() << "Could not prepare insert into resource tags statement" << q.lastError();
341 for (int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
342 endInsertRows();
343 }
344 return false;
345 }
346
347 for (int i = 0; i < resourceIdsToAdd.count(); i++) {
348 q.addBindValue(resourceIdsToAdd[i]);
349 q.addBindValue(tag->id());
350 q.addBindValue(true);
351
352 }
353
354 if (!q.exec()) {
355 qWarning() << "Could not execute insert into resource tags statement" << q.boundValues() << q.lastError();
356 for (int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
357 endInsertRows();
358 }
359 return false;
360 }
361 }
362
363 resetQuery();
364
365 for (int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
366 endInsertRows();
367 }
368
369 return true;
370}
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 372 of file KisTagResourceModel.cpp.

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

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 96 of file KisTagResourceModel.h.


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