12#include <QSqlDatabase>
31 : QAbstractTableModel(parent)
57 if (parent.isValid()) {
63 const bool r = q.prepare(
"SELECT COUNT(DISTINCT resource_tags.tag_id || resources.name || resources.filename || resources.md5sum)\n"
64 "FROM resource_tags\n"
67 "WHERE resource_tags.resource_id = resources.id\n"
68 "AND resources.resource_type_id = resource_types.id\n"
69 "AND resource_types.name = :resource_type\n"
70 "AND resource_tags.active = 1\n");
73 qWarning() <<
"Could not execute resource/tags rowcount query" << q.lastError();
80 qWarning() <<
"Could not execute resource/tags rowcount query" << q.lastError();
93 if (parent.isValid()) {
104 if (!index.isValid()) {
return v; }
105 if (index.row() >
rowCount()) {
return v; }
109 if (!pos) {
return v;}
111 if (role < Qt::UserRole +
TagId && index.column() <
TagId) {
115 if (role == Qt::FontRole) {
119 if (index.column() >=
TagId) {
122 role = Qt::UserRole + index.column();
127 case Qt::UserRole +
TagId:
134 v =
d->
query.value(
"resource_id");
137 case Qt::UserRole +
Tag:
140 v = QVariant::fromValue(tag);
150 v =
d->
query.value(
"resource_active");
155 v =
d->
query.value(
"tag_active");
160 v =
d->
query.value(
"resource_storage_active");
165 v =
d->
query.value(
"resource_name");
170 v =
d->
query.value(
"translated_name");
172 v =
d->
query.value(
"tag_name");
196 for (
int i = 0; i < resourceIds.count(); i++) {
199 switch (taggedState) {
202 resourceIdsToAdd.append(resourceIds[i]);
206 resourceIdsToUpdate.append(resourceIds[i]);
214 if (resourceIdsToAdd.isEmpty() && resourceIdsToUpdate.isEmpty()) {
219 int howManyTimesBeginInsertedCalled = 0;
221 if (resourceIdsToUpdate.count() > 0) {
223 QSqlQuery allIndices;
224 if (!allIndices.prepare(
createQuery(
false,
true))) {
225 qWarning() <<
"Could not prepare tagResource-allIndices query" << allIndices.lastError();
231 if (!allIndices.exec()) {
232 qWarning() <<
"Could not execute tagResource-allIndices query" << allIndices.lastError();
235 int activesRowId = -1;
236 int lastActiveRowId = -1;
239 QMap<int, int> resourcesCountForLastActiveRowId;
243 while (allIndices.next()) {
245 bool isActive = allIndices.value(
"resource_tags_pair_active").toBool();
248 lastActiveRowId = activesRowId;
250 bool variantSuccess =
true;
251 int rowTagId = allIndices.value(
"tag_id").toInt(&variantSuccess);
253 int rowResourceId = allIndices.value(
"resource_id").toInt(&variantSuccess);
255 if (rowTagId == tag->id() && resourceIdsToUpdate.contains(rowResourceId)) {
256 if (!resourcesCountForLastActiveRowId.contains(lastActiveRowId)) {
257 resourcesCountForLastActiveRowId[lastActiveRowId] = 1;
259 resourcesCountForLastActiveRowId[lastActiveRowId] = resourcesCountForLastActiveRowId[lastActiveRowId] + 1;
265 Q_FOREACH(
const int key, resourcesCountForLastActiveRowId.keys()) {
281 beginInsertRows(QModelIndex(), key + 1, key + resourcesCountForLastActiveRowId[key]);
282 howManyTimesBeginInsertedCalled++;
288 if (!q.prepare(
"UPDATE resource_tags\n"
290 "WHERE resource_id = :resource_id\n"
291 "AND tag_id = :tag_id")) {
294 qWarning() <<
"Could not prepare update resource_tags to active statement" << q.lastError();
299 QVariantList resourceIdsVariants;
300 QVariantList tagIdVariants;
302 for (
int i = 0; i < resourceIdsToUpdate.count(); i++) {
303 resourceIdsVariants << QVariant(resourceIdsToUpdate[i]);
304 tagIdVariants << QVariant(tag->id());
307 q.bindValue(
":resource_id", resourceIdsVariants);
308 q.bindValue(
":tag_id", tagIdVariants);
310 if (!q.execBatch()) {
311 qWarning() <<
"Could not execute update resource_tags to active statement" << q.lastError();
312 for (
int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
320 if (resourceIdsToAdd.count() > 0) {
322 beginInsertRows(QModelIndex(),
rowCount(),
rowCount() + resourceIdsToAdd.count() - 1);
323 howManyTimesBeginInsertedCalled++;
330 for (
int i = 0; i < resourceIdsToAdd.count(); i++) {
334 values.append(
"(?, ?, ?)");
337 if (!q.prepare(QString(
"INSERT INTO resource_tags\n"
338 "(resource_id, tag_id, active)\n"
339 "VALUES ") + values + QString(
";\n"))) {
340 qWarning() <<
"Could not prepare insert into resource tags statement" << q.lastError();
341 for (
int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
347 for (
int i = 0; i < resourceIdsToAdd.count(); i++) {
348 q.addBindValue(resourceIdsToAdd[i]);
349 q.addBindValue(tag->id());
350 q.addBindValue(
true);
355 qWarning() <<
"Could not execute insert into resource tags statement" << q.boundValues() << q.lastError();
356 for (
int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
365 for (
int i = 0; i < howManyTimesBeginInsertedCalled; i++) {
374 if (!tag || !tag->valid())
return false;
375 if (!
d->
query.isSelect())
return false;
378 int beginRemoveRowsCount = 0;
382 if (!q.prepare(
"UPDATE resource_tags\n"
384 "WHERE tag_id = :tag_id\n"
385 "AND resource_id = :resource_id")) {
386 qWarning() <<
"Could not prepare untagResource-update query" << q.lastError();
390 QSqlQuery allIndices;
391 if (!allIndices.prepare(
createQuery(
true,
true))) {
392 qWarning() <<
"Could not prepare untagResource-allIndices query " << allIndices.lastError();
398 if (!allIndices.exec()) {
399 qCritical() <<
"Could not exec untagResource-allIndices query " << allIndices.lastError();
402 int activesRowId = -1;
403 int lastActiveRowId = -1;
406 QMap<int, int> resourcesCountForLastActiveRowId;
410 while (allIndices.next()) {
412 bool variantSuccess =
true;
414 bool isActive =
true;
417 int rowTagId = allIndices.value(
"tag_id").toInt(&variantSuccess);
419 int rowResourceId = allIndices.value(
"resource_id").toInt(&variantSuccess);
422 bool willStayActive = isActive && (rowTagId != tag->id() || !resourceIds.contains(rowResourceId));
424 if (willStayActive) {
425 lastActiveRowId = activesRowId;
426 }
else if (isActive) {
428 if (!resourcesCountForLastActiveRowId.contains(lastActiveRowId)) {
429 resourcesCountForLastActiveRowId[lastActiveRowId] = 0;
431 resourcesCountForLastActiveRowId[lastActiveRowId]++;
435 Q_FOREACH(
const int key, resourcesCountForLastActiveRowId.keys()) {
452 beginRemoveRows(QModelIndex(), key + 1, key + resourcesCountForLastActiveRowId[key]);
453 beginRemoveRowsCount++;
456 QSqlDatabase::database().transaction();
457 for (
int i = 0; i < resourceIds.count(); i++) {
458 int resourceId = resourceIds[i];
460 if (resourceId < 0)
continue;
463 q.bindValue(
":tag_id", tag->id());
464 q.bindValue(
":resource_id", resourceId);
467 qWarning() <<
"Could not execute untagResource-update query" << q.lastError() << q.boundValues();
468 for (
int i = 0; i < beginRemoveRowsCount; i++) {
471 QSqlDatabase::database().rollback();
475 QSqlDatabase::database().commit();
477 if (beginRemoveRowsCount > 0) {
479 for (
int i = 0; i < beginRemoveRowsCount; i++) {
490 bool r = query.prepare(
"SELECT resource_tags.active\n"
491 "FROM resource_tags\n"
492 "WHERE resource_tags.resource_id = :resource_id\n"
493 "AND resource_tags.tag_id = :tag_id\n");
496 qWarning() <<
"Could not prepare bool KisAllTagResourceModel::checkResourceTaggedState query" << query.lastError();
500 query.bindValue(
":resource_id", resourceId);
501 query.bindValue(
":tag_id", tag->id());
504 qWarning() <<
"Could not execute is resource tagged with a specific tag query" << query.boundValues() << query.lastError();
514 return query.value(0).toInt() > 0;
536 if (resourceId < 0)
return;
544 for (
int i = 0; i <
rowCount(); ++i) {
545 const QModelIndex idx = this->index(i, 0);
553 Q_FOREACH(
const QModelIndex &index, indexes) {
560 QString query = QString(
"WITH initial_selection AS (\n"
562 " , resources.name\n"
563 " , resources.filename\n"
564 " , resources.md5sum\n"
565 " , resource_types.id as resource_type_id\n"
566 " , resource_types.name as resource_type_name\n"
567 " , min(resources.id) as resource_id\n"
568 ) + (returnADbIndexToo ? QString(
", resource_tags.id as resource_tags_row_id\n") : QString(
"")) + QString(
569 ) + (onlyActive ? QString(
"") : QString(
", resource_tags.active as resource_tags_pair_active\n")) + QString(
570 " FROM resource_types\n"
571 " JOIN resource_tags\n ON resource_tags.resource_id = resources.id\n"
572 ) + (onlyActive ? QString(
" AND resource_tags.active = 1\n") : QString(
"")) + QString(
573 " JOIN resources ON resources.resource_type_id = resource_types.id\n"
574 " JOIN tags ON tags.id = resource_tags.tag_id\n"
575 " AND tags.resource_type_id = resource_types.id\n"
576 " WHERE resource_types.name = :resource_type\n"
577 " GROUP BY tags.id\n"
578 " , resources.name\n"
579 " , resources.filename\n"
580 " , resources.md5sum\n"
581 " , resource_types.id\n"
582 " ORDER BY resource_tags.id\n"
585 " initial_selection.id as tag_id\n"
586 ", initial_selection.name as resource_name\n"
587 ", initial_selection.filename as resource_filename\n"
588 ", initial_selection.md5sum as resource_md5sum\n"
589 ", initial_selection.resource_id as resource_id\n"
590 ", tags.url as tag_url"
591 ", tags.active as tag_active"
592 ", tags.name as tag_name"
593 ", tags.comment as tag_comment"
594 ", resources.status as resource_active\n"
595 ", resources.tooltip as resource_tooltip\n"
596 ", resources.status as resource_active\n"
597 ", resources.storage_id as storage_id\n"
598 ", storages.active as resource_storage_active\n"
599 ", storages.location as location\n"
600 ", tag_translations.name as translated_name\n"
601 ", tag_translations.comment as translated_comment\n"
602 ", initial_selection.resource_type_name as resource_type\n"
603 ) + (returnADbIndexToo ? QString(
", initial_selection.resource_tags_row_id as resource_tags_row_id\n") : QString(
"")) + QString(
604 ) + (onlyActive ? QString(
"") : QString(
", initial_selection.resource_tags_pair_active as resource_tags_pair_active\n")) + QString(
605 "FROM initial_selection\n"
606 "JOIN tags ON tags.id = initial_selection.id\n"
607 " AND tags.resource_type_id = initial_selection.resource_type_id\n"
608 "JOIN resources ON resources.id = resource_id\n"
609 "JOIN storages ON storages.id = resources.storage_id\n"
610 "LEFT JOIN tag_translations ON tag_translations.tag_id = initial_selection.id\n"
611 " AND tag_translations.language = :language\n");
620 if (orientation != Qt::Horizontal) {
623 if (role != Qt::DisplayRole) {
631 return i18n(
"Storage ID");
635 return i18n(
"File Name");
637 return i18n(
"Tooltip");
639 return i18n(
"Image");
641 return i18n(
"Status");
643 return i18n(
"Location");
645 return i18n(
"Resource Type");
647 return i18n(
"Active");
649 return i18n(
"Storage Active");
651 return i18n(
"md5sum");
655 return i18n(
"Large Thumbnail");
657 return i18n(
"Dirty");
659 return i18n(
"Metadata");
661 role = Qt::UserRole + section;
667 return i18n(
"Tag ID");
669 return i18n(
"Resource ID");
671 return i18n(
"Tag Url");
673 return i18n(
"Resource");
675 return i18n(
"Resource Active");
677 return i18n(
"Tag Active");
679 return i18n(
"Storage Active");
681 return i18n(
"Resource Name");
683 return i18n(
"Tag File Name");
701 qWarning() <<
"Could not prepare KisAllTagResourcesModel query" <<
d->
query.lastError();
710 qWarning() <<
"Could not execute KisAllTagResourcesModel query" <<
d->
query.lastError();
731 : QSortFilterProxyModel(parent)
798 Q_FOREACH(
const KisTagSP tag, tags) {
799 if (tag && tag->valid() && tag->id() > -1) {
810 if (resource->valid() && resource->resourceId() > -1) {
819 QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
820 if (!idx.isValid())
return false;
856 return nameLeft.toLower() < nameRight.toLower();
868 if (
id < 1)
return nullptr;
875 if (!resource || !resource->valid() || resource->resourceId() < 0)
return QModelIndex();
877 for (
int i = 0; i < rowCount(); ++i) {
879 Q_ASSERT(idx.isValid());
884 return QModelIndex();
889 if (resourceId < 0)
return QModelIndex();
890 for (
int i = 0; i < rowCount(); ++i) {
892 Q_ASSERT(idx.isValid());
897 return QModelIndex();
920 return resourceModel.
importResource(filename, device, allowOverwrite, storageId);
940 return resourceModel.
addResource(resource, storageId);
949 if (index.isValid()) {
950 Q_EMIT dataChanged(index, index, {Qt::EditRole});
962 if (index.isValid()) {
963 Q_EMIT dataChanged(index, index, {Qt::EditRole});
975 if (index.isValid()) {
976 Q_EMIT dataChanged(index, index, {Qt::EditRole});
float value(const T *src, size_t ch)
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
@ Status
Whether the resource is active. Duplicate of ResourceActive.
@ ResourceActive
Whether the current resource is active.
@ Dirty
A dirty resource is one that has been modified locally but not saved.
@ LargeThumbnail
A larger thumbnail for displaying in a tooltip. 200x200 or so.
@ MetaData
MetaData is a map of key, value pairs that is associated with this resource.
@ StorageActive
Whether the current resource's storage is active.
KisAllTagResourceModel(const QString &resourceType, QObject *parent=0)
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
void removeStorage(const QString &location)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
int isResourceTagged(const KisTagSP tag, const int resourceId) override
isResourceTagged
void slotResourceActiveStateChanged(const QString &resourceType, int resourceId)
int columnCount(const QModelIndex &parent=QModelIndex()) const override
~KisAllTagResourceModel() override
void addStorage(const QString &location)
QString createQuery(bool onlyAchieve=true, bool returnADbIndexToo=false)
bool tagResources(const KisTagSP tag, const QVector< int > &resourceIds) override
bool untagResources(const KisTagSP tag, const QVector< int > &resourceId) override
QVariant data(const QModelIndex &index, int role) const override
Note: only role is significant, column is not.
KisTagSP tagForUrl(const QString &tagUrl, const QString resourceType)
tagForUrl create a tag from the database
KoResourceSP resourceForId(int resourceId)
resourceForId returns the resource with the given id, or 0 if no such resource exists....
static KisResourceLocator * instance()
static KisAllTagResourceModel * tagResourceModel(const QString &resourceType)
The KisResourceModel class provides the main access to resources. It is possible to filter the resour...
bool setResourceMetaData(KoResourceSP resource, QMap< QString, QVariant > metadata) override
setResourceMetaData
KoResourceSP importResourceFile(const QString &filename, const bool allowOverwrite, const QString &storageId=QString("")) override
importResourceFile
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
bool renameResource(KoResourceSP resource, const QString &name) override
renameResource name the given resource. The resource will have its name field reset,...
bool exportResource(KoResourceSP resource, QIODevice *device) override
exportResource exports a resource into a QIODevice
bool updateResource(KoResourceSP resource) override
updateResource creates a new version of the resource in the storage and in the database....
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...
QModelIndex indexForResource(KoResourceSP resource) const override
indexFromResource
bool setResourceActive(const QModelIndex &index, bool value) override
setResourceActive changes 'active' state of the resource
KoResourceSP importResource(const QString &filename, QIODevice *device, const bool allowOverwrite, const QString &storageId=QString("")) override
importResource imports a resource from a QIODevice
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()
bool setResourceMetaData(KoResourceSP resource, QMap< QString, QVariant > metadata) override
setResourceMetaData
void setResourceFilter(ResourceFilter filter) override
QModelIndex indexForResourceId(int resourceId) const override
indexFromResource
bool untagResources(const KisTagSP tag, const QVector< int > &resourceIds) override
bool setResourceActive(const QModelIndex &index, bool value) override
setResourceActive changes 'active' state of the resource
KoResourceSP importResource(const QString &filename, QIODevice *device, const bool allowOverwrite, const QString &storageId=QString()) override
importResource imports a resource from a QIODevice
bool addResource(KoResourceSP resource, const QString &storageId) override
addResource adds the given resource to the database and storage. If the resource already exists in th...
void storageChanged(const QString &location)
void setTagFilter(TagFilter filter)
~KisTagResourceModel() override
KisTagResourceModel(const QString &resourceType, QObject *parent=0)
bool tagResources(const KisTagSP tag, const QVector< int > &resourceIds) override
void setTagsFilter(const QVector< int > tagIds)
QModelIndex indexForResource(KoResourceSP resource) const override
indexFromResource
void setResourcesFilter(const QVector< int > resourceIds)
bool renameResource(KoResourceSP resource, const QString &name) override
renameResource name the given resource. The resource will have its name field reset,...
KoResourceSP importResourceFile(const QString &filename, const bool allowOverwrite, const QString &storageId=QString()) override
importResourceFile
bool reloadResource(KoResourceSP resource) override
reloadResource
int isResourceTagged(const KisTagSP tag, const int resourceId) override
isResourceTagged
bool updateResource(KoResourceSP resource) override
updateResource creates a new version of the resource in the storage and in the database....
bool importWillOverwriteResource(const QString &fileName, const QString &storageLocation) const override
importWillOverwriteResource checks is importing a resource with this filename will overwrite anything
KoResourceSP resourceForIndex(QModelIndex index) const override
resourceForIndex returns a properly versioned and id'ed resource object
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
bool exportResource(KoResourceSP resource, QIODevice *device) override
exportResource exports a resource into a QIODevice
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
void setStorageFilter(StorageFilter filter) override
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override
static QString currentLocale()
#define KIS_ASSERT_RECOVER(cond)
#define KIS_SAFE_ASSERT_RECOVER(cond)
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
StorageFilter storageFilter
QVector< int > resourceIds
ResourceFilter resourceFilter
KisAllTagResourceModel * sourceModel