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 update resource. Resource is null or not valid";
491 return false;
492 }
493
495 qWarning() << "Failed to update resource" << resource;
496 return false;
497 }
498 bool r = resetQuery();
499 QModelIndex index = indexForResource(resource);
500 Q_EMIT dataChanged(index, index);
501 return r;
502}
503
505{
506 if (!resource || !resource->valid()) {
507 qWarning() << "Cannot reload resource. Resource is null or not valid";
508 return false;
509 }
510
512 qWarning() << "Failed to reload resource" << resource;
513 return false;
514 }
515
521 QModelIndex index = indexForResource(resource);
522 Q_EMIT dataChanged(index, index);
523 return true;
524}
525
526bool KisAllResourcesModel::renameResource(KoResourceSP resource, const QString &name)
527{
528 if (!resource || !resource->valid() || name.isEmpty()) {
529 qWarning() << "Cannot rename resources. Resource is NULL or not valid or name is empty";
530 return false;
531 }
532 resource->setName(name);
534 qWarning() << "Failed to rename resource" << resource << name;
535 return false;
536 }
537 bool r = resetQuery();
538 QModelIndex index = indexForResource(resource);
539 Q_EMIT dataChanged(index, index);
540 return r;
541}
542
543//static int s_i9 {0};
544
545bool KisAllResourcesModel::setResourceMetaData(KoResourceSP resource, QMap<QString, QVariant> metadata)
546{
547 Q_ASSERT(resource->resourceId() > -1);
548 return KisResourceLocator::instance()->setMetaDataForResource(resource->resourceId(), metadata);
549}
550
552{
553 bool r = d->resourcesQuery.prepare(
554 "SELECT resources.id\n"
555 ", resources.storage_id\n"
556 ", resources.name\n"
557 ", resources.filename\n"
558 ", resources.tooltip\n"
559 ", resources.status\n"
560 ", resources.md5sum\n"
561 ", storages.location\n"
562 ", resource_types.name as resource_type\n"
563 ", resources.status as resource_active\n"
564 ", storages.active as storage_active\n"
565 "FROM resources\n"
566 ", resource_types\n"
567 ", storages\n"
568 "WHERE resources.resource_type_id = resource_types.id\n"
569 "AND resources.storage_id = storages.id\n"
570 "AND resource_types.name = :resource_type\n"
571 "GROUP BY resources.name\n"
572 ", resources.filename\n"
573 ", resources.md5sum\n"
574 "ORDER BY resources.id");
575
576 if (!r) {
577 qWarning() << "Could not prepare KisAllResourcesModel query" << d->resourcesQuery.lastError();
578 return false;
579 }
580
581 d->resourcesQuery.bindValue(":resource_type", d->resourceType);
582 return true;
583}
584
586{
587 d->resourcesQuery.clear();
588}
589
591{
596 if (!d->resourcesQuery.isValid()) {
597 d->resourcesQuery.clear();
598 prepareQuery();
599 }
600
601 bool r = d->resourcesQuery.exec();
602 if (!r) {
603 qWarning() << "Could not select" << d->resourceType << "resources" << d->resourcesQuery.lastError() << d->resourcesQuery.boundValues();
604 }
605 d->cachedRowCount = -1;
606
607 return r;
608}
609
611{
612 bool r;
613
614 QSqlQuery q;
615
616 r = q.prepare("SELECT tags.url\n"
617 "FROM tags\n"
618 ", resource_tags\n"
619 ", resource_types\n"
620 "WHERE tags.active > 0\n" // make sure the tag is active
621 "AND tags.id = resource_tags.tag_id\n" // join tags + resource_tags by tag_id
622 "AND resource_tags.resource_id = :resource_id\n"
623 "AND resource_types.id = tags.resource_type_id\n" // make sure we're looking for tags for a specific resource
624 "AND resource_tags.active = 1\n"); // and the tag must be active
625 if (!r) {
626 qWarning() << "Could not prepare TagsForResource query" << q.lastError();
627 }
628
629 q.bindValue(":resource_id", resourceId);
630 r = q.exec();
631 if (!r) {
632 qWarning() << "Could not select tags for" << resourceId << q.lastError() << q.boundValues();
633 }
634
636 while (q.next()) {
637 KisTagSP tag = KisResourceLocator::instance()->tagForUrl(q.value(0).toString(), d->resourceType);
638 if (tag && tag->valid()) {
639 tags << tag;
640 }
641 }
642 return tags;
643}
644
645
646int KisAllResourcesModel::rowCount(const QModelIndex &parent) const
647{
648 if (parent.isValid()) {
649 return 0;
650 }
651
652 if (d->cachedRowCount < 0) {
660 QSqlQuery q;
661 bool r = q.prepare("SELECT COUNT(DISTINCT resources.name || resources.filename || resources.md5sum)\n"
662 "FROM resources\n"
663 ", resource_types\n"
664 "WHERE resources.resource_type_id = resource_types.id\n"
665 "AND resource_types.name = :resource_type\n");
666 if (!r) {
667 qWarning() << "Could not prepare all resources rowcount query" << q.lastError();
668 return 0;
669 }
670 q.bindValue(":resource_type", d->resourceType);
671 r = q.exec();
672 if (!r) {
673 qWarning() << "Could not execute all resources rowcount query" << q.lastError() << q.boundValues();
674 return 0;
675 }
676 q.first();
677
678 const_cast<KisAllResourcesModel*>(this)->d->cachedRowCount = q.value(0).toInt();
679 }
680
681 return d->cachedRowCount;
682}
683
685{
687 if (resourceIds.isEmpty()) return;
688
689 resetQuery();
690
691 Q_FOREACH (int resourceId, resourceIds) {
692 QModelIndex index = indexForResourceId(resourceId);
693
694 if (index.isValid()) {
695 Q_EMIT dataChanged(index, index, {Qt::UserRole + KisAbstractResourceModel::StorageActive});
696 }
697 }
698}
699
700void KisAllResourcesModel::storageResynchronized(const QString &storage, bool isBulkResynchronization)
701{
702 Q_UNUSED(storage);
703
704 // we handle bulk-synchronization separately in slotStoragesBulkSynchronizationFinished()
705 if (isBulkResynchronization) return;
706
707 // TODO: ideally, we should use more fine-grained updates for
708 // updating the storages, but let's keep it this
709 beginResetModel();
710 resetQuery();
711 endResetModel();
712}
713
715{
716 beginResetModel();
717 resetQuery();
718 endResetModel();
719}
720
721void KisAllResourcesModel::beginExternalResourceImport(const QString &resourceType, int numResources)
722{
723 if (resourceType != d->resourceType) return;
724
725 beginInsertRows(QModelIndex(), rowCount(), rowCount() + numResources - 1);
726}
727
728void KisAllResourcesModel::endExternalResourceImport(const QString &resourceType)
729{
730 if (resourceType != d->resourceType) return;
731
732 resetQuery();
733 endInsertRows();
734}
735
736void KisAllResourcesModel::beginExternalResourceRemove(const QString &resourceType, const QVector<int> &resourceIds)
737{
738 if (resourceType != d->resourceType) return;
739
740 Q_FOREACH (int resourceId, resourceIds) {
741 const QModelIndex index = indexForResourceId(resourceId);
742 if (index.isValid()) {
743 beginRemoveRows(QModelIndex(), index.row(), index.row());
745 } else {
746 // 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)
747 dbgResources << "KisAllResourcesModel::beginExternalResourceRemove got invalid index" << index << "for resourceId" << resourceId
748 << "of type" << resourceType << "(possibly the resource was deduplicated via sql query and that's why it doesn't appear in the model)";
749 }
750 }
751}
752
753void KisAllResourcesModel::endExternalResourceRemove(const QString &resourceType)
754{
755 if (resourceType != d->resourceType) return;
756
758 resetQuery();
759 }
760 for (int i = 0; i < d->externalResourcesRemovedCount; i++) {
761 endRemoveRows();
762 }
763
765}
766
767void KisAllResourcesModel::slotResourceActiveStateChanged(const QString &resourceType, int resourceId)
768{
769 if (resourceType != d->resourceType) return;
770 if (resourceId < 0) return;
771
772 resetQuery();
773
774 QModelIndex index = indexForResourceId(resourceId);
775
776 if (index.isValid()) {
777 Q_EMIT dataChanged(index, index, {Qt::CheckStateRole, Qt::UserRole + KisAbstractResourceModel::ResourceActive});
778 }
779}
780
787
788KisResourceModel::KisResourceModel(const QString &type, QObject *parent)
789 : QSortFilterProxyModel(parent)
790 , d(new Private)
791{
792 setSourceModel(KisResourceModelProvider::resourceModel(type));
793}
794
799
801{
802 if (d->resourceFilter != filter) {
803 d->resourceFilter = filter;
804 invalidateFilter();
805 }
806}
807
809{
810 if (d->storageFilter != filter) {
811 d->storageFilter = filter;
812 invalidateFilter();
813 }
814}
815
817{
818 d->showOnlyUntaggedResources = showOnlyUntagged;
819 invalidateFilter();
820}
821
823{
824 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
825 if (source) {
826 return source->resourceForIndex(mapToSource(index));
827 }
828 return 0;
829}
830
832{
833 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
834 if (source) {
835 return mapFromSource(source->indexForResource(resource));
836 }
837 return QModelIndex();
838}
839
840QModelIndex KisResourceModel::indexForResourceId(int resourceId) const
841{
842 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
843 if (source) {
844 return mapFromSource(source->indexForResourceId(resourceId));
845 }
846 return QModelIndex();
847}
848
849bool KisResourceModel::setResourceActive(const QModelIndex &index, bool value)
850{
851 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
852 if (source) {
853 return source->setResourceActive(mapToSource(index), value);
854 }
855 return false;
856}
857
858KoResourceSP KisResourceModel::importResourceFile(const QString &filename, const bool allowOverwrite, const QString &storageId)
859{
860 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
861 KoResourceSP res;
862 if (source) {
863 res = source->importResourceFile(filename, allowOverwrite, storageId);
864 }
865 invalidate();
866 return res;
867}
868
869KoResourceSP KisResourceModel::importResource(const QString &filename, QIODevice *device, const bool allowOverwrite, const QString &storageId)
870{
871 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
872 KoResourceSP res;
873 if (source) {
874 res = source->importResource(filename, device, allowOverwrite, storageId);
875 }
876 invalidate();
877 return res;
878}
879
880bool KisResourceModel::importWillOverwriteResource(const QString &fileName, const QString &storageLocation) const
881{
882 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
883 return source && source->importWillOverwriteResource(fileName, storageLocation);
884}
885
886bool KisResourceModel::exportResource(KoResourceSP resource, QIODevice *device)
887{
888 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
889 bool res = false;
890 if (source) {
891 res = source->exportResource(resource, device);
892 }
893 return res;
894}
895
896bool KisResourceModel::addResource(KoResourceSP resource, const QString &storageId)
897{
898 KisAllResourcesModel *source = qobject_cast<KisAllResourcesModel*>(sourceModel());
899 bool updateInsteadOfAdd = false;
900 bool result = false;
901
902 // Check whether the resource already existed, in that case, we will update
903 // and possibly reactivate the resource
904 QSqlQuery q;
905
906 if (!q.prepare("SELECT resources.id\n"
907 ", resources.md5sum\n"
908 ", storages.location\n"
909 ", resource_types.name\n"
910 "FROM resources\n"
911 ", storages\n"
912 ", resource_types\n"
913 "WHERE resources.name = :name\n"
914 "AND resources.storage_id = storages.id\n"
915 "AND resources.resource_type_id = resource_types.id\n"
916 "AND resources.status = 0")) {
917 qWarning() << "Could not create KisResourceModel::addResource query" << q.lastError();
918 }
919
920 q.bindValue(":name", resource->name());
921
922 if (!q.exec()) {
923 qWarning() << "Could not execute KisResourceModel::addResource query" << q.lastError();
924 }
925
926 while (q.next()) {
927 int id = q.value(0).toInt();
928 QString md5sum = q.value(1).toString();
929 QString storageLocation = q.value(2).toString();
930 QString resourceType = q.value(3).toString();
931
932
933 QSqlQuery q2;
934
935 if (!q2.prepare("SELECT MAX(version)\n"
936 "FROM versioned_resources\n"
937 "WHERE resource_id = :id")) {
938 qWarning() << "Could not prepare versioned_resources query" << q.lastError();
939 }
940
941 q2.bindValue(":id", id);
942
943 if (!q2.exec()) {
944 qWarning() << "Could not execute versioned_resources query" << q.lastError();
945 }
946
947 if (!q2.first()) {
948 qWarning() << "No resource version found with id" << id;
949 }
950
951 q.first();
952
953 int version = q2.value(0).toInt();
954
955 if (resourceType == resource->resourceType().first) {
956 resource->setResourceId(id);
957 resource->setVersion(version);
958 resource->setMD5Sum(md5sum);
959 resource->setActive(true);
960 resource->setStorageLocation(storageLocation);
961 bool result = updateResource(resource);
962 updateInsteadOfAdd = result;
963 break;
964 }
965 }
966
967 if (!updateInsteadOfAdd) {
968 result = source->addResource(resource, storageId);
969 }
970
971 if (result) {
972 invalidate();
973 }
974
975 return result;
976}
977
979{
980 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
981 if (source) {
982 return source->updateResource(resource);
983 }
984 return false;
985}
986
988{
989 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
990 if (source) {
991 return source->reloadResource(resource);
992 }
993 return false;
994}
995
996bool KisResourceModel::renameResource(KoResourceSP resource, const QString &name)
997{
998 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
999 if (source) {
1000 return source->renameResource(resource, name);
1001 }
1002 return false;
1003}
1004
1005bool KisResourceModel::setResourceMetaData(KoResourceSP resource, QMap<QString, QVariant> metadata)
1006{
1007 KisAbstractResourceModel *source = dynamic_cast<KisAbstractResourceModel*>(sourceModel());
1008 if (source) {
1009 return source->setResourceMetaData(resource, metadata);
1010 }
1011 return false;
1012}
1013
1014bool KisResourceModel::filterAcceptsColumn(int /*source_column*/, const QModelIndex &/*source_parent*/) const
1015{
1016 return true;
1017}
1018
1019bool KisResourceModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
1020{
1021 QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
1022
1023 if (idx.isValid()) {
1024 int id = idx.data(Qt::UserRole + KisAbstractResourceModel::Id).toInt();
1025
1027
1028 QString queryString = ("SELECT COUNT(*)\n"
1029 "FROM resources\n"
1030 ", storages\n"
1031 "WHERE resources.id IN (select resource_id FROM resource_tags WHERE active = 1)\n"
1032 "AND storages.id = resources.storage_id\n"
1033 "AND resources.id = :resource_id\n");
1034
1036 queryString.append("AND resources.status > 0\n");
1037 }
1038 else if (d->resourceFilter == ShowInactiveResources) {
1039 queryString.append("AND resources.status = 0\n");
1040 }
1041
1043 queryString.append("AND storages.active > 0\n");
1044 }
1045 else if (d->storageFilter == ShowInactiveStorages) {
1046 queryString.append("AND storages.active = 0\n");
1047 }
1048
1049 QSqlQuery q;
1050
1051 if (!q.prepare((queryString))) {
1052 qWarning() << "KisResourceModel: Could not prepare resource_tags query" << q.lastError();
1053 }
1054
1055 q.bindValue(":resource_id", id);
1056
1057 if (!q.exec()) {
1058 qWarning() << "KisResourceModel: Could not execute resource_tags query" << q.lastError() << q.boundValues();
1059 }
1060
1061 q.first();
1062 if (q.value(0).toInt() > 0) {
1063 return false;
1064 }
1065 }
1066 }
1067
1068 return filterResource(idx);
1069}
1070
1071bool KisResourceModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
1072{
1073 QString nameLeft = sourceModel()->data(source_left, Qt::UserRole + KisAbstractResourceModel::Name).toString();
1074 QString nameRight = sourceModel()->data(source_right, Qt::UserRole + KisAbstractResourceModel::Name).toString();
1075
1076 return nameLeft.toLower() < nameRight.toLower();
1077}
1078
1080{
1081 QVector<KoResourceSP> resources;
1082 for (int i = 0; i < rowCount(); ++i) {
1083 QModelIndex idx = index(i, 0);
1084 if (idx.isValid() && data(idx, Qt::UserRole + column).toString() == filter) {
1085 resources << resourceForIndex(idx);
1086 }
1087 }
1088
1089 return resources;
1090}
1091
1092bool KisResourceModel::filterResource(const QModelIndex &idx) const
1093{
1095 return true;
1096 }
1097
1098 ResourceFilter resourceActive = (ResourceFilter)sourceModel()->data(idx, Qt::UserRole + KisAbstractResourceModel::ResourceActive).toInt();
1099 StorageFilter storageActive = (StorageFilter)sourceModel()->data(idx, Qt::UserRole + KisAbstractResourceModel::StorageActive).toInt();
1100
1102 if (storageActive == d->storageFilter) {
1103 return true;
1104 }
1105 }
1106
1108 if (resourceActive == d->resourceFilter) {
1109 return true;
1110 }
1111 }
1112
1113 if ((storageActive == d->storageFilter) && (resourceActive == d->resourceFilter)) {
1114 return true;
1115 }
1116
1117 return false;
1118}
1119
1120
1122{
1123 KoResourceSP res = static_cast<KisAllResourcesModel*>(sourceModel())->resourceForId(id);
1124 QModelIndex idx = indexForResource(res);
1125 if (idx.isValid()) {
1126 return res;
1127 }
1128 return 0;
1129}
1130
1136
1141
1143{
1145}
1146
1148{
1149 return static_cast<KisAllResourcesModel*>(sourceModel())->tagsForResource(resourceId);
1150}
float value(const T *src, size_t ch)
qreal v
QPointF q2
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
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)
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
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