Krita Source Code Documentation
Loading...
Searching...
No Matches
KisResourceModel.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2018 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7#include "KisResourceModel.h"
8
9#include <QBuffer>
10#include <QSqlError>
11#include <QSqlQuery>
12
13#include <KisResourceLocator.h>
14#include <KisResourceCacheDb.h>
15
17#include <KisStorageModel.h>
18#include <KisTagModel.h>
19#include <KisResourceTypes.h>
20#include <kis_debug.h>
22
24
32
33KisAllResourcesModel::KisAllResourcesModel(const QString &resourceType, QObject *parent)
34 : QAbstractTableModel(parent)
35 , d(new Private)
36{
37
40
45
51
52 d->resourceType = resourceType;
53
55 resetQuery();
56}
57
62
63int KisAllResourcesModel::columnCount(const QModelIndex &parent) const
64{
65 if (parent.isValid()) {
66 return 0;
67 }
68
69 return d->columnCount;
70}
71
72QVariant KisAllResourcesModel::data(const QModelIndex &index, int role) const
73{
74
75 QVariant v;
76 if (!index.isValid()) return v;
77
78 if (index.row() > rowCount()) return v;
79 if (index.column() > d->columnCount) return v;
80
81 bool pos = const_cast<KisAllResourcesModel*>(this)->d->resourcesQuery.seek(index.row());
82
83 if (pos) {
85 }
86
87 return v;
88}
89
90QVariant KisAllResourcesModel::headerData(int section, Qt::Orientation orientation, int role) const
91{
92 if (role != Qt::DisplayRole) {
93 return {};
94 }
95 if (orientation == Qt::Horizontal) {
96 switch (section) {
97 case Id:
98 return i18n("Id");
99 case StorageId:
100 return i18n("Storage ID");
101 case Name:
102 return i18n("Name");
103 case Filename:
104 return i18n("File Name");
105 case Tooltip:
106 return i18n("Tooltip");
107 case Thumbnail:
108 return i18n("Image");
109 case Status:
110 return i18n("Status");
111 case Location:
112 return i18n("Location");
113 case ResourceType:
114 return i18n("Resource Type");
115 case ResourceActive:
116 return i18n("Active");
117 case StorageActive:
118 return i18n("Storage Active");
119 case MD5:
120 return i18n("md5sum");
121 case Tags:
122 return i18n("Tags");
123 case LargeThumbnail:
124 return i18n("Large Thumbnail");
125 case Dirty:
126 return i18n("Dirty");
127 case MetaData:
128 return i18n("Metadata");
129 case BrokenStatus:
130 return i18n("Broken Status");
132 return i18n("Broken Status Message");
133 default:
134 return QString::number(section);
135 }
136 }
137 return {};
138}
139
140bool KisAllResourcesModel::setData(const QModelIndex &index, const QVariant &value, int role)
141{
142 if (index.isValid() && role == Qt::CheckStateRole &&
143 value.canConvert<bool>()) {
144
145 return setResourceActive(index, value.toBool());
146 }
147
148 return true;
149}
150
151Qt::ItemFlags KisAllResourcesModel::flags(const QModelIndex &index) const
152{
153 if (!index.isValid()) {
154 return Qt::NoItemFlags;
155 }
156 return QAbstractTableModel::flags(index) | Qt::ItemIsEditable | Qt::ItemNeverHasChildren;
157}
158
159QHash<int, QByteArray> KisAllResourcesModel::roleNames() const
160{
161 QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
162 roles[Qt::UserRole + Id] = "id";
163 roles[Qt::UserRole + StorageId] = "storageId";
164 roles[Qt::UserRole + Name] = "name";
165 roles[Qt::UserRole + Filename] = "filename";
166 //roles[Qt::UserRole + Tooltip] = "tooltip";
167 roles[Qt::UserRole + Thumbnail] = "thumbnail";
168 roles[Qt::UserRole + Status] = "status";
169 roles[Qt::UserRole + Location] = "location";
170 roles[Qt::UserRole + ResourceType] = "resourcetype";
171 roles[Qt::UserRole + MD5] = "md5";
172 roles[Qt::UserRole + Tags] = "tags";
173 roles[Qt::UserRole + LargeThumbnail] = "largethumbnail";
174 roles[Qt::UserRole + Dirty] = "dirty";
175 roles[Qt::UserRole + MetaData] = "metadata";
176 roles[Qt::UserRole + ResourceActive] = "resourceactive";
177 roles[Qt::UserRole + StorageActive] = "storageactive";
178 roles[Qt::UserRole + BrokenStatus] = "brokenstatus";
179 roles[Qt::UserRole + BrokenStatusMessage] = "brokenstatusmessage";
180
181 return roles;
182}
183
185{
186 KoResourceSP resource = 0;
187
188 if (!index.isValid()) return resource;
189 if (index.row() > rowCount()) return resource;
190 if (index.column() > d->columnCount) return resource;
191
192 bool pos = const_cast<KisAllResourcesModel*>(this)->d->resourcesQuery.seek(index.row());
193 if (pos) {
194 int id = d->resourcesQuery.value("id").toInt();
195 resource = resourceForId(id);
196 }
197 return resource;
198}
199
204
205bool KisAllResourcesModel::resourceExists(const QString &md5, const QString &filename, const QString &name)
206{
207 QSqlQuery q;
208
209 // md5
210
211 if (!md5.isEmpty()) {
212
213 bool r = q.prepare("SELECT resources.id AS id\n"
214 "FROM resources\n"
215 "WHERE md5sum = :md5sum");
216 if (!r) {
217 qWarning() << "Could not prepare find resourceExists by md5 query" << q.lastError();
218 }
219
220 q.bindValue(":mdsum", md5);
221
222 r = q.exec();
223
224 if (!r) {
225 qWarning() << "Could not execute resourceExists by md5 query" << q.lastError();
226 }
227
228 if (q.first()) {
229 return true;
230 }
231 }
232
233 // filename
234
235 if (!filename.isEmpty()) {
236
237 bool r = q.prepare("SELECT resources.id AS id\n"
238 "FROM resources\n"
239 "WHERE filename = :filename");
240 if (!r) {
241 qWarning() << "Could not prepare find resourceExists by filename query" << q.lastError();
242 }
243
244 q.bindValue(":filename", filename);
245
246 r = q.exec();
247
248 if (!r) {
249 qWarning() << "Could not execute resourceExists by filename query" << q.lastError();
250 }
251
252 if (q.first()) {
253 return true;
254 }
255 }
256
257 // name
258
259 if (!name.isEmpty()) {
260
261 bool r = q.prepare("SELECT resources.id AS id\n"
262 "FROM resources\n"
263 "WHERE name = :name");
264 if (!r) {
265 qWarning() << "Could not prepare find resourceExists by name query" << q.lastError();
266 }
267
268 q.bindValue(":name", name);
269
270 r = q.exec();
271 if (!r) {
272 qWarning() << "Could not execute resourceExists by name query" << q.lastError();
273 }
274
275 if (q.first()) {
276 return true;
277 }
278 }
279
280 // failure
281
282 return false;
283}
284
286{
287 QVector<KoResourceSP> resources;
288
289 if (filename.isEmpty()) return resources;
290
291 QSqlQuery q;
292 bool r = q.prepare("SELECT resources.id AS id\n"
293 "FROM resources\n"
294 ", resource_types\n"
295 "WHERE resources.resource_type_id = resource_types.id\n"
296 "AND resources.filename = :resource_filename\n"
297 "AND resource_types.name = :resource_type\n");
298 if (!r) {
299 qWarning() << "Could not prepare KisAllResourcesModel query for resource name" << q.lastError();
300 }
301 q.bindValue(":resource_filename", filename);
302 q.bindValue(":resource_type", d->resourceType);
303
304 r = q.exec();
305 if (!r) {
306 qWarning() << "Could not select" << d->resourceType << "resources by filename" << q.lastError() << q.boundValues();
307 }
308
309 while (q.next()) {
310 int id = q.value("id").toInt();
312 if (resource) {
313 resources << resource;
314 }
315
316 }
317
318 return resources;
319}
320
322{
323 QVector<KoResourceSP> resources;
324
325 if (name.isEmpty()) return resources;
326
327 KoResourceSP resource = 0;
328
329 QSqlQuery q;
330 bool r = q.prepare("SELECT resources.id AS id\n"
331 "FROM resources\n"
332 ", resource_types\n"
333 "WHERE resources.resource_type_id = resource_types.id\n"
334 "AND resources.name = :resource_name\n"
335 "AND resource_types.name = :resource_type\n");
336 if (!r) {
337 qWarning() << "Could not prepare KisAllResourcesModel query for resource name" << q.lastError();
338 }
339
340 q.bindValue(":resource_type", d->resourceType);
341 q.bindValue(":resource_name", name);
342
343 r = q.exec();
344 if (!r) {
345 qWarning() << "Could not select" << d->resourceType << "resources by name" << q.lastError() << q.boundValues();
346 }
347
348 while (q.next()) {
349 int id = q.value("id").toInt();
351 if (resource) {
352 resources << resource;
353 }
354 }
355
356 return resources;
357}
358
359
361{
362 QVector<KoResourceSP> resources;
363
364 if (md5sum.isEmpty()) return resources;
365
366 KoResourceSP resource = 0;
367
368 QSqlQuery q;
369 bool r = q.prepare("SELECT resource_id AS id\n"
370 "FROM versioned_resources\n"
371 "WHERE md5sum = :md5sum");
372 if (!r) {
373 qWarning() << "Could not prepare KisAllResourcesModel query for resource md5" << q.lastError();
374 }
375 q.bindValue(":md5sum", md5sum);
376
377 r = q.exec();
378 if (!r) {
379 qWarning() << "Could not select" << d->resourceType << "resources by md5" << q.lastError() << q.boundValues();
380 }
381
382 while (q.next()) {
383 int id = q.value("id").toInt();
385 if (resource) {
386 resources << resource;
387 }
388 }
389 return resources;
390}
391
393{
394 if (!resource || !resource->valid() || resource->resourceId() < 0) return QModelIndex();
395
396 // For now a linear seek to find the first resource with the right id
397 return indexForResourceId(resource->resourceId());
398}
399
400QModelIndex KisAllResourcesModel::indexForResourceId(int resourceId) const
401{
402 if (!d->resourcesQuery.first()) {
403 return QModelIndex();
404 }
405
406 do {
407 if (d->resourcesQuery.value("id").toInt() == resourceId) {
408 return index(d->resourcesQuery.at(), 0);
409 }
410 } while (d->resourcesQuery.next());
411
412 return QModelIndex();
413}
414
415bool KisAllResourcesModel::setResourceActive(const QModelIndex &index, bool value)
416{
417 if (index.row() > rowCount()) return false;
418 if (index.column() > d->columnCount) return false;
419
420 int resourceId = index.data(Qt::UserRole + Id).toInt();
422 qWarning() << "Failed to change active state of the resource" << resourceId;
423 return false;
424 }
425
426 return true;
427}
428//static int s_i6 {0};
429
430KoResourceSP KisAllResourcesModel::importResourceFile(const QString &filename, const bool allowOverwrite, const QString &storageId)
431{
432 KoResourceSP importedResource = KisResourceLocator::instance()->importResourceFromFile(d->resourceType, filename, allowOverwrite, storageId);
433
434 if (!importedResource) {
435 qWarning() << "Failed to import resource" << filename;
436 }
437 resetQuery();
438
439 return importedResource;
440}
441
442KoResourceSP KisAllResourcesModel::importResource(const QString &filename, QIODevice *device, const bool allowOverwrite, const QString &storageId)
443{
444 KoResourceSP importedResource = KisResourceLocator::instance()->importResource(d->resourceType, filename, device, allowOverwrite, storageId);
445
446 if (!importedResource) {
447 qWarning() << "Failed to import resource" << filename;
448 }
449 resetQuery();
450
451 return importedResource;
452}
453
454bool KisAllResourcesModel::importWillOverwriteResource(const QString &fileName, const QString &storageLocation) const
455{
456 return KisResourceLocator::instance()->importWillOverwriteResource(d->resourceType, fileName, storageLocation);
457}
458
459bool KisAllResourcesModel::exportResource(KoResourceSP resource, QIODevice *device)
460{
461 bool res = KisResourceLocator::instance()->exportResource(resource, device);
462 if (!res) {
463 qWarning() << "Failed to export resource" << resource->signature();
464 }
465 return res;
466}
467
468bool KisAllResourcesModel::addResource(KoResourceSP resource, const QString &storageId)
469{
470 if (!resource || !resource->valid()) {
471 qWarning() << "Cannot add resource. Resource is null or not valid";
472 return false;
473 }
474
475 bool r = true;
476 beginInsertRows(QModelIndex(), rowCount(), rowCount());
477 if (!KisResourceLocator::instance()->addResource(d->resourceType, resource, storageId)) {
478 qWarning() << "Failed to add resource" << resource->name();
479 r = false;
480 }
481 resetQuery();
482 endInsertRows();
483
484 return r;
485}
486
488{
489 if (!resource || !resource->valid()) {
490 qWarning() << "Cannot add resource. Resource is null or not valid";
491 return false;
492 }
493
494 bool r = true;
495 beginInsertRows(QModelIndex(), rowCount(), rowCount());
497 qWarning() << "Failed to add resource with name deduplication" << resource->name();
498 r = false;
499 }
500 resetQuery();
501 endInsertRows();
502
503 return r;
504}
505
507{
508 if (!resource || !resource->valid()) {
509 qWarning() << "Cannot update resource. Resource is null or not valid";
510 return false;
511 }
512
514 qWarning() << "Failed to update resource" << resource;
515 return false;
516 }
517 bool r = resetQuery();
518 QModelIndex index = indexForResource(resource);
519 Q_EMIT dataChanged(index, index);
520 return r;
521}
522
524{
525 if (!resource || !resource->valid()) {
526 qWarning() << "Cannot reload resource. Resource is null or not valid";
527 return false;
528 }
529
531 qWarning() << "Failed to reload resource" << resource;
532 return false;
533 }
534
540 QModelIndex index = indexForResource(resource);
541 Q_EMIT dataChanged(index, index);
542 return true;
543}
544
545bool KisAllResourcesModel::renameResource(KoResourceSP resource, const QString &name)
546{
547 if (!resource || !resource->valid() || name.isEmpty()) {
548 qWarning() << "Cannot rename resources. Resource is NULL or not valid or name is empty";
549 return false;
550 }
551 resource->setName(name);
553 qWarning() << "Failed to rename resource" << resource << name;
554 return false;
555 }
556 bool r = resetQuery();
557 QModelIndex index = indexForResource(resource);
558 Q_EMIT dataChanged(index, index);
559 return r;
560}
561
562//static int s_i9 {0};
563
564bool KisAllResourcesModel::setResourceMetaData(KoResourceSP resource, QMap<QString, QVariant> metadata)
565{
566 Q_ASSERT(resource->resourceId() > -1);
567 return KisResourceLocator::instance()->setMetaDataForResource(resource->resourceId(), metadata);
568}
569
571{
572 bool r = d->resourcesQuery.prepare(
573 "SELECT resources.id\n"
574 ", resources.storage_id\n"
575 ", resources.name\n"
576 ", resources.filename\n"
577 ", resources.tooltip\n"
578 ", resources.status\n"
579 ", resources.md5sum\n"
580 ", storages.location\n"
581 ", resource_types.name as resource_type\n"
582 ", resources.status as resource_active\n"
583 ", storages.active as storage_active\n"
584 "FROM resources\n"
585 ", resource_types\n"
586 ", storages\n"
587 "WHERE resources.resource_type_id = resource_types.id\n"
588 "AND resources.storage_id = storages.id\n"
589 "AND resource_types.name = :resource_type\n"
590 "GROUP BY resources.name\n"
591 ", resources.filename\n"
592 ", resources.md5sum\n"
593 "ORDER BY resources.id");
594
595 if (!r) {
596 qWarning() << "Could not prepare KisAllResourcesModel query" << d->resourcesQuery.lastError();
597 return false;
598 }
599
600 d->resourcesQuery.bindValue(":resource_type", d->resourceType);
601 return true;
602}
603
605{
606 d->resourcesQuery.clear();
607}
608
610{
615 if (!d->resourcesQuery.isValid()) {
616 d->resourcesQuery.clear();
617 prepareQuery();
618 }
619
620 bool r = d->resourcesQuery.exec();
621 if (!r) {
622 qWarning() << "Could not select" << d->resourceType << "resources" << d->resourcesQuery.lastError() << d->resourcesQuery.boundValues();
623 }
624 d->cachedRowCount = -1;
625
626 return r;
627}
628
630{
631 bool r;
632
633 QSqlQuery q;
634
635 r = q.prepare("SELECT tags.url\n"
636 "FROM tags\n"
637 ", resource_tags\n"
638 ", resource_types\n"
639 "WHERE tags.active > 0\n" // make sure the tag is active
640 "AND tags.id = resource_tags.tag_id\n" // join tags + resource_tags by tag_id
641 "AND resource_tags.resource_id = :resource_id\n"
642 "AND resource_types.id = tags.resource_type_id\n" // make sure we're looking for tags for a specific resource
643 "AND resource_tags.active = 1\n"); // and the tag must be active
644 if (!r) {
645 qWarning() << "Could not prepare TagsForResource query" << q.lastError();
646 }
647
648 q.bindValue(":resource_id", resourceId);
649 r = q.exec();
650 if (!r) {
651 qWarning() << "Could not select tags for" << resourceId << q.lastError() << q.boundValues();
652 }
653
655 while (q.next()) {
656 KisTagSP tag = KisResourceLocator::instance()->tagForUrl(q.value(0).toString(), d->resourceType);
657 if (tag && tag->valid()) {
658 tags << tag;
659 }
660 }
661 return tags;
662}
663
664
665int KisAllResourcesModel::rowCount(const QModelIndex &parent) const
666{
667 if (parent.isValid()) {
668 return 0;
669 }
670
671 if (d->cachedRowCount < 0) {
679 QSqlQuery q;
680 bool r = q.prepare("SELECT COUNT(DISTINCT resources.name || resources.filename || resources.md5sum)\n"
681 "FROM resources\n"
682 ", resource_types\n"
683 "WHERE resources.resource_type_id = resource_types.id\n"
684 "AND resource_types.name = :resource_type\n");
685 if (!r) {
686 qWarning() << "Could not prepare all resources rowcount query" << q.lastError();
687 return 0;
688 }
689 q.bindValue(":resource_type", d->resourceType);
690 r = q.exec();
691 if (!r) {
692 qWarning() << "Could not execute all resources rowcount query" << q.lastError() << q.boundValues();
693 return 0;
694 }
695 q.first();
696
697 const_cast<KisAllResourcesModel*>(this)->d->cachedRowCount = q.value(0).toInt();
698 }
699
700 return d->cachedRowCount;
701}
702
704{
706 if (resourceIds.isEmpty()) return;
707
708 resetQuery();
709
710 Q_FOREACH (int resourceId, resourceIds) {
711 QModelIndex index = indexForResourceId(resourceId);
712
713 if (index.isValid()) {
714 Q_EMIT dataChanged(index, index, {Qt::UserRole + KisAbstractResourceModel::StorageActive});
715 }
716 }
717}
718
719void KisAllResourcesModel::storageResynchronized(const QString &storage, bool isBulkResynchronization)
720{
721 Q_UNUSED(storage);
722
723 // we handle bulk-synchronization separately in slotStoragesBulkSynchronizationFinished()
724 if (isBulkResynchronization) return;
725
726 // TODO: ideally, we should use more fine-grained updates for
727 // updating the storages, but let's keep it this
728 beginResetModel();
729 resetQuery();
730 endResetModel();
731}
732
734{
735 beginResetModel();
736 resetQuery();
737 endResetModel();
738}
739
740void KisAllResourcesModel::beginExternalResourceImport(const QString &resourceType, int numResources)
741{
742 if (resourceType != d->resourceType) return;
743
744 beginInsertRows(QModelIndex(), rowCount(), rowCount() + numResources - 1);
745}
746
747void KisAllResourcesModel::endExternalResourceImport(const QString &resourceType)
748{
749 if (resourceType != d->resourceType) return;
750
751 resetQuery();
752 endInsertRows();
753}
754
755void KisAllResourcesModel::beginExternalResourceRemove(const QString &resourceType, const QVector<int> &resourceIds)
756{
757 if (resourceType != d->resourceType) return;
758
759 Q_FOREACH (int resourceId, resourceIds) {
760 const QModelIndex index = indexForResourceId(resourceId);
761 if (index.isValid()) {
762 beginRemoveRows(QModelIndex(), index.row(), index.row());
764 } else {
765 // it's fine if the index is invalid; it probably means it's one of the duplicates (another resource with the same type and content was already in the database)
766 dbgResources << "KisAllResourcesModel::beginExternalResourceRemove got invalid index" << index << "for resourceId" << resourceId
767 << "of type" << resourceType << "(possibly the resource was deduplicated via sql query and that's why it doesn't appear in the model)";
768 }
769 }
770}
771
772void KisAllResourcesModel::endExternalResourceRemove(const QString &resourceType)
773{
774 if (resourceType != d->resourceType) return;
775
777 resetQuery();
778 }
779 for (int i = 0; i < d->externalResourcesRemovedCount; i++) {
780 endRemoveRows();
781 }
782
784}
785
786void KisAllResourcesModel::slotResourceActiveStateChanged(const QString &resourceType, int resourceId)
787{
788 if (resourceType != d->resourceType) return;
789 if (resourceId < 0) return;
790
791 resetQuery();
792
793 QModelIndex index = indexForResourceId(resourceId);
794
795 if (index.isValid()) {
796 Q_EMIT dataChanged(index, index, {Qt::CheckStateRole, Qt::UserRole + KisAbstractResourceModel::ResourceActive});
797 }
798}
799
806
807KisResourceModel::KisResourceModel(const QString &type, QObject *parent)
808 : QSortFilterProxyModel(parent)
809 , d(new Private)
810{
811 setSourceModel(KisResourceModelProvider::resourceModel(type));
812}
813
818
820{
821 if (d->resourceFilter != filter) {
822 d->resourceFilter = filter;
823 invalidateFilter();
824 }
825}
826
828{
829 if (d->storageFilter != filter) {
830 d->storageFilter = filter;
831 invalidateFilter();
832 }
833}
834
836{
837 d->showOnlyUntaggedResources = showOnlyUntagged;
838 invalidateFilter();
839}
840
842{
843 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
844 if (source) {
845 return source->resourceForIndex(mapToSource(index));
846 }
847 return 0;
848}
849
851{
852 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
853 if (source) {
854 return mapFromSource(source->indexForResource(resource));
855 }
856 return QModelIndex();
857}
858
859QModelIndex KisResourceModel::indexForResourceId(int resourceId) const
860{
861 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
862 if (source) {
863 return mapFromSource(source->indexForResourceId(resourceId));
864 }
865 return QModelIndex();
866}
867
868bool KisResourceModel::setResourceActive(const QModelIndex &index, bool value)
869{
870 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
871 if (source) {
872 return source->setResourceActive(mapToSource(index), value);
873 }
874 return false;
875}
876
877KoResourceSP KisResourceModel::importResourceFile(const QString &filename, const bool allowOverwrite, const QString &storageId)
878{
879 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
880 KoResourceSP res;
881 if (source) {
882 res = source->importResourceFile(filename, allowOverwrite, storageId);
883 }
884 invalidate();
885 return res;
886}
887
888KoResourceSP KisResourceModel::importResource(const QString &filename, QIODevice *device, const bool allowOverwrite, const QString &storageId)
889{
890 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
891 KoResourceSP res;
892 if (source) {
893 res = source->importResource(filename, device, allowOverwrite, storageId);
894 }
895 invalidate();
896 return res;
897}
898
899bool KisResourceModel::importWillOverwriteResource(const QString &fileName, const QString &storageLocation) const
900{
901 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
902 return source && source->importWillOverwriteResource(fileName, storageLocation);
903}
904
905bool KisResourceModel::exportResource(KoResourceSP resource, QIODevice *device)
906{
907 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
908 bool res = false;
909 if (source) {
910 res = source->exportResource(resource, device);
911 }
912 return res;
913}
914
915bool KisResourceModel::addResource(KoResourceSP resource, const QString &storageId)
916{
917 KisAllResourcesModel *source = qobject_cast<KisAllResourcesModel*>(sourceModel());
918 bool updateInsteadOfAdd = false;
919 bool result = false;
920
921 // Check whether the resource already existed, in that case, we will update
922 // and possibly reactivate the resource
923 QSqlQuery q;
924
925 if (!q.prepare("SELECT resources.id\n"
926 ", resources.md5sum\n"
927 ", storages.location\n"
928 ", resource_types.name\n"
929 "FROM resources\n"
930 ", storages\n"
931 ", resource_types\n"
932 "WHERE resources.name = :name\n"
933 "AND resources.storage_id = storages.id\n"
934 "AND resources.resource_type_id = resource_types.id\n"
935 "AND resources.status = 0")) {
936 qWarning() << "Could not create KisResourceModel::addResource query" << q.lastError();
937 }
938
939 q.bindValue(":name", resource->name());
940
941 if (!q.exec()) {
942 qWarning() << "Could not execute KisResourceModel::addResource query" << q.lastError();
943 }
944
945 while (q.next()) {
946 int id = q.value(0).toInt();
947 QString md5sum = q.value(1).toString();
948 QString storageLocation = q.value(2).toString();
949 QString resourceType = q.value(3).toString();
950
951
952 QSqlQuery q2;
953
954 if (!q2.prepare("SELECT MAX(version)\n"
955 "FROM versioned_resources\n"
956 "WHERE resource_id = :id")) {
957 qWarning() << "Could not prepare versioned_resources query" << q.lastError();
958 }
959
960 q2.bindValue(":id", id);
961
962 if (!q2.exec()) {
963 qWarning() << "Could not execute versioned_resources query" << q.lastError();
964 }
965
966 if (!q2.first()) {
967 qWarning() << "No resource version found with id" << id;
968 }
969
970 q.first();
971
972 int version = q2.value(0).toInt();
973
974 if (resourceType == resource->resourceType().first) {
975 resource->setResourceId(id);
976 resource->setVersion(version);
977 resource->setMD5Sum(md5sum);
978 resource->setActive(true);
979 resource->setStorageLocation(storageLocation);
980 bool result = updateResource(resource);
981 updateInsteadOfAdd = result;
982 break;
983 }
984 }
985
986 if (!updateInsteadOfAdd) {
987 result = source->addResource(resource, storageId);
988 }
989
990 if (result) {
991 invalidate();
992 }
993
994 return result;
995}
996
998{
999 KisAllResourcesModel *source = qobject_cast<KisAllResourcesModel*>(sourceModel());
1000
1001 const bool result = source->addResourceDeduplicateFileName(resource, storageId);
1002
1003 if (result) {
1004 invalidate();
1005 }
1006
1007 return result;
1008}
1009
1011{
1012 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
1013 if (source) {
1014 return source->updateResource(resource);
1015 }
1016 return false;
1017}
1018
1020{
1021 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
1022 if (source) {
1023 return source->reloadResource(resource);
1024 }
1025 return false;
1026}
1027
1028bool KisResourceModel::renameResource(KoResourceSP resource, const QString &name)
1029{
1030 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
1031 if (source) {
1032 return source->renameResource(resource, name);
1033 }
1034 return false;
1035}
1036
1037bool KisResourceModel::setResourceMetaData(KoResourceSP resource, QMap<QString, QVariant> metadata)
1038{
1039 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
1040 if (source) {
1041 return source->setResourceMetaData(resource, metadata);
1042 }
1043 return false;
1044}
1045
1046bool KisResourceModel::filterAcceptsColumn(int /*source_column*/, const QModelIndex &/*source_parent*/) const
1047{
1048 return true;
1049}
1050
1051bool KisResourceModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
1052{
1053 QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
1054
1055 if (idx.isValid()) {
1056 int id = idx.data(Qt::UserRole + KisAbstractResourceModel::Id).toInt();
1057
1059
1060 QString queryString = ("SELECT COUNT(*)\n"
1061 "FROM resources\n"
1062 ", storages\n"
1063 "WHERE resources.id IN (select resource_id FROM resource_tags WHERE active = 1)\n"
1064 "AND storages.id = resources.storage_id\n"
1065 "AND resources.id = :resource_id\n");
1066
1068 queryString.append("AND resources.status > 0\n");
1069 }
1070 else if (d->resourceFilter == ShowInactiveResources) {
1071 queryString.append("AND resources.status = 0\n");
1072 }
1073
1075 queryString.append("AND storages.active > 0\n");
1076 }
1077 else if (d->storageFilter == ShowInactiveStorages) {
1078 queryString.append("AND storages.active = 0\n");
1079 }
1080
1081 QSqlQuery q;
1082
1083 if (!q.prepare((queryString))) {
1084 qWarning() << "KisResourceModel: Could not prepare resource_tags query" << q.lastError();
1085 }
1086
1087 q.bindValue(":resource_id", id);
1088
1089 if (!q.exec()) {
1090 qWarning() << "KisResourceModel: Could not execute resource_tags query" << q.lastError() << q.boundValues();
1091 }
1092
1093 q.first();
1094 if (q.value(0).toInt() > 0) {
1095 return false;
1096 }
1097 }
1098 }
1099
1100 return filterResource(idx);
1101}
1102
1103bool KisResourceModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
1104{
1105 QString nameLeft = sourceModel()->data(source_left, Qt::UserRole + KisAbstractResourceModel::Name).toString();
1106 QString nameRight = sourceModel()->data(source_right, Qt::UserRole + KisAbstractResourceModel::Name).toString();
1107
1108 return nameLeft.toLower() < nameRight.toLower();
1109}
1110
1112{
1113 QVector<KoResourceSP> resources;
1114 for (int i = 0; i < rowCount(); ++i) {
1115 QModelIndex idx = index(i, 0);
1116 if (idx.isValid() && data(idx, Qt::UserRole + column).toString() == filter) {
1117 resources << resourceForIndex(idx);
1118 }
1119 }
1120
1121 return resources;
1122}
1123
1124bool KisResourceModel::filterResource(const QModelIndex &idx) const
1125{
1127 return true;
1128 }
1129
1130 ResourceFilter resourceActive = (ResourceFilter)sourceModel()->data(idx, Qt::UserRole + KisAbstractResourceModel::ResourceActive).toInt();
1131 StorageFilter storageActive = (StorageFilter)sourceModel()->data(idx, Qt::UserRole + KisAbstractResourceModel::StorageActive).toInt();
1132
1134 if (storageActive == d->storageFilter) {
1135 return true;
1136 }
1137 }
1138
1140 if (resourceActive == d->resourceFilter) {
1141 return true;
1142 }
1143 }
1144
1145 if ((storageActive == d->storageFilter) && (resourceActive == d->resourceFilter)) {
1146 return true;
1147 }
1148
1149 return false;
1150}
1151
1152
1154{
1155 KoResourceSP res = static_cast<KisAllResourcesModel*>(sourceModel())->resourceForId(id);
1156 QModelIndex idx = indexForResource(res);
1157 if (idx.isValid()) {
1158 return res;
1159 }
1160 return 0;
1161}
1162
1168
1173
1175{
1177}
1178
1180{
1181 return static_cast<KisAllResourcesModel*>(sourceModel())->tagsForResource(resourceId);
1182}
float value(const T *src, size_t ch)
qreal v
QPointF q2
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
Columns
The Columns enum indexes the columns in the model. To get the thumbnail for a particular resource,...
@ Status
Whether the resource is active. Duplicate of ResourceActive.
@ ResourceActive
Whether the current resource is active.
@ Dirty
A dirty resource is one that has been modified locally but not saved.
@ LargeThumbnail
A larger thumbnail for displaying in a tooltip. 200x200 or so.
@ MetaData
MetaData is a map of key, value pairs that is associated with this resource.
@ BrokenStatus
Whether the resource is broken (bool)
@ StorageActive
Whether the current resource's storage is active.
The KisAllresourcesModel class provides access to the cache database for a particular resource type....
KisAllResourcesModel(const QString &resourceType, QObject *parent=0)
void endExternalResourceImport(const QString &resourceType)
bool addResourceDeduplicateFileName(KoResourceSP resource, const QString &storageId=QString("")) override
addResource adds the given resource to the database and storage. If the resource already exists in th...
KoResourceSP importResource(const QString &filename, QIODevice *device, const bool allowOverwrite, const QString &storageId=QString("")) override
importResource imports a resource from a QIODevice
void slotResourceActiveStateChanged(const QString &resourceType, int resourceId)
bool resourceExists(const QString &md5, const QString &filename, const QString &name)
resourceExists checks whether there is a resource with, in order, the given md5, the filename or the ...
QModelIndex indexForResourceId(int resourceId) const override
indexFromResource
bool setResourceActive(const QModelIndex &index, bool value) override
setResourceActive changes 'active' state of the resource
bool importWillOverwriteResource(const QString &fileName, const QString &storageLocation=QString()) const override
importWillOverwriteResource checks is importing a resource with this filename will overwrite anything
bool setData(const QModelIndex &index, const QVariant &value, int role) override
void beginExternalResourceImport(const QString &resourceType, int numResources)
QVector< KoResourceSP > resourcesForName(const QString &name) const
Qt::ItemFlags flags(const QModelIndex &index) const override
KoResourceSP resourceForId(int id) const
QVector< KoResourceSP > resourcesForFilename(QString filename) const
QHash< int, QByteArray > roleNames() const override
bool addResource(KoResourceSP resource, const QString &storageId=QString("")) override
addResource adds the given resource to the database and storage. If the resource already exists in th...
void beginExternalResourceRemove(const QString &resourceType, const QVector< int > &resourceId)
int columnCount(const QModelIndex &parent=QModelIndex()) const override
QVariant data(const QModelIndex &index, int role) const override
QModelIndex indexForResource(KoResourceSP resource) const override
indexFromResource
bool exportResource(KoResourceSP resource, QIODevice *device) override
exportResource exports a resource into a QIODevice
bool renameResource(KoResourceSP resource, const QString &name) override
renameResource name the given resource. The resource will have its name field reset,...
QVector< KoResourceSP > resourcesForMD5(const QString &md5sum) const
void storageResynchronized(const QString &storage, bool isBulkResynchronization)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void endExternalResourceRemove(const QString &resourceType)
bool reloadResource(KoResourceSP resource) override
reloadResource
QVector< KisTagSP > tagsForResource(int resourceId) const
bool setResourceMetaData(KoResourceSP resource, QMap< QString, QVariant > metadata) override
setResourceMetaData
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
KoResourceSP resourceForIndex(QModelIndex index=QModelIndex()) const override
resourceForIndex returns a properly versioned and id'ed resource object
KoResourceSP importResourceFile(const QString &filename, const bool allowOverwrite, const QString &storageId=QString("")) override
importResourceFile
void storageActiveStateChanged(const QString &location)
bool updateResource(KoResourceSP resource) override
updateResource creates a new version of the resource in the storage and in the database....
static QVector< int > resourcesForStorage(const QString &resourceType, const QString &storageLocation)
KisTagSP tagForUrl(const QString &tagUrl, const QString resourceType)
tagForUrl create a tag from the database
KoResourceSP importResource(const QString &resourceType, const QString &fileName, QIODevice *device, const bool allowOverwrite, const QString &storageLocation=QString())
importResource
void endExternalResourceRemove(const QString &resourceType)
Emitted when the locator finished importing the embedded resource.
bool exportResource(KoResourceSP resource, QIODevice *device)
exportResource
void beginExternalResourceImport(const QString &resourceType, int numResources)
Emitted when the locator needs to add an embedded resource.
void beginExternalResourceRemove(const QString &resourceType, const QVector< int > resourceIds)
Emitted when the locator needs to add an embedded resource.
bool importWillOverwriteResource(const QString &resourceType, const QString &fileName, const QString &storageLocation=QString()) const
return whether importing will overwrite some existing resource
bool setMetaDataForResource(int id, QMap< QString, QVariant > map) const
setMetaDataForResource
void endExternalResourceImport(const QString &resourceType)
Emitted when the locator finished importing the embedded resource.
void resourceActiveStateChanged(const QString &resourceType, int resourceId)
Emitted when a resource changes its active state.
KoResourceSP resourceForId(int resourceId)
resourceForId returns the resource with the given id, or 0 if no such resource exists....
static KisResourceLocator * instance()
KoResourceSP importResourceFromFile(const QString &resourceType, const QString &fileName, const bool allowOverwrite, const QString &storageLocation=QString())
importResourceFromFile
static KisAllResourcesModel * resourceModel(const QString &resourceType)
QVector< KoResourceSP > filterByColumn(const QString filter, KisAllResourcesModel::Columns column) const
bool setResourceMetaData(KoResourceSP resource, QMap< QString, QVariant > metadata) override
setResourceMetaData
KoResourceSP resourceForId(int id) const
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override
KoResourceSP importResourceFile(const QString &filename, const bool allowOverwrite, const QString &storageId=QString("")) override
importResourceFile
bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const override
bool importWillOverwriteResource(const QString &fileName, const QString &storageLocation=QString()) const override
importWillOverwriteResource checks is importing a resource with this filename will overwrite anything
bool reloadResource(KoResourceSP resource) override
reloadResource
QVector< KisTagSP > tagsForResource(int resourceId) const
bool renameResource(KoResourceSP resource, const QString &name) override
renameResource name the given resource. The resource will have its name field reset,...
KisResourceModel(const QString &type, QObject *parent=0)
bool filterResource(const QModelIndex &idx) const
bool addResourceDeduplicateFileName(KoResourceSP resource, const QString &storageId=QString("")) override
addResource adds the given resource to the database and storage. If the resource already exists in th...
void setStorageFilter(StorageFilter filter) override
bool exportResource(KoResourceSP resource, QIODevice *device) override
exportResource exports a resource into a QIODevice
QVector< KoResourceSP > resourcesForMD5(const QString md5sum) const
bool updateResource(KoResourceSP resource) override
updateResource creates a new version of the resource in the storage and in the database....
QVector< KoResourceSP > resourcesForFilename(QString fileName) const
QVector< KoResourceSP > resourcesForName(QString name) const
bool addResource(KoResourceSP resource, const QString &storageId=QString("")) override
addResource adds the given resource to the database and storage. If the resource already exists in th...
void setResourceFilter(ResourceFilter filter) override
QModelIndex indexForResource(KoResourceSP resource) const override
indexFromResource
void showOnlyUntaggedResources(bool showOnlyUntagged)
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
bool setResourceActive(const QModelIndex &index, bool value) override
setResourceActive changes 'active' state of the resource
QModelIndex indexForResourceId(int resourceId) const override
indexFromResource
KoResourceSP importResource(const QString &filename, QIODevice *device, const bool allowOverwrite, const QString &storageId=QString("")) override
importResource imports a resource from a QIODevice
KoResourceSP resourceForIndex(QModelIndex index=QModelIndex()) const override
resourceForIndex returns a properly versioned and id'ed resource object
static QVariant variantFromResourceQuery(const QSqlQuery &query, int column, int role, bool useResourcePrefix)
variantFromResourceQuery returns a QVariant for the given column and or role
static KisStorageModel * instance()
void storageDisabled(const QString &storage)
void storageEnabled(const QString &storage)
void storageResynchronized(const QString &storage, bool isBulkResynchronization)
Emitted when an individual storage is initialized.
void storagesBulkSynchronizationFinished()
Emitted on loading when all the storages are finished initialization.
#define dbgResources
Definition kis_debug.h:43