Krita Source Code Documentation
Loading...
Searching...
No Matches
KisTagModel.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2018 boud <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2020 Agata Cacko <cacko.azh@gmail.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7#include "KisTagModel.h"
8
9#include <QSqlError>
10#include <QSqlQuery>
11
12#include <klocalizedstring.h>
13
14#include <KisResourceLocator.h>
15#include <KisResourceCacheDb.h>
16#include <KisTag.h>
17
19#include <KisTagResourceModel.h>
20#include <KisStorageModel.h>
21#include <QVector>
22
23#include <kis_assert.h>
24
25static int s_fakeRowsCount {2};
26
28 QSqlQuery query;
29 QString resourceType;
30 int columnCount {5};
32};
33
34
35KisAllTagsModel::KisAllTagsModel(const QString &resourceType, QObject *parent)
36 : QAbstractTableModel(parent)
37 , d(new Private())
38{
39 d->resourceType = resourceType;
40 if (!d->resourceType.isEmpty()) {
41 resetQuery();
42 }
43
44 connect(KisResourceLocator::instance(), SIGNAL(storageAdded(const QString&)), this, SLOT(addStorage(const QString&)));
45 connect(KisResourceLocator::instance(), SIGNAL(storageRemoved(const QString&)), this, SLOT(removeStorage(const QString&)));
46 connect(KisStorageModel::instance(), SIGNAL(storageEnabled(const QString&)), this, SLOT(addStorage(const QString&)));
47 connect(KisStorageModel::instance(), SIGNAL(storageDisabled(const QString&)), this, SLOT(removeStorage(const QString&)));
48}
49
51{
53 model.setTagsFilter(QVector<int>() << tag->id());
54 QVector<int> taggedResources;
55 for (int i = 0; i < model.rowCount(); i++) {
56 QModelIndex idx = model.index(i, 0);
57 taggedResources.append(model.data(idx, Qt::UserRole + KisTagResourceModel::Id).toInt());
58 }
59
60 model.untagResources(tag, taggedResources);
61
62}
63
68
69int KisAllTagsModel::rowCount(const QModelIndex &parent) const
70{
71 if (parent.isValid()) {
72 return 0;
73 }
74
75 if (d->cachedRowCount < 0) {
76 QSqlQuery q;
77 const bool r = q.prepare("SELECT count(*)\n"
78 "FROM tags\n"
79 ", resource_types\n"
80 "LEFT JOIN tag_translations ON tag_translations.tag_id = tags.id AND tag_translations.language = :language\n"
81 "WHERE tags.resource_type_id = resource_types.id\n"
82 "AND resource_types.name = :resource_type\n");
83 if (!r) {
84 qWarning() << "Could not execute tags rowcount query" << q.lastError();
85 return 0;
86 }
87 q.bindValue(":resource_type", d->resourceType);
88 q.bindValue(":language", KisTag::currentLocale());
89 if (!q.exec()) {
90 qWarning() << "Could not execute tags rowcount query" << q.lastError();
91 return 0;
92 }
93 q.first();
94
95 const_cast<KisAllTagsModel*>(this)->d->cachedRowCount = q.value(0).toInt() + s_fakeRowsCount;
96 }
97 return d->cachedRowCount;
98}
99
100int KisAllTagsModel::columnCount(const QModelIndex &parent) const
101{
102 if (parent.isValid()) {
103 return 0;
104 }
105
106 return d->columnCount;
107}
108
109QVariant KisAllTagsModel::data(const QModelIndex &index, int role) const
110{
111 QVariant v;
112
113 if (!index.isValid()) return v;
114 if (index.row() > rowCount()) return v;
115 if (index.column() > d->columnCount) return v;
116
117 if (index.row() < s_fakeRowsCount) {
118 if (index.row() == KisAllTagsModel::All + s_fakeRowsCount) {
119 switch(role) {
120 case Qt::DisplayRole: // fallthrough
121 case Qt::ToolTipRole: // fallthrough
122 case Qt::StatusTipRole: // fallthrough
123 case Qt::WhatsThisRole:
124 case Qt::UserRole + Name:
125 return i18n("All");
126 case Qt::UserRole + Id:
127 return QString::number(KisAllTagsModel::All);
128 case Qt::UserRole + Url: {
129 return urlAll();
130 }
131 case Qt::UserRole + ResourceType:
132 return d->resourceType;
133 case Qt::UserRole + Active:
134 return true;
135 case Qt::UserRole + KisTagRole:
136 {
137 KisTagSP tag = tagForIndex(index);
138 QVariant response;
139 response.setValue(tag);
140 return response;
141 }
142 default:
143 ;
144 }
145 } else if (index.row() == KisAllTagsModel::AllUntagged + s_fakeRowsCount) {
146 switch(role) {
147 case Qt::DisplayRole: // fallthrough
148 case Qt::ToolTipRole: // fallthrough
149 case Qt::StatusTipRole: // fallthrough
150 case Qt::WhatsThisRole:
151 case Qt::UserRole + Name:
152 return i18n("All untagged");
153 case Qt::UserRole + Id:
154 return QString::number(KisAllTagsModel::AllUntagged);
155 case Qt::UserRole + Url: {
156 return urlAllUntagged();
157 }
158 case Qt::UserRole + ResourceType:
159 return d->resourceType;
160 case Qt::UserRole + Active:
161 return true;
162 case Qt::UserRole + KisTagRole:
163 {
164 KisTagSP tag = tagForIndex(index);
165 QVariant response;
166 response.setValue(tag);
167 return response;
168 }
169 default:
170 ;
171 }
172 }
173 }
174 else {
175 bool pos = const_cast<KisAllTagsModel*>(this)->d->query.seek(index.row() - s_fakeRowsCount);
176 if (pos) {
177 switch(role) {
178 case Qt::DisplayRole:
179 case Qt::UserRole + Name:
180 {
181 QVariant name = d->query.value("translated_name");
182 if (name.isNull()) {
183 name = d->query.value("name");
184 }
185 return name;
186 }
187 case Qt::ToolTipRole: // fallthrough
188 case Qt::StatusTipRole: // fallthrough
189 case Qt::WhatsThisRole:
190 {
191 QVariant comment = d->query.value("translated_comment");
192 if (comment.isNull()) {
193 comment = d->query.value("comment");
194 }
195 return comment;
196 }
197 case Qt::UserRole + Id:
198 return d->query.value("id");
199 case Qt::UserRole + Url:
200 return d->query.value("url");
201 case Qt::UserRole + ResourceType:
202 return d->query.value("resource_type");
203 case Qt::UserRole + Active:
204 return d->query.value("active");
205 case Qt::UserRole + KisTagRole:
206 {
207 KisTagSP tag = tagForIndex(index);
208 QVariant response;
209 response.setValue(tag);
210 return response;
211 }
212 default:
213 ;
214 }
215 }
216 }
217 return v;
218}
219
220bool KisAllTagsModel::setData(const QModelIndex &index, const QVariant &value, int role)
221{
222 int id = data(index, Qt::UserRole + Id).toInt();
223
224 if (index.isValid() &&
225 (role == Qt::UserRole + Active)) {
226
227 QSqlQuery q;
228 if (!q.prepare("UPDATE tags\n"
229 "SET active = :active\n"
230 "WHERE id = :id\n")) {
231 qWarning() << "Could not prepare make existing tag active query" << q.lastError();
232 return false;
233 }
234 q.bindValue(":active", value.toBool());
235 q.bindValue(":id", id);
236
237 if (!q.exec()) {
238 qWarning() << "Could not execute make existing tag active query" << q.boundValues(), q.lastError();
239 return false;
240 }
241 KisResourceLocator::instance()->purgeTag(data(index, Qt::UserRole + Url).toString(), d->resourceType);
242 }
243 resetQuery();
244 Q_EMIT dataChanged(index, index, {role});
245 return true;
246}
247
248Qt::ItemFlags KisAllTagsModel::flags(const QModelIndex &index) const
249{
250 if (!index.isValid()) {
251 return Qt::NoItemFlags;
252 }
253 return QAbstractTableModel::flags(index) | Qt::ItemIsEditable | Qt::ItemNeverHasChildren;
254}
255
257{
258 if (!tag) return QModelIndex();
259 // For now a linear seek to find the first tag
260 if (tag->id() < 0 && (tag->url() == urlAll() || tag->url() == urlAllUntagged())) {
261 // this must be either a fake tag id, or a "naked" tag
262 // TODO: do we even use "naked tags"? won't it be better to just use QStrings?
263 return index(tag->id() + s_fakeRowsCount, 0);
264 }
265
266 d->query.first();
267 bool r = d->query.first();
268 if (!r) {
269 return QModelIndex();
270 }
271 do {
272 if (tag->id() >= 0) {
273 if (d->query.value("id").toInt() == tag->id()) {
274 return index(d->query.at() + s_fakeRowsCount, 0);
275 }
276 }
277 else {
278 // This is a naked tag, one that didn't come from the
279 // database.
280 // But not a "fake" tag (All or AllUntagged)!
281 if (d->query.value("url").toString() == tag->url()
282 && d->query.value("resource_type") == d->resourceType) {
283 return index(d->query.at() + s_fakeRowsCount, 0);
284 }
285 }
286 } while (d->query.next());
287
288 return QModelIndex();
289}
290
292{
293 KisTagSP tag = 0;
294 if (!index.isValid()) return tag;
295 if (index.row() > rowCount()) return tag;
296 if (index.column() > columnCount()) return tag;
297
298 if (index.row() < s_fakeRowsCount) {
299 if (index.row() == KisAllTagsModel::All + s_fakeRowsCount) {
300 tag.reset(new KisTag());
301 tag->setName(i18n("All"));
302 tag->setResourceType(d->resourceType);
303 tag->setUrl(urlAll());
304 tag->setComment(i18n("All resources"));
305 tag->setId(KisAllTagsModel::All);
306 tag->setActive(true);
307 tag->setValid(true);
308 }
309 else if (index.row() == KisAllTagsModel::AllUntagged + s_fakeRowsCount) {
310 tag.reset(new KisTag());
311 tag->setName(i18n("All untagged"));
312 tag->setResourceType(d->resourceType);
313 tag->setUrl(urlAllUntagged());
314 tag->setComment(i18n("All untagged resources"));
316 tag->setActive(true);
317 tag->setValid(true);
318 }
319 }
320 else {
321 bool pos = const_cast<KisAllTagsModel*>(this)->d->query.seek(index.row() - s_fakeRowsCount);
322 if (pos) {
323 tag = KisResourceLocator::instance()->tagForUrl(d->query.value("url").toString(), d->resourceType);
324 }
325 }
326
327 return tag;
328}
329
330KisTagSP KisAllTagsModel::addTag(const QString& tagName, const bool allowOverwrite, QVector<KoResourceSP> taggedResources)
331{
332 KisTagSP tag = KisTagSP(new KisTag());
333 tag->setName(tagName);
334 tag->setUrl(tagName);
335 tag->setValid(true);
336 tag->setActive(true);
337 tag->setResourceType(d->resourceType);
338
339 if (addTag(tag, allowOverwrite, taggedResources)) {
340 return tag;
341 }
342 else {
343 return 0;
344 }
345}
346
347
348bool KisAllTagsModel::addTag(const KisTagSP tag, const bool allowOverwrite, QVector<KoResourceSP> taggedResources)
349{
350 if (!tag) return false;
351 if (!tag->valid()) return false;
352
353 bool r = true;
354
355 if (!KisResourceCacheDb::hasTag(tag->url(), d->resourceType)) {
356 beginInsertRows(QModelIndex(), rowCount(), rowCount());
357 if (!KisResourceCacheDb::addTag(d->resourceType, "", tag)) {
358 qWarning() << "Could not add tag" << tag;
359 return false;
360 }
361 resetQuery();
362 endInsertRows();
363
364 }
365 else if (allowOverwrite) {
366 KisTagSP trueTag = tagForUrl(tag->url());
367 r = setData(indexForTag(trueTag), QVariant::fromValue(true), Qt::UserRole + KisAllTagsModel::Active);
368 untagAllResources(trueTag);
369 tag->setComment(trueTag->comment()); // id will be set later, comment and filename are the only thing left
370 tag->setFilename(trueTag->filename());
371 }
372 else {
373 return false;
374 }
375
376 tag->setId(data(indexForTag(tag), Qt::UserRole + KisAllTagsModel::Id).toInt());
377 tag->setValid(true);
378 tag->setActive(data(indexForTag(tag), Qt::UserRole + KisAllTagsModel::Active).toInt());
379
380 if (!taggedResources.isEmpty()) {
381 QVector<int> resourceIds;
382 Q_FOREACH(const KoResourceSP resource, taggedResources) {
383
384 if (!resource) continue;
385 if (!resource->valid()) continue;
386 if (resource->resourceId() < 0) continue;
387
388 resourceIds << resource->resourceId();
389 }
391 }
392
393 return r;
394}
395
397{
398 if (!tag) return false;
399 if (!tag->valid()) return false;
400
401 tag->setActive(true);
402
403 return setData(indexForTag(tag), QVariant::fromValue(true), Qt::UserRole + KisAllTagsModel::Active);
404
405}
406
408{
409 if (!tag) return false;
410 if (!tag->valid()) return false;
411
412 tag->setActive(false);
413
414 return setData(indexForTag(tag), QVariant::fromValue(false), Qt::UserRole + KisAllTagsModel::Active);
415}
416
417bool KisAllTagsModel::renameTag(const KisTagSP tag, const QString &newName, const bool allowOverwrite)
418{
419 if (!tag) return false;
420 if (!tag->valid()) return false;
421 if (tag->id() < 0) return false;
422
423 if (newName.isEmpty()) return false;
424
425 KisTagSP dstTag = tagForUrl(newName);
426
427 if (dstTag && dstTag->active() && !allowOverwrite) {
428 return false;
429 }
430
431 if (!dstTag) {
432 dstTag = addTag(newName, false, {});
433 } else {
434 if (!dstTag->active()) {
435 setTagActive(dstTag);
436 }
437 untagAllResources(dstTag);
438 }
439
440 QVector<int> resourceIds;
441
443 model.setTagsFilter(QVector<int>() << tag->id());
444
445 for (int i = 0; i < model.rowCount(); i++) {
446 QModelIndex idx = model.index(i, 0);
447 resourceIds.append(model.data(idx, Qt::UserRole + KisTagResourceModel::Id).toInt());
448 }
449
450 model.tagResources(dstTag, resourceIds);
451 model.untagResources(tag, resourceIds);
452 setTagInactive(tag);
453
454 return true;
455}
456
457bool KisAllTagsModel::changeTagActive(const KisTagSP tag, bool active)
458{
459 if (!tag) return false;
460 if (!tag->valid()) return false;
461
462 QModelIndex idx = indexForTag(tag);
463 tag->setActive(active);
464 return setData(idx, QVariant::fromValue(active), Qt::UserRole + KisAllTagsModel::Active);
465
466}
467
468KisTagSP KisAllTagsModel::tagForUrl(const QString& tagUrl) const
469{
470 if (tagUrl.isEmpty()) {
471 return KisTagSP();
472 }
473
474 if (tagUrl == urlAll()) {
475 return tagForIndex(index(Ids::All + s_fakeRowsCount, 0));
476 } else if (tagUrl == urlAllUntagged()) {
477 return tagForIndex(index(Ids::AllUntagged + s_fakeRowsCount, 0));
478 }
479
481}
482
484{
485 bool r = d->query.prepare("SELECT tags.id\n"
486 ", tags.url\n"
487 ", tags.name\n"
488 ", tags.comment\n"
489 ", tags.active\n"
490 ", tags.filename\n"
491 ", resource_types.name as resource_type\n"
492 ", tag_translations.name as translated_name\n"
493 ", tag_translations.comment as translated_comment\n"
494 "FROM tags\n"
495 ", resource_types\n"
496 "LEFT JOIN tag_translations ON tag_translations.tag_id = tags.id AND tag_translations.language = :language\n"
497 "WHERE tags.resource_type_id = resource_types.id\n"
498 "AND resource_types.name = :resource_type\n"
499 "ORDER BY tags.id\n");
500
501 if (!r) {
502 qWarning() << "Could not prepare KisAllTagsModel query" << d->query.lastError();
503 }
504
505 d->query.bindValue(":resource_type", d->resourceType);
506 d->query.bindValue(":language", KisTag::currentLocale());
507
508 r = d->query.exec();
509
510 if (!r) {
511 qWarning() << "Could not select tags" << d->query.lastError();
512 }
513
514 d->cachedRowCount = -1;
515 return r;
516}
517
519{
520 d->query.clear();
521}
522
523void KisAllTagsModel::addStorage(const QString &location)
524{
525 Q_UNUSED(location)
526 beginResetModel();
527 resetQuery();
528 endResetModel();
529}
530
531void KisAllTagsModel::removeStorage(const QString &location)
532{
533 Q_UNUSED(location)
534 beginResetModel();
535 resetQuery();
536 endResetModel();
537}
538
543
544KisTagModel::KisTagModel(const QString &type, QObject *parent)
545 : QSortFilterProxyModel(parent)
546 , d(new Private())
547{
548 setSourceModel(KisResourceModelProvider::tagModel(type));
550}
551
553{
554 delete d;
555}
556
558{
559 if (d->tagFilter != filter) {
560 d->tagFilter = filter;
561 invalidateFilter();
562 }
563}
564
566{
567 if (d->storageFilter != filter) {
568 d->storageFilter = filter;
569 invalidateFilter();
570 }
571}
572
573QModelIndex KisTagModel::indexForTag(KisTagSP tag) const
574{
575 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel());
576 if (source) {
577 return mapFromSource(source->indexForTag(tag));
578 }
579 return QModelIndex();
580
581}
582
583KisTagSP KisTagModel::tagForIndex(QModelIndex index) const
584{
585 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel());
586 if (source) {
587 return source->tagForIndex(mapToSource(index));
588 }
589 return 0;
590}
591
592
593KisTagSP KisTagModel::addTag(const QString &tagName, const bool allowOverwrite, QVector<KoResourceSP> taggedResources)
594{
595 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel());
596 if (source) {
597 return source->addTag(tagName, allowOverwrite, taggedResources);
598 }
599 return 0;
600}
601
602KisTagSP KisTagModel::tagForUrl(const QString& url) const
603{
604 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel());
605 if (source) {
606 return source->tagForUrl(url);
607 }
608 return 0;
609}
610
611
612bool KisTagModel::addTag(const KisTagSP tag, const bool allowOverwrite, QVector<KoResourceSP> taggedResources)
613{
614 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel());
615 if (source) {
616 return source->addTag(tag, allowOverwrite, taggedResources) ;
617 }
618 return false;
619}
620
622{
623 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel());
624 if (source) {
625 return source->setTagInactive(tag) ;
626 }
627 return false;
628}
629
631{
632 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel());
633 if (source) {
634 return source->setTagActive(tag) ;
635 }
636 return false;
637
638}
639
640bool KisTagModel::renameTag(const KisTagSP tag, const QString &newName, const bool allowOverwrite)
641{
642 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel());
643 if (source) {
644 return source->renameTag(tag, newName, allowOverwrite);
645 }
646 return false;
647}
648
649bool KisTagModel::changeTagActive(const KisTagSP tag, bool active)
650{
651 KisAbstractTagModel *source = dynamic_cast<KisAbstractTagModel*>(sourceModel());
652 if (source) {
653 return source->changeTagActive(tag, active);
654 }
655 return false;
656}
657
658
659bool KisTagModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
660{
662 return true;
663 }
664
665 QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
666 if (!idx.isValid()) {
667 return false;
668 }
669 int tagId = sourceModel()->data(idx, Qt::UserRole + KisAllTagsModel::Id).toInt();
670
671 if (tagId < 0) {
672 return true;
673 }
674
675 TagFilter tagActive = (TagFilter)sourceModel()->data(idx, Qt::UserRole + KisAllTagsModel::Active).toInt();
676
677 StorageFilter storageActive = ShowAllStorages;
678
680 return (tagActive == d->tagFilter);
681 }
682
683 {
684 if (tagId > 0) {
685 QSqlQuery q;
686 const bool r = q.prepare("SELECT count(*)\n"
687 "FROM tags_storages\n"
688 ", storages\n"
689 "WHERE tags_storages.tag_id = :tag_id\n"
690 "AND tags_storages.storage_id = storages.id\n"
691 "AND storages.active = 1\n");
692 if (!r) {
693 qWarning() << "Could not execute tags in storages query" << q.lastError();
694 return true;
695 }
696
697 q.bindValue(":tag_id", tagId);
698
699 if (!q.exec()) {
700 qWarning() << "Could not execute tags in storages query" << q.lastError() << q.boundValues();
701 return true;
702 }
703 else {
704 q.first();
705
706 if (q.value(0).toInt() > 0) {
707 storageActive = ShowActiveStorages;
708 }
709 }
710 }
711 }
712
713 if (d->tagFilter == ShowAllTags) {
714 return (storageActive == d->storageFilter);
715 }
716
717 return ((storageActive == d->storageFilter) && (tagActive == d->tagFilter));
718}
719
720bool KisTagModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
721{
722 const bool leftIsFakeRow = source_left.row() < s_fakeRowsCount;
723 const bool rightIsFakeRow = source_right.row() < s_fakeRowsCount;
724 // Always sort fake rows ("All" and "All Untagged") above the rest.
725 if (leftIsFakeRow && rightIsFakeRow) {
726 return source_left.row() < source_right.row();
727 } else if (leftIsFakeRow) {
728 return true;
729 } else if (rightIsFakeRow) {
730 return false;
731 } else {
732 QString nameLeft = sourceModel()->data(source_left, Qt::UserRole + KisAllTagsModel::Name).toString().toLower();
733 QString nameRight = sourceModel()->data(source_right, Qt::UserRole + KisAllTagsModel::Name).toString().toLower();
734 return (nameLeft < nameRight);
735 }
736}
float value(const T *src, size_t ch)
qreal v
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
static int s_fakeRowsCount
QSharedPointer< KisTag > KisTagSP
Definition KisTag.h:20
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
QModelIndex indexForTag(KisTagSP tag) const override
static QString urlAll()
Definition KisTagModel.h:92
void removeStorage(const QString &location)
void untagAllResources(KisTagSP tag)
int columnCount(const QModelIndex &parent=QModelIndex()) const override
KisAllTagsModel(const QString &resourceType, QObject *parent=0)
QVariant data(const QModelIndex &index, int role) const override
void addStorage(const QString &location)
Private *const d
bool renameTag(const KisTagSP tag, const QString &newName, const bool allowOverwrite) override
KisTagSP tagForUrl(const QString &tagUrl) const override
Retrieve a tag by url.
~KisAllTagsModel() override
Qt::ItemFlags flags(const QModelIndex &index) const override
static QString urlAllUntagged()
Definition KisTagModel.h:93
bool setData(const QModelIndex &index, const QVariant &value, int role) override
KisTagSP addTag(const QString &tagName, const bool allowOverwrite, QVector< KoResourceSP > taggedResources) override
Add a new tag with a possibly empty list of resources to tag.
KisTagSP tagForIndex(QModelIndex index=QModelIndex()) const override
bool changeTagActive(const KisTagSP tag, bool active) override
bool setTagInactive(const KisTagSP tag) override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
bool setTagActive(const KisTagSP tag) override
static bool addTag(const QString &resourceType, const QString storageLocation, KisTagSP tag)
static bool hasTag(const QString &url, const QString &resourceType)
KisTagSP tagForUrl(const QString &tagUrl, const QString resourceType)
tagForUrl create a tag from the database
void purgeTag(const QString tagUrl, const QString resourceType)
static KisResourceLocator * instance()
static KisAllTagsModel * tagModel(const QString &resourceType)
static KisStorageModel * instance()
bool renameTag(const KisTagSP tag, const QString &newName, const bool allowOverwrite) override
KisTagSP addTag(const QString &tagName, const bool allowOverwrite, QVector< KoResourceSP > taggedResources) override
Add a new tag with a possibly empty list of resources to tag.
KisTagSP tagForUrl(const QString &url) const override
Retrieve a tag by url.
~KisTagModel() override
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
void setTagFilter(TagFilter filter)
KisTagModel(const QString &type, QObject *parent=0)
bool setTagActive(const KisTagSP tag) override
QModelIndex indexForTag(KisTagSP tag) const override
Private *const d
void setStorageFilter(StorageFilter filter)
bool setTagInactive(const KisTagSP tag) override
KisTagSP tagForIndex(QModelIndex index=QModelIndex()) const override
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override
bool changeTagActive(const KisTagSP tag, bool active) override
The KisTagResourceModel class makes it possible to retrieve the resources for certain tags or the tag...
bool untagResources(const KisTagSP tag, const QVector< int > &resourceIds) override
bool tagResources(const KisTagSP tag, const QVector< int > &resourceIds) override
void setTagsFilter(const QVector< int > tagIds)
The KisTag loads a tag from a .tag file. A .tag file is a .desktop file. The following fields are imp...
Definition KisTag.h:34
static QString currentLocale()
Definition KisTag.cpp:84
StorageFilter storageFilter