File indexing completed on 2024-05-12 15:59:53
0001 /* 0002 * SPDX-FileCopyrightText: 2018 boud <boud@valdyas.org> 0003 * SPDX-FileCopyrightText: 2020 Agata Cacko <cacko.azh@gmail.com> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 #include "KisTagModel.h" 0008 0009 #include <QtSql> 0010 #include <QStringList> 0011 #include <QElapsedTimer> 0012 0013 #include <klocalizedstring.h> 0014 0015 #include <KisResourceLocator.h> 0016 #include <KisResourceCacheDb.h> 0017 #include <KisTag.h> 0018 0019 #include <KisResourceModelProvider.h> 0020 #include <KisTagResourceModel.h> 0021 #include <KisStorageModel.h> 0022 #include <QVector> 0023 0024 #include <kis_assert.h> 0025 0026 static int s_fakeRowsCount {2}; 0027 0028 struct KisAllTagsModel::Private { 0029 QSqlQuery query; 0030 QString resourceType; 0031 int columnCount {5}; 0032 int cachedRowCount {-1}; 0033 }; 0034 0035 0036 KisAllTagsModel::KisAllTagsModel(const QString &resourceType, QObject *parent) 0037 : QAbstractTableModel(parent) 0038 , d(new Private()) 0039 { 0040 d->resourceType = resourceType; 0041 if (!d->resourceType.isEmpty()) { 0042 resetQuery(); 0043 } 0044 0045 connect(KisResourceLocator::instance(), SIGNAL(storageAdded(const QString&)), this, SLOT(addStorage(const QString&))); 0046 connect(KisResourceLocator::instance(), SIGNAL(storageRemoved(const QString&)), this, SLOT(removeStorage(const QString&))); 0047 connect(KisStorageModel::instance(), SIGNAL(storageEnabled(const QString&)), this, SLOT(addStorage(const QString&))); 0048 connect(KisStorageModel::instance(), SIGNAL(storageDisabled(const QString&)), this, SLOT(removeStorage(const QString&))); 0049 } 0050 0051 void KisAllTagsModel::untagAllResources(KisTagSP tag) 0052 { 0053 KisTagResourceModel model(d->resourceType); 0054 model.setTagsFilter(QVector<int>() << tag->id()); 0055 QVector<int> taggedResources; 0056 for (int i = 0; i < model.rowCount(); i++) { 0057 QModelIndex idx = model.index(i, 0); 0058 taggedResources.append(model.data(idx, Qt::UserRole + KisTagResourceModel::Id).toInt()); 0059 } 0060 0061 model.untagResources(tag, taggedResources); 0062 0063 } 0064 0065 KisAllTagsModel::~KisAllTagsModel() 0066 { 0067 delete d; 0068 } 0069 0070 int KisAllTagsModel::rowCount(const QModelIndex &parent) const 0071 { 0072 if (parent.isValid()) { 0073 return 0; 0074 } 0075 0076 if (d->cachedRowCount < 0) { 0077 QSqlQuery q; 0078 q.prepare("SELECT count(*)\n" 0079 "FROM tags\n" 0080 ", resource_types\n" 0081 "LEFT JOIN tag_translations ON tag_translations.tag_id = tags.id AND tag_translations.language = :language\n" 0082 "WHERE tags.resource_type_id = resource_types.id\n" 0083 "AND resource_types.name = :resource_type\n"); 0084 q.bindValue(":resource_type", d->resourceType); 0085 q.bindValue(":language", KisTag::currentLocale()); 0086 if (!q.exec()) { 0087 qWarning() << "Could not execute tags rowcount query" << q.lastError(); 0088 } 0089 q.first(); 0090 0091 const_cast<KisAllTagsModel*>(this)->d->cachedRowCount = q.value(0).toInt() + s_fakeRowsCount; 0092 } 0093 return d->cachedRowCount; 0094 } 0095 0096 int KisAllTagsModel::columnCount(const QModelIndex &parent) const 0097 { 0098 if (parent.isValid()) { 0099 return 0; 0100 } 0101 0102 return d->columnCount; 0103 } 0104 0105 QVariant KisAllTagsModel::data(const QModelIndex &index, int role) const 0106 { 0107 QVariant v; 0108 0109 if (!index.isValid()) return v; 0110 if (index.row() > rowCount()) return v; 0111 if (index.column() > d->columnCount) return v; 0112 0113 if (index.row() < s_fakeRowsCount) { 0114 if (index.row() == KisAllTagsModel::All + s_fakeRowsCount) { 0115 switch(role) { 0116 case Qt::DisplayRole: // fallthrough 0117 case Qt::ToolTipRole: // fallthrough 0118 case Qt::StatusTipRole: // fallthrough 0119 case Qt::WhatsThisRole: 0120 case Qt::UserRole + Name: 0121 return i18n("All"); 0122 case Qt::UserRole + Id: 0123 return QString::number(KisAllTagsModel::All); 0124 case Qt::UserRole + Url: { 0125 return urlAll(); 0126 } 0127 case Qt::UserRole + ResourceType: 0128 return d->resourceType; 0129 case Qt::CheckStateRole: 0130 case Qt::UserRole + Active: 0131 return true; 0132 case Qt::UserRole + KisTagRole: 0133 { 0134 KisTagSP tag = tagForIndex(index); 0135 QVariant response; 0136 response.setValue(tag); 0137 return response; 0138 } 0139 default: 0140 ; 0141 } 0142 } else if (index.row() == KisAllTagsModel::AllUntagged + s_fakeRowsCount) { 0143 switch(role) { 0144 case Qt::DisplayRole: // fallthrough 0145 case Qt::ToolTipRole: // fallthrough 0146 case Qt::StatusTipRole: // fallthrough 0147 case Qt::WhatsThisRole: 0148 case Qt::UserRole + Name: 0149 return i18n("All Untagged"); 0150 case Qt::UserRole + Id: 0151 return QString::number(KisAllTagsModel::AllUntagged); 0152 case Qt::UserRole + Url: { 0153 return urlAllUntagged(); 0154 } 0155 case Qt::UserRole + ResourceType: 0156 return d->resourceType; 0157 case Qt::CheckStateRole: 0158 case Qt::UserRole + Active: 0159 return true; 0160 case Qt::UserRole + KisTagRole: 0161 { 0162 KisTagSP tag = tagForIndex(index); 0163 QVariant response; 0164 response.setValue(tag); 0165 return response; 0166 } 0167 default: 0168 ; 0169 } 0170 } 0171 } 0172 else { 0173 bool pos = const_cast<KisAllTagsModel*>(this)->d->query.seek(index.row() - s_fakeRowsCount); 0174 if (pos) { 0175 switch(role) { 0176 case Qt::DisplayRole: 0177 case Qt::UserRole + Name: 0178 { 0179 QVariant name = d->query.value("translated_name"); 0180 if (name.isNull()) { 0181 name = d->query.value("name"); 0182 } 0183 return name; 0184 } 0185 case Qt::ToolTipRole: // fallthrough 0186 case Qt::StatusTipRole: // fallthrough 0187 case Qt::WhatsThisRole: 0188 { 0189 QVariant comment = d->query.value("translated_comment"); 0190 if (comment.isNull()) { 0191 comment = d->query.value("comment"); 0192 } 0193 return comment; 0194 } 0195 case Qt::UserRole + Id: 0196 return d->query.value("id"); 0197 case Qt::UserRole + Url: 0198 return d->query.value("url"); 0199 case Qt::UserRole + ResourceType: 0200 return d->query.value("resource_type"); 0201 case Qt::CheckStateRole: 0202 case Qt::UserRole + Active: 0203 return d->query.value("active"); 0204 case Qt::UserRole + KisTagRole: 0205 { 0206 KisTagSP tag = tagForIndex(index); 0207 QVariant response; 0208 response.setValue(tag); 0209 return response; 0210 } 0211 default: 0212 ; 0213 } 0214 } 0215 } 0216 return v; 0217 } 0218 0219 bool KisAllTagsModel::setData(const QModelIndex &index, const QVariant &value, int role) 0220 { 0221 int id = data(index, Qt::UserRole + Id).toInt(); 0222 0223 if (index.isValid() && 0224 (role == Qt::CheckStateRole || role == Active)) { 0225 0226 QSqlQuery q; 0227 if (!q.prepare("UPDATE tags\n" 0228 "SET active = :active\n" 0229 "WHERE id = :id\n")) { 0230 qWarning() << "Could not prepare make existing tag active query" << q.lastError(); 0231 return false; 0232 } 0233 q.bindValue(":active", value.toBool()); 0234 q.bindValue(":id", id); 0235 0236 if (!q.exec()) { 0237 qWarning() << "Could not execute make existing tag active query" << q.boundValues(), q.lastError(); 0238 return false; 0239 } 0240 KisResourceLocator::instance()->purgeTag(data(index, Qt::UserRole + Url).toString(), d->resourceType); 0241 } 0242 resetQuery(); 0243 emit dataChanged(index, index, {role}); 0244 return true; 0245 } 0246 0247 Qt::ItemFlags KisAllTagsModel::flags(const QModelIndex &index) const 0248 { 0249 if (!index.isValid()) { 0250 return Qt::NoItemFlags; 0251 } 0252 return QAbstractTableModel::flags(index) | Qt::ItemIsEditable | Qt::ItemNeverHasChildren; 0253 } 0254 0255 QModelIndex KisAllTagsModel::indexForTag(KisTagSP tag) const 0256 { 0257 if (!tag) return QModelIndex(); 0258 // For now a linear seek to find the first tag 0259 if (tag->id() < 0 && (tag->url() == urlAll() || tag->url() == urlAllUntagged())) { 0260 // this must be either a fake tag id, or a "naked" tag 0261 // TODO: do we even use "naked tags"? won't it be better to just use QStrings? 0262 return index(tag->id() + s_fakeRowsCount, 0); 0263 } 0264 0265 d->query.first(); 0266 bool r = d->query.first(); 0267 if (!r) { 0268 return QModelIndex(); 0269 } 0270 do { 0271 if (tag->id() >= 0) { 0272 if (d->query.value("id").toInt() == tag->id()) { 0273 return index(d->query.at() + s_fakeRowsCount, 0); 0274 } 0275 } 0276 else { 0277 // This is a naked tag, one that didn't come from the 0278 // database. 0279 // But not a "fake" tag (All or AllUntagged)! 0280 if (d->query.value("url").toString() == tag->url() 0281 && d->query.value("resource_type") == d->resourceType) { 0282 return index(d->query.at() + s_fakeRowsCount, 0); 0283 } 0284 } 0285 } while (d->query.next()); 0286 0287 return QModelIndex(); 0288 } 0289 0290 KisTagSP KisAllTagsModel::tagForIndex(QModelIndex index) const 0291 { 0292 KisTagSP tag = 0; 0293 if (!index.isValid()) return tag; 0294 if (index.row() > rowCount()) return tag; 0295 if (index.column() > columnCount()) return tag; 0296 0297 if (index.row() < s_fakeRowsCount) { 0298 if (index.row() == KisAllTagsModel::All + s_fakeRowsCount) { 0299 tag.reset(new KisTag()); 0300 tag->setName(i18n("All")); 0301 tag->setResourceType(d->resourceType); 0302 tag->setUrl(urlAll()); 0303 tag->setComment(i18n("All Resources")); 0304 tag->setId(KisAllTagsModel::All); 0305 tag->setActive(true); 0306 tag->setValid(true); 0307 } 0308 else if (index.row() == KisAllTagsModel::AllUntagged + s_fakeRowsCount) { 0309 tag.reset(new KisTag()); 0310 tag->setName(i18n("All Untagged")); 0311 tag->setResourceType(d->resourceType); 0312 tag->setUrl(urlAllUntagged()); 0313 tag->setComment(i18n("All Untagged Resources")); 0314 tag->setId(KisAllTagsModel::AllUntagged); 0315 tag->setActive(true); 0316 tag->setValid(true); 0317 } 0318 } 0319 else { 0320 bool pos = const_cast<KisAllTagsModel*>(this)->d->query.seek(index.row() - s_fakeRowsCount); 0321 if (pos) { 0322 tag = KisResourceLocator::instance()->tagForUrl(d->query.value("url").toString(), d->resourceType); 0323 } 0324 } 0325 0326 return tag; 0327 } 0328 0329 KisTagSP KisAllTagsModel::addTag(const QString& tagName, const bool allowOverwrite, QVector<KoResourceSP> taggedResources) 0330 { 0331 KisTagSP tag = KisTagSP(new KisTag()); 0332 tag->setName(tagName); 0333 tag->setUrl(tagName); 0334 tag->setValid(true); 0335 tag->setActive(true); 0336 tag->setResourceType(d->resourceType); 0337 0338 if (addTag(tag, allowOverwrite, taggedResources)) { 0339 return tag; 0340 } 0341 else { 0342 return 0; 0343 } 0344 } 0345 0346 0347 bool KisAllTagsModel::addTag(const KisTagSP tag, const bool allowOverwrite, QVector<KoResourceSP> taggedResouces) 0348 { 0349 if (!tag) return false; 0350 if (!tag->valid()) return false; 0351 0352 bool r = true; 0353 0354 if (!KisResourceCacheDb::hasTag(tag->url(), d->resourceType)) { 0355 beginInsertRows(QModelIndex(), rowCount(), rowCount()); 0356 if (!KisResourceCacheDb::addTag(d->resourceType, "", tag)) { 0357 qWarning() << "Could not add tag" << tag; 0358 return false; 0359 } 0360 resetQuery(); 0361 endInsertRows(); 0362 0363 } 0364 else if (allowOverwrite) { 0365 KisTagSP trueTag = tagForUrl(tag->url()); 0366 r = setData(indexForTag(trueTag), QVariant::fromValue(true), Qt::CheckStateRole); 0367 untagAllResources(trueTag); 0368 tag->setComment(trueTag->comment()); // id will be set later, comment and filename are the only thing left 0369 tag->setFilename(trueTag->filename()); 0370 } 0371 else { 0372 return false; 0373 } 0374 0375 tag->setId(data(indexForTag(tag), Qt::UserRole + KisAllTagsModel::Id).toInt()); 0376 tag->setValid(true); 0377 tag->setActive(data(indexForTag(tag), Qt::UserRole + KisAllTagsModel::Active).toInt()); 0378 0379 if (!taggedResouces.isEmpty()) { 0380 QVector<int> resourceIds; 0381 Q_FOREACH(const KoResourceSP resource, taggedResouces) { 0382 0383 if (!resource) continue; 0384 if (!resource->valid()) continue; 0385 if (resource->resourceId() < 0) continue; 0386 0387 resourceIds << resource->resourceId(); 0388 } 0389 KisTagResourceModel(d->resourceType).tagResources(tag, resourceIds); 0390 } 0391 0392 return r; 0393 } 0394 0395 bool KisAllTagsModel::setTagActive(const KisTagSP tag) 0396 { 0397 if (!tag) return false; 0398 if (!tag->valid()) return false; 0399 0400 tag->setActive(true); 0401 0402 return setData(indexForTag(tag), QVariant::fromValue(true), Qt::CheckStateRole); 0403 0404 } 0405 0406 bool KisAllTagsModel::setTagInactive(const KisTagSP tag) 0407 { 0408 if (!tag) return false; 0409 if (!tag->valid()) return false; 0410 0411 tag->setActive(false); 0412 0413 return setData(indexForTag(tag), QVariant::fromValue(false), Qt::CheckStateRole); 0414 } 0415 0416 bool KisAllTagsModel::renameTag(const KisTagSP tag, const QString &newName, const bool allowOverwrite) 0417 { 0418 if (!tag) return false; 0419 if (!tag->valid()) return false; 0420 if (tag->id() < 0) return false; 0421 0422 if (newName.isEmpty()) return false; 0423 0424 KisTagSP dstTag = tagForUrl(newName); 0425 0426 if (dstTag && dstTag->active() && !allowOverwrite) { 0427 return false; 0428 } 0429 0430 if (!dstTag) { 0431 dstTag = addTag(newName, false, {}); 0432 } else { 0433 if (!dstTag->active()) { 0434 setTagActive(dstTag); 0435 } 0436 untagAllResources(dstTag); 0437 } 0438 0439 QVector<int> resourceIds; 0440 0441 KisTagResourceModel model(d->resourceType); 0442 model.setTagsFilter(QVector<int>() << tag->id()); 0443 0444 for (int i = 0; i < model.rowCount(); i++) { 0445 QModelIndex idx = model.index(i, 0); 0446 resourceIds.append(model.data(idx, Qt::UserRole + KisTagResourceModel::Id).toInt()); 0447 } 0448 0449 model.tagResources(dstTag, resourceIds); 0450 model.untagResources(tag, resourceIds); 0451 setTagInactive(tag); 0452 0453 return true; 0454 } 0455 0456 bool KisAllTagsModel::changeTagActive(const KisTagSP tag, bool active) 0457 { 0458 if (!tag) return false; 0459 if (!tag->valid()) return false; 0460 0461 QModelIndex idx = indexForTag(tag); 0462 tag->setActive(active); 0463 return setData(idx, QVariant::fromValue(active), Qt::CheckStateRole); 0464 0465 } 0466 0467 KisTagSP KisAllTagsModel::tagForUrl(const QString& tagUrl) const 0468 { 0469 if (tagUrl.isEmpty()) { 0470 return KisTagSP(); 0471 } 0472 0473 if (tagUrl == urlAll()) { 0474 return tagForIndex(index(Ids::All + s_fakeRowsCount, 0)); 0475 } else if (tagUrl == urlAllUntagged()) { 0476 return tagForIndex(index(Ids::AllUntagged + s_fakeRowsCount, 0)); 0477 } 0478 0479 return KisResourceLocator::instance()->tagForUrl(tagUrl, d->resourceType); 0480 } 0481 0482 bool KisAllTagsModel::resetQuery() 0483 { 0484 bool r = d->query.prepare("SELECT tags.id\n" 0485 ", tags.url\n" 0486 ", tags.name\n" 0487 ", tags.comment\n" 0488 ", tags.active\n" 0489 ", tags.filename\n" 0490 ", resource_types.name as resource_type\n" 0491 ", tag_translations.name as translated_name\n" 0492 ", tag_translations.comment as translated_comment\n" 0493 "FROM tags\n" 0494 ", resource_types\n" 0495 "LEFT JOIN tag_translations ON tag_translations.tag_id = tags.id AND tag_translations.language = :language\n" 0496 "WHERE tags.resource_type_id = resource_types.id\n" 0497 "AND resource_types.name = :resource_type\n" 0498 "ORDER BY tags.id\n"); 0499 0500 if (!r) { 0501 qWarning() << "Could not prepare KisAllTagsModel query" << d->query.lastError(); 0502 } 0503 0504 d->query.bindValue(":resource_type", d->resourceType); 0505 d->query.bindValue(":language", KisTag::currentLocale()); 0506 0507 r = d->query.exec(); 0508 0509 if (!r) { 0510 qWarning() << "Could not select tags" << d->query.lastError(); 0511 } 0512 0513 d->cachedRowCount = -1; 0514 return r; 0515 } 0516 0517 void KisAllTagsModel::addStorage(const QString &location) 0518 { 0519 Q_UNUSED(location) 0520 beginResetModel(); 0521 resetQuery(); 0522 endResetModel(); 0523 } 0524 0525 void KisAllTagsModel::removeStorage(const QString &location) 0526 { 0527 Q_UNUSED(location) 0528 beginResetModel(); 0529 resetQuery(); 0530 endResetModel(); 0531 } 0532 0533 struct KisTagModel::Private { 0534 TagFilter tagFilter{KisTagModel::ShowActiveTags}; 0535 StorageFilter storageFilter {KisTagModel::ShowActiveStorages}; 0536 }; 0537 0538 KisTagModel::KisTagModel(const QString &type, QObject *parent) 0539 : QSortFilterProxyModel(parent) 0540 , d(new Private()) 0541 { 0542 setSourceModel(KisResourceModelProvider::tagModel(type)); 0543 sort(KisAllTagsModel::Name); 0544 } 0545 0546 KisTagModel::~KisTagModel() 0547 { 0548 delete d; 0549 } 0550 0551 void KisTagModel::setTagFilter(KisTagModel::TagFilter filter) 0552 { 0553 if (d->tagFilter != filter) { 0554 d->tagFilter = filter; 0555 invalidateFilter(); 0556 } 0557 } 0558 0559 void KisTagModel::setStorageFilter(KisTagModel::StorageFilter filter) 0560 { 0561 if (d->storageFilter != filter) { 0562 d->storageFilter = filter; 0563 invalidateFilter(); 0564 } 0565 } 0566 0567 QModelIndex KisTagModel::indexForTag(KisTagSP tag) const 0568 { 0569 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel()); 0570 if (source) { 0571 return mapFromSource(source->indexForTag(tag)); 0572 } 0573 return QModelIndex(); 0574 0575 } 0576 0577 KisTagSP KisTagModel::tagForIndex(QModelIndex index) const 0578 { 0579 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel()); 0580 if (source) { 0581 return source->tagForIndex(mapToSource(index)); 0582 } 0583 return 0; 0584 } 0585 0586 0587 KisTagSP KisTagModel::addTag(const QString &tagName, const bool allowOverwrite, QVector<KoResourceSP> taggedResources) 0588 { 0589 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel()); 0590 if (source) { 0591 return source->addTag(tagName, allowOverwrite, taggedResources); 0592 } 0593 return 0; 0594 } 0595 0596 KisTagSP KisTagModel::tagForUrl(const QString& url) const 0597 { 0598 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel()); 0599 if (source) { 0600 return source->tagForUrl(url); 0601 } 0602 return 0; 0603 } 0604 0605 0606 bool KisTagModel::addTag(const KisTagSP tag, const bool allowOverwrite, QVector<KoResourceSP> taggedResouces) 0607 { 0608 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel()); 0609 if (source) { 0610 return source->addTag(tag, allowOverwrite, taggedResouces) ; 0611 } 0612 return false; 0613 } 0614 0615 bool KisTagModel::setTagInactive(const KisTagSP tag) 0616 { 0617 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel()); 0618 if (source) { 0619 return source->setTagInactive(tag) ; 0620 } 0621 return false; 0622 } 0623 0624 bool KisTagModel::setTagActive(const KisTagSP tag) 0625 { 0626 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel()); 0627 if (source) { 0628 return source->setTagActive(tag) ; 0629 } 0630 return false; 0631 0632 } 0633 0634 bool KisTagModel::renameTag(const KisTagSP tag, const QString &newName, const bool allowOverwrite) 0635 { 0636 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel()); 0637 if (source) { 0638 return source->renameTag(tag, newName, allowOverwrite); 0639 } 0640 return false; 0641 } 0642 0643 bool KisTagModel::changeTagActive(const KisTagSP tag, bool active) 0644 { 0645 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel()); 0646 if (source) { 0647 return source->changeTagActive(tag, active); 0648 } 0649 return false; 0650 } 0651 0652 0653 bool KisTagModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const 0654 { 0655 if (d->tagFilter == ShowAllTags && d->storageFilter == ShowAllStorages) { 0656 return true; 0657 } 0658 0659 QModelIndex idx = sourceModel()->index(source_row, 0, source_parent); 0660 if (!idx.isValid()) { 0661 return false; 0662 } 0663 int tagId = sourceModel()->data(idx, Qt::UserRole + KisAllTagsModel::Id).toInt(); 0664 0665 if (tagId < 0) { 0666 return true; 0667 } 0668 0669 TagFilter tagActive = (TagFilter)sourceModel()->data(idx, Qt::UserRole + KisAllTagsModel::Active).toInt(); 0670 0671 StorageFilter storageActive = ShowAllStorages; 0672 0673 if (d->storageFilter == ShowAllStorages) { 0674 return (tagActive == d->tagFilter); 0675 } 0676 0677 { 0678 if (tagId > 0) { 0679 QSqlQuery q; 0680 q.prepare("SELECT count(*)\n" 0681 "FROM tags_storages\n" 0682 ", storages\n" 0683 "WHERE tags_storages.tag_id = :tag_id\n" 0684 "AND tags_storages.storage_id = storages.id\n" 0685 "AND storages.active = 1\n"); 0686 0687 q.bindValue(":tag_id", tagId); 0688 0689 if (!q.exec()) { 0690 qWarning() << "Could not execute tags in storages query" << q.lastError() << q.boundValues(); 0691 } 0692 else { 0693 q.first(); 0694 0695 if (q.value(0).toInt() > 0) { 0696 storageActive = ShowActiveStorages; 0697 } 0698 } 0699 } 0700 } 0701 0702 if (d->tagFilter == ShowAllTags) { 0703 return (storageActive == d->storageFilter); 0704 } 0705 0706 return ((storageActive == d->storageFilter) && (tagActive == d->tagFilter)); 0707 } 0708 0709 bool KisTagModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const 0710 { 0711 const bool leftIsFakeRow = source_left.row() < s_fakeRowsCount; 0712 const bool rightIsFakeRow = source_right.row() < s_fakeRowsCount; 0713 // Always sort fake rows ("All" and "All Untagged") above the rest. 0714 if (leftIsFakeRow && rightIsFakeRow) { 0715 return source_left.row() < source_right.row(); 0716 } else if (leftIsFakeRow) { 0717 return true; 0718 } else if (rightIsFakeRow) { 0719 return false; 0720 } else { 0721 QString nameLeft = sourceModel()->data(source_left, Qt::UserRole + KisAllTagsModel::Name).toString().toLower(); 0722 QString nameRight = sourceModel()->data(source_right, Qt::UserRole + KisAllTagsModel::Name).toString().toLower(); 0723 return (nameLeft < nameRight); 0724 } 0725 }