diff --git a/libs/resources/KisTagModel.cpp b/libs/resources/KisTagModel.cpp index ef3defdb99..5a21a104da 100644 --- a/libs/resources/KisTagModel.cpp +++ b/libs/resources/KisTagModel.cpp @@ -1,465 +1,466 @@ /* * Copyright (c) 2018 boud + * Copyright (c) 2020 Agata Cacko * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisTagModel.h" #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(QSharedPointer) struct KisTagModel::Private { QSqlQuery query; QSqlQuery tagForResourceQuery; QString resourceType; int columnCount {5}; int cachedRowCount {-1}; int fakeRowsCount {1}; }; KisTagModel::KisTagModel(const QString &resourceType, QObject *parent) : QAbstractTableModel(parent) , d(new Private()) { d->resourceType = resourceType; if (!d->resourceType.isEmpty()) { prepareQuery(); } } KisTagModel::~KisTagModel() { delete d; } int KisTagModel::rowCount(const QModelIndex &/*parent*/) const { if (d->cachedRowCount < 0) { QSqlQuery q; q.prepare("SELECT count(*)\n" "FROM tags\n" ", resource_types\n" "WHERE active = 1\n" "AND tags.resource_type_id = resource_types.id\n" "AND resource_types.name = :resource_type\n" "AND tags.storage_id in (SELECT id\n" " FROM storages\n" " WHERE active == 1)"); q.bindValue(":resource_type", d->resourceType); q.exec(); q.first(); const_cast(this)->d->cachedRowCount = q.value(0).toInt() + d->fakeRowsCount; } return d->cachedRowCount; } int KisTagModel::columnCount(const QModelIndex &/*parent*/) const { return d->columnCount; } QVariant KisTagModel::data(const QModelIndex &index, int role) const { QVariant v; if (!index.isValid()) return v; if (index.row() > rowCount()) return v; if (index.column() > d->columnCount) return v; // The first row is All // XXX: Should we also add an "All Untagged"? if (index.row() < d->fakeRowsCount) { switch(role) { case Qt::DisplayRole: // fallthrough case Qt::ToolTipRole: // fallthrough case Qt::StatusTipRole: // fallthrough case Qt::WhatsThisRole: return i18n("All"); case Qt::UserRole + Id: return "-1"; case Qt::UserRole + Url: { return "All"; } case Qt::UserRole + ResourceType: return d->resourceType; case Qt::UserRole + Active: return true; case Qt::UserRole + KisTagRole: { KisTagSP tag = tagForIndex(index); QVariant response; response.setValue(tag); return response; } default: ; } } else { bool pos = const_cast(this)->d->query.seek(index.row() - d->fakeRowsCount); if (pos) { switch(role) { case Qt::DisplayRole: return d->query.value("name"); case Qt::ToolTipRole: // fallthrough case Qt::StatusTipRole: // fallthrough case Qt::WhatsThisRole: return d->query.value("comment"); case Qt::UserRole + Id: return d->query.value("id"); case Qt::UserRole + Url: return d->query.value("url"); case Qt::UserRole + ResourceType: return d->query.value("resource_type"); case Qt::UserRole + Active: return d->query.value("active"); case Qt::UserRole + KisTagRole: { KisTagSP tag = tagForIndex(index); QVariant response; response.setValue(tag); return response; } default: ; } } } return v; } void KisTagModel::setResourceType(const QString &resourceType) { d->resourceType = resourceType; prepareQuery(); } KisTagSP KisTagModel::tagForIndex(QModelIndex index) const { KisTagSP tag = 0; if (!index.isValid()) return tag; if (index.row() > rowCount()) return tag; if (index.column() > columnCount()) return tag; if (index.row() < d->fakeRowsCount) { tag.reset(new KisTag()); tag->setName("All"); tag->setUrl("All"); tag->setComment("All"); tag->setId(-1); tag->setActive(true); tag->setValid(true); } else { bool pos = const_cast(this)->d->query.seek(index.row() - d->fakeRowsCount); if (pos) { tag.reset(new KisTag()); tag->setUrl(d->query.value("url").toString()); tag->setName(d->query.value("name").toString()); tag->setComment(d->query.value("comment").toString()); tag->setId(d->query.value("id").toInt()); tag->setActive(d->query.value("active").toBool()); tag->setValid(true); } } return tag; } bool KisTagModel::addTag(const KisTagSP tag, QVector taggedResouces) { if (tag.isNull()) return false; if (!tag) return false; if (!tag->valid()) return false; // A new tag doesn't have an ID yet, that comes from the database if (tag->id() >= 0) return false; if (!KisResourceCacheDb::hasTag(tag->url(), d->resourceType)) { if (!KisResourceCacheDb::addTag(d->resourceType, "", tag->url(), tag->name(), tag->comment())) { qWarning() << "Could not add tag" << tag; return false; } } else { QSqlQuery q; if (!q.prepare("UPDATE tags\n" "SET active = 1\n" "WHERE url = :url\n" "AND resource_type_id = (SELECT id\n" " FROM resource_types\n" " WHERE name = :resource_type\n)")) { qWarning() << "Couild not prepare make existing tag active query" << tag << q.lastError(); return false; } q.bindValue(":url", tag->url()); q.bindValue(":resource_type", d->resourceType); if (!q.exec()) { qWarning() << "Couild not execute make existing tag active query" << q.boundValues(), q.lastError(); return false; } } Q_FOREACH(const KoResourceSP resource, taggedResouces) { if (!resource) continue; if (!resource->valid()) continue; if (resource->resourceId() < 0) continue; tagResource(tag, resource); } return prepareQuery(); } bool KisTagModel::removeTag(const KisTagSP tag) { if (!tag) return false; if (!tag->valid()) return false; if (tag->id() < 0) return false; QSqlQuery q; if (!q.prepare("UPDATE tags\n" "SET active = 0\n" "WHERE id = :id")) { qWarning() << "Could not prepare remove tag query" << q.lastError(); return false; } q.bindValue(":id", tag->id()); if (!q.exec()) { qWarning() << "Could not execute remove tag query" << q.lastError(); return false; } // reset tags-resources model KisTagsResourcesModelProvider::getModel(d->resourceType)->resetQuery(); return prepareQuery(); } bool KisTagModel::tagResource(const KisTagSP tag, const KoResourceSP resource) { return KisTagsResourcesModelProvider::getModel(d->resourceType)->tagResource(tag, resource); /* if (!tag) return false; if (!tag->valid()) return false; if (tag->id() < 0) return false; if (!resource) return false; if (!resource->valid()) return false; if (resource->resourceId() < 0) return false; QSqlQuery q; bool r = q.prepare("INSERT INTO resource_tags\n" "(resource_id, tag_id)\n" "VALUES\n" "( (SELECT id\n" " FROM resources\n" " WHERE id = :resource_id)\n" ", (SELECT id\n" " FROM tags\n" " WHERE url = :url\n" " AND name = :name\n" " AND comment = :comment\n" " AND resource_type_id = (SELECT id\n" " FROM resource_types\n" " WHERE name = :resource_type" " \n)" " )\n" ")\n"); if (!r) { qWarning() << "Could not prepare insert into resource tags statement" << q.lastError(); return false; } q.bindValue(":resource_id", resource->resourceId()); q.bindValue(":url", tag->url()); q.bindValue(":name", tag->name()); q.bindValue(":comment", tag->comment()); q.bindValue(":resource_type", d->resourceType); if (!q.exec()) { qWarning() << "Could not execute insert into resource tags statement" << q.boundValues() << q.lastError(); return false; } return prepareQuery(); */ } bool KisTagModel::untagResource(const KisTagSP tag, const KoResourceSP resource) { return KisTagsResourcesModelProvider::getModel(d->resourceType)->untagResource(tag, resource); /* if (!tag) return false; if (!tag->valid()) return false; if (!tag->id()) return false; if (!resource) return false; if (!resource->valid()) return false; if (resource->resourceId() < 0) return false; // we need to delete an entry in resource_tags bool r = d->query.prepare("DELETE FROM resource_tags\n" "WHERE resource_id = :resource_id\n" "AND tag_id = :tag_id"); if (!r) { qWarning() << "Could not prepare KisTagModel query" << d->query.lastError(); } d->query.bindValue(":resource_id", resource->resourceId()); d->query.bindValue(":tag_id", tag->id()); r = d->query.exec(); if (!r) { qWarning() << "Could not select tags" << d->query.lastError(); } return prepareQuery(); */ } bool KisTagModel::renameTag(const KisTagSP tag, const QString &name) { if (!tag) return false; if (!tag->valid()) return false; if (name.isEmpty()) return false; QSqlQuery q; if (!q.prepare("UPDATE tags\n" "SET name = :name\n" "WHERE url = :url\n" "AND resource_type_id = (SELECT id\n" " FROM resource_types\n" " WHERE name = :resource_type\n)")) { qWarning() << "Couild not prepare make existing tag active query" << tag << q.lastError(); return false; } q.bindValue(":name", name); q.bindValue(":url", tag->url()); q.bindValue(":resource_type", d->resourceType); if (!q.exec()) { qWarning() << "Couild not execute make existing tag active query" << q.boundValues(), q.lastError(); return false; } return prepareQuery(); } QVector KisTagModel::tagsForResource(int resourceId) const { return KisTagsResourcesModelProvider::getModel(d->resourceType)->tagsForResource(resourceId); /* d->tagForResourceQuery.bindValue(":resource_id", resourceId); bool r = d->tagForResourceQuery.exec(); if (!r) { qWarning() << "Could not select tags for" << resourceId << d->tagForResourceQuery.lastError() << d->tagForResourceQuery.boundValues(); } QVector tags; while (d->tagForResourceQuery.next()) { //qDebug() << d->tagQuery.value(0).toString() << d->tagQuery.value(1).toString() << d->tagQuery.value(2).toString(); KisTagSP tag(new KisTag()); tag->setId(d->tagForResourceQuery.value("id").toInt()); tag->setUrl(d->tagForResourceQuery.value("url").toString()); tag->setName(d->tagForResourceQuery.value("name").toString()); tag->setComment(d->tagForResourceQuery.value("comment").toString()); tag->setValid(true); tag->setActive(true); tags << tag; } return tags; */ } bool KisTagModel::prepareQuery() { beginResetModel(); bool r = d->query.prepare("SELECT tags.id\n" ", tags.url\n" ", tags.name\n" ", tags.comment\n" ", resource_types.name as resource_type\n" "FROM tags\n" ", resource_types\n" "WHERE tags.resource_type_id = resource_types.id\n" "AND resource_types.name = :resource_type\n" "AND tags.active = 1\n" "AND tags.storage_id in (SELECT id\n" " FROM storages\n" " WHERE active == 1)"); if (!r) { qWarning() << "Could not prepare KisTagModel query" << d->query.lastError(); } d->query.bindValue(":resource_type", d->resourceType); r = d->query.exec(); if (!r) { qWarning() << "Could not select tags" << d->query.lastError(); } r = d->tagForResourceQuery.prepare("SELECT tags.id\n" ", tags.url\n" ", tags.name\n" ", tags.comment\n" "FROM tags\n" ", resource_tags\n" "WHERE tags.active > 0\n" // make sure the tag is active "AND tags.id = resource_tags.tag_id\n" // join tags + resource_tags by tag_id "AND resource_tags.resource_id = :resource_id\n"); // make sure we're looking for tags for a specific resource if (!r) { qWarning() << "Could not prepare TagsForResource query" << d->tagForResourceQuery.lastError(); } KisTagsResourcesModelProvider::resetModel(d->resourceType); d->cachedRowCount = -1; endResetModel(); return r; } diff --git a/libs/resources/KisTagModel.h b/libs/resources/KisTagModel.h index 3f83491ce3..895ea038c2 100644 --- a/libs/resources/KisTagModel.h +++ b/libs/resources/KisTagModel.h @@ -1,87 +1,88 @@ /* * Copyright (c) 2018 boud + * Copyright (c) 2020 Agata Cacko * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KISTAGMODEL_H #define KISTAGMODEL_H #include #include #include #include #include "kritaresources_export.h" class KRITARESOURCES_EXPORT KisTagModel : public QAbstractTableModel { Q_OBJECT private: KisTagModel(const QString &resourceType, QObject *parent = 0); public: enum Columns { Id = 0, Url, Name, Comment, ResourceType, Active, KisTagRole, }; ~KisTagModel() override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role) const override; // KisTagModel API KisTagSP tagForIndex(QModelIndex index = QModelIndex()) const; QList allTags() const; bool addTag(const KisTagSP tag, QVector taggedResouces = QVector()); bool removeTag(const KisTagSP tag); bool tagResource(const KisTagSP tag, const KoResourceSP resource); bool untagResource(const KisTagSP tag, const KoResourceSP resource); bool renameTag(const KisTagSP tag, const QString &name); QVector tagsForResource(int resourceId) const; private: friend class DlgDbExplorer; friend class KisTagModelProvider; friend class TestTagModel; void setResourceType(const QString &resourceType); bool prepareQuery(); struct Private; Private* const d; }; typedef QSharedPointer KisTagModelSP; #endif // KISTAGMODEL_H diff --git a/libs/resourcewidgets/KisResourceItemChooserContextMenu.cpp b/libs/resourcewidgets/KisResourceItemChooserContextMenu.cpp index ad84439c29..857452a104 100644 --- a/libs/resourcewidgets/KisResourceItemChooserContextMenu.cpp +++ b/libs/resourcewidgets/KisResourceItemChooserContextMenu.cpp @@ -1,302 +1,303 @@ /* This file is part of the KDE project * Copyright (c) 2013 Sascha Suelzer + * Copyright (c) 2020 Agata Cacko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * */ #include "KisResourceItemChooserContextMenu.h" #include #include #include #include #include #include #include #include #include #include "kis_debug.h" KoLineEditAction::KoLineEditAction(QObject* parent) : QWidgetAction(parent) , m_closeParentOnTrigger(false) { fprintf(stderr, "created a new KoLineEditAction\n"); QWidget* pWidget = new QWidget (0); QHBoxLayout* pLayout = new QHBoxLayout(); m_label = new QLabel(0); m_editBox = new QLineEdit(0); m_editBox->setClearButtonEnabled(true); m_AddButton = new QPushButton(); m_AddButton->setIcon(koIcon("list-add")); pLayout->addWidget(m_label); pLayout->addWidget(m_editBox); pLayout->addWidget(m_AddButton); pWidget->setLayout(pLayout); setDefaultWidget(pWidget); connect (m_editBox, &QLineEdit::returnPressed, this, &KoLineEditAction::onTriggered); connect (m_AddButton, &QPushButton::clicked, this, &KoLineEditAction::onTriggered); } KoLineEditAction::~KoLineEditAction() { } void KoLineEditAction::setIcon(const QIcon &icon) { QPixmap pixmap = QPixmap(icon.pixmap(16,16)); m_label->setPixmap(pixmap); } void KoLineEditAction::closeParentOnTrigger(bool closeParent) { m_closeParentOnTrigger = closeParent; } bool KoLineEditAction::closeParentOnTrigger() { return m_closeParentOnTrigger; } void KoLineEditAction::onTriggered() { ENTER_FUNCTION(); fprintf(stderr, "void KoLineEditAction::onTriggered()"); if (! m_editBox->text().isEmpty()) { KisTagSP tag(new KisTag()); tag->setName(m_editBox->text()); tag->setUrl(m_editBox->text()); emit triggered(tag); m_editBox->text().clear(); if (m_closeParentOnTrigger) { this->parentWidget()->close(); m_editBox->clearFocus(); } } } void KoLineEditAction::setPlaceholderText(const QString& clickMessage) { m_editBox->setPlaceholderText(clickMessage); } void KoLineEditAction::setText(const QString& text) { ENTER_FUNCTION(); m_editBox->setText(text); } void KoLineEditAction::setVisible(bool showAction) { QLayout* currentLayout = defaultWidget()->layout(); this->QAction::setVisible(showAction); for(int i=0;icount();i++) { currentLayout->itemAt(i)->widget()->setVisible(showAction); } defaultWidget()->setVisible(showAction); } ContextMenuExistingTagAction::ContextMenuExistingTagAction(KoResourceSP resource, KisTagSP tag, QObject* parent) : QAction(parent) , m_resource(resource) , m_tag(tag) { fprintf(stderr, "ContextMenuExistingTagAction created for: %s\n", tag->name().toUtf8().toStdString().c_str()); setText(tag->name()); connect (this, SIGNAL(triggered()), this, SLOT(onTriggered())); } ContextMenuExistingTagAction::~ContextMenuExistingTagAction() { } void ContextMenuExistingTagAction::onTriggered() { fprintf(stderr, "void ContextMenuExistingTagAction::onTriggered()\n"); ENTER_FUNCTION(); emit triggered(m_resource, m_tag); } NewTagAction::~NewTagAction() { } NewTagAction::NewTagAction(KoResourceSP resource, QMenu* parent) :KoLineEditAction (parent) { fprintf(stderr, "NewTagAction created\n"); m_resource = resource; setIcon(koIcon("document-new")); setPlaceholderText(i18n("New tag")); closeParentOnTrigger(true); connect (this, SIGNAL(triggered(KisTagSP)), this, SLOT(onTriggered(KisTagSP))); } void NewTagAction::onTriggered(const KisTagSP tag) { emit triggered(m_resource,tag); } class CompareWithOtherTagFunctor { KisTagSP m_referenceTag; public: CompareWithOtherTagFunctor(KisTagSP referenceTag) { m_referenceTag = referenceTag; } bool operator()(KisTagSP otherTag) { return !otherTag.isNull() && otherTag->url() == m_referenceTag->url(); } }; bool compareWithSpecialTags(KisTagSP tag) { // TODO: RESOURCES: id < 0? For now, "All" fits return !tag.isNull() && tag->id() < 0; } KisResourceItemChooserContextMenu::KisResourceItemChooserContextMenu(KoResourceSP resource, const KisTagSP currentlySelectedTag) { QImage image = resource->image(); QIcon icon(QPixmap::fromImage(image)); QAction * label = new QAction(resource->name(), this); label->setIcon(icon); addAction(label); QMenu * removableTagsMenu; QMenu * assignableTagsMenu; KisTagsResourcesModel* model = KisTagsResourcesModelProvider::getModel(resource->resourceType().first); KisTagModel* tagModel = KisTagModelProvider::tagModel(resource->resourceType().first); QList removables = model->tagsForResource(resource->resourceId()).toList(); QList list; for (int i = 0; i < tagModel->rowCount(); i++) { QModelIndex index = tagModel->index(i, 0); KisTagSP tag = tagModel->tagForIndex(index); if (!tag.isNull()) { list << tag; } } QList assignables2 = list; CompareWithOtherTagFunctor comparer(currentlySelectedTag); //std::sort(removables.begin(), removables.end(), KisTag::compareNamesAndUrls); //std::sort(assignables2.begin(), assignables2.end(), KisTag::compareNamesAndUrls); bool currentTagInRemovables = !currentlySelectedTag.isNull(); currentTagInRemovables = currentTagInRemovables && (std::find_if(removables.begin(), removables.end(), comparer) != removables.end()); // remove "All" tag from both "Remove from this tag" and "Assign to this tag" list std::remove_if(removables.begin(), removables.end(), compareWithSpecialTags); std::remove_if(assignables2.begin(), assignables2.end(), compareWithSpecialTags); assignableTagsMenu = addMenu(koIcon("list-add"),i18n("Assign to tag")); if (!removables.isEmpty()) { addSeparator(); KisTagSP currentTag = currentlySelectedTag; if (!currentTag.isNull() && currentTagInRemovables) { std::remove_if(removables.begin(), removables.end(), comparer); std::remove_if(assignables2.begin(), assignables2.end(), comparer); ContextMenuExistingTagAction * removeTagAction = new ContextMenuExistingTagAction(resource, currentTag, this); removeTagAction->setText(i18n("Remove from this tag")); removeTagAction->setIcon(koIcon("list-remove")); connect(removeTagAction, SIGNAL(triggered(KoResourceSP, const KisTagSP)), this, SIGNAL(resourceTagRemovalRequested(KoResourceSP, const KisTagSP))); addAction(removeTagAction); } if (!removables.isEmpty()) { removableTagsMenu = addMenu(koIcon("list-remove"),i18n("Remove from other tag")); foreach (const KisTagSP tag, removables) { std::remove_if(assignables2.begin(), assignables2.end(), comparer); if (tag.isNull()) { continue; } ContextMenuExistingTagAction * removeTagAction = new ContextMenuExistingTagAction(resource, tag, this); connect(removeTagAction, SIGNAL(triggered(KoResourceSP, const KisTagSP)), this, SIGNAL(resourceTagRemovalRequested(KoResourceSP, const KisTagSP))); removableTagsMenu->addAction(removeTagAction); } } } foreach (const KisTagSP &tag, assignables2) { if (tag.isNull()) { continue; } ContextMenuExistingTagAction * addTagAction = new ContextMenuExistingTagAction(resource, tag, this); connect(addTagAction, SIGNAL(triggered(KoResourceSP, const KisTagSP)), this, SIGNAL(resourceTagAdditionRequested(KoResourceSP, const KisTagSP))); assignableTagsMenu->addAction(addTagAction); } assignableTagsMenu->addSeparator(); NewTagAction * addTagAction = new NewTagAction(resource, this); connect(addTagAction, SIGNAL(triggered(KoResourceSP, const KisTagSP)), this, SIGNAL(resourceAssignmentToNewTagRequested(KoResourceSP, const KisTagSP))); assignableTagsMenu->addAction(addTagAction); } KisResourceItemChooserContextMenu::~KisResourceItemChooserContextMenu() { } diff --git a/libs/resourcewidgets/KisResourceItemChooserContextMenu.h b/libs/resourcewidgets/KisResourceItemChooserContextMenu.h index 7435346b7a..4c39f31ce4 100644 --- a/libs/resourcewidgets/KisResourceItemChooserContextMenu.h +++ b/libs/resourcewidgets/KisResourceItemChooserContextMenu.h @@ -1,117 +1,118 @@ /* * This file is part of the KDE project * Copyright (c) 2013 Sascha Suelzer * Copyright (c) 2019 Boudewijn Rempt + * Copyright (c) 2020 Agata Cacko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * */ #ifndef KISRESOURCEITEMCHOOSERCONTEXTMENU_H #define KISRESOURCEITEMCHOOSERCONTEXTMENU_H #include #include #include #include #include #include #include class ContextMenuExistingTagAction : public QAction { Q_OBJECT public: explicit ContextMenuExistingTagAction( KoResourceSP resource, KisTagSP tag, QObject* parent = 0); ~ContextMenuExistingTagAction() override; Q_SIGNALS: void triggered(KoResourceSP resource, KisTagSP tag); protected Q_SLOTS: void onTriggered(); private: KoResourceSP m_resource; KisTagSP m_tag; }; /*! * A line edit QWidgetAction. * Default behavior: Closes its parent upon triggering. */ class KoLineEditAction : public QWidgetAction { Q_OBJECT public: explicit KoLineEditAction(QObject* parent); ~KoLineEditAction() override; void setIcon(const QIcon &icon); void closeParentOnTrigger(bool closeParent); bool closeParentOnTrigger(); void setPlaceholderText(const QString& clickMessage); void setText(const QString& text); void setVisible(bool showAction); Q_SIGNALS: void triggered(const KisTagSP tag); protected Q_SLOTS: void onTriggered(); private: bool m_closeParentOnTrigger; QLabel * m_label; QLineEdit * m_editBox; QPushButton * m_AddButton; }; class NewTagAction : public KoLineEditAction { Q_OBJECT public: explicit NewTagAction (KoResourceSP resource, QMenu* parent); ~NewTagAction() override; Q_SIGNALS: void triggered(KoResourceSP resource, const KisTagSP tag); protected Q_SLOTS: void onTriggered(const KisTagSP tagName); private: KoResourceSP m_resource; }; class KisResourceItemChooserContextMenu : public QMenu { Q_OBJECT public: explicit KisResourceItemChooserContextMenu(KoResourceSP resource, const KisTagSP currentlySelectedTag); ~KisResourceItemChooserContextMenu() override; Q_SIGNALS: /// Emitted when a resource should be added to an existing tag. void resourceTagAdditionRequested(KoResourceSP resource, const KisTagSP tag); /// Emitted when a resource should be removed from an existing tag. void resourceTagRemovalRequested(KoResourceSP resource, const KisTagSP tag); /// Emitted when a resource should be added to a new tag, which will need to be created. void resourceAssignmentToNewTagRequested(KoResourceSP resource, const KisTagSP tag); }; #endif // KORESOURCEITEMCHOOSERCONTEXTMENU_H diff --git a/libs/resourcewidgets/KisResourceTaggingManager.cpp b/libs/resourcewidgets/KisResourceTaggingManager.cpp index bec4c96dcd..ae03398cec 100644 --- a/libs/resourcewidgets/KisResourceTaggingManager.cpp +++ b/libs/resourcewidgets/KisResourceTaggingManager.cpp @@ -1,380 +1,380 @@ /* * This file is part of the KDE project * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Jan Hambrecht * Copyright (c) 2007 Sven Langkamp * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2011 José Luis Vergara * Copyright (c) 2013 Sascha Suelzer - * + * Copyright (c) 2020 Agata Cacko * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisResourceTaggingManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisTagFilterWidget.h" #include "KisTagChooserWidget.h" #include "KisResourceItemChooserContextMenu.h" #include "kis_debug.h" #include "KisTag.h" class TaggedResourceSet { public: TaggedResourceSet() {} TaggedResourceSet(const QString& tagName, const QList& resources) : tagName(tagName) , resources(resources) {} QString tagName; QList resources; }; class KisResourceTaggingManager::Private { public: KisTagSP currentTag; KisTagChooserWidget *tagChooser; KisTagFilterWidget *tagFilter; QCompleter *tagCompleter; QPointer model; KisTagModel* tagModel; KisResourceModel* resourceSourceModel; }; KisResourceTaggingManager::KisResourceTaggingManager(QString resourceType, KisTagFilterResourceProxyModel *model, QWidget *parent) : QObject(parent) , d(new Private()) { d->model = model; d->tagModel = KisTagModelProvider::tagModel(resourceType); d->resourceSourceModel = KisResourceModelProvider::resourceModel(resourceType); d->tagChooser = new KisTagChooserWidget(d->tagModel, parent); d->tagFilter = new KisTagFilterWidget(d->tagModel, parent); connect(d->tagChooser, SIGNAL(tagChosen(KisTagSP)), this, SLOT(tagChooserIndexChanged(KisTagSP))); connect(d->tagChooser, SIGNAL(newTagRequested(KisTagSP)), this, SLOT(contextCreateNewTag(KisTagSP))); connect(d->tagChooser, SIGNAL(tagDeletionRequested(KisTagSP)), this, SLOT(removeTagFromComboBox(KisTagSP))); connect(d->tagChooser, SIGNAL(tagRenamingRequested(KisTagSP,KisTagSP)), this, SLOT(renameTag(KisTagSP,KisTagSP))); connect(d->tagChooser, SIGNAL(tagUndeletionRequested(KisTagSP)), this, SLOT(undeleteTag(KisTagSP))); connect(d->tagChooser, SIGNAL(tagUndeletionListPurgeRequested()), this, SLOT(purgeTagUndeleteList())); connect(d->tagFilter, SIGNAL(saveButtonClicked()), this, SLOT(tagSaveButtonPressed())); connect(d->tagFilter, SIGNAL(filterTextChanged(QString)), this, SLOT(tagSearchLineEditTextChanged(QString))); syncTagBoxEntries(); } KisResourceTaggingManager::~KisResourceTaggingManager() { delete d; } void KisResourceTaggingManager::showTaggingBar(bool show) { show ? d->tagFilter->show() : d->tagFilter->hide(); show ? d->tagChooser->show() : d->tagChooser->hide(); } void KisResourceTaggingManager::purgeTagUndeleteList() { ENTER_FUNCTION(); //d->lastDeletedTag = TaggedResourceSet(); //d->tagChooser->setUndeletionCandidate(QString()); } void KisResourceTaggingManager::undeleteTag(const KisTagSP tagToUndelete) { ENTER_FUNCTION(); /* QString tagName = tagToUndelete; QStringList allTags = availableTags(); if (allTags.contains(tagName)) { bool ok; tagName = QInputDialog::getText( d->tagChooser, i18n("Unable to undelete tag"), i18n("The tag you are trying to undelete already exists in tag list.
Please enter a new, unique name for it.
"), QLineEdit::Normal, tagName, &ok); if (!ok || allTags.contains(tagName) || tagName.isEmpty()) { QMessageBox msgBox; msgBox.setIcon(QMessageBox::Warning); msgBox.setText(i18n("Tag was not undeleted.")); msgBox.exec(); return; } } // QList serverResources = d->model->serverResources(); // Q_FOREACH(KoResourceSP resource, d->lastDeletedTag.resources) { // if (serverResources.contains(resource)) { // addResourceTag(resource, tagName); // } // } // d->model->tagCategoryAdded(tagName); d->tagChooser->setCurrentIndex(d->tagChooser->findIndexOf(tagName)); d->tagChooser->setUndeletionCandidate(QString()); // d->lastDeletedTag = TaggedResourceSet(); */ } void KisResourceTaggingManager::addResourceTag(KoResourceSP resource, const KisTagSP tag) { d->tagModel->tagResource(tag, resource); } void KisResourceTaggingManager::syncTagBoxEntryAddition(const KisTagSP tag) { ENTER_FUNCTION(); //d->tagChooser->insertItem(tag); } void KisResourceTaggingManager::contextCreateNewTag(const KisTagSP tag) { fprintf(stderr, "void KisResourceTaggingManager::contextCreateNewTag(const KisTagSP tag)"); ENTER_FUNCTION(); /* if (!tag.isEmpty()) { // d->model->addTag(0, tag); // d->model->tagCategoryAdded(tag); d->tagChooser->setCurrentIndex(d->tagChooser->findIndexOf(tag)); updateTaggedResourceView(); } */ } void KisResourceTaggingManager::contextCreateNewTag(KoResourceSP resource , const KisTagSP tag) { // TODO: RESOURCES: this function should use QString, not KisTagSP fprintf(stderr, "void KisResourceTaggingManager::contextCreateNewTag(KoResourceSP resource , const KisTagSP tag)"); KisTagSP inserted = d->tagChooser->insertItem(tag); int previousIndex = d->tagChooser->currentIndex(); d->tagModel->tagResource(inserted, resource); d->tagChooser->setCurrentIndex(previousIndex); } void KisResourceTaggingManager::syncTagBoxEntryRemoval(const KisTagSP tag) { ENTER_FUNCTION(); //d->tagChooser->removeItem(tag); } void KisResourceTaggingManager::syncTagBoxEntries() { ENTER_FUNCTION(); /* QList tags = d->tagModel->allTags(); tags.sort(); Q_FOREACH (const KisTagSP &tag, tags) { //d->tagChooser->insertItem(tag); } */ } void KisResourceTaggingManager::contextAddTagToResource(KoResourceSP resource, const KisTagSP tag) { fprintf(stderr, "void KisResourceTaggingManager::contextAddTagToResource(KoResourceSP resource, const KisTagSP tag)"); ENTER_FUNCTION(); addResourceTag(resource, tag); updateTaggedResourceView(); } void KisResourceTaggingManager::contextRemoveTagFromResource(KoResourceSP resource, const KisTagSP tag) { fprintf(stderr, "void KisResourceTaggingManager::contextRemoveTagFromResource(KoResourceSP resource, const KisTagSP tag)"); ENTER_FUNCTION(); removeResourceTag(resource, tag); updateTaggedResourceView(); } void KisResourceTaggingManager::removeTagFromComboBox(const KisTagSP tag) { fprintf(stderr, "void KisResourceTaggingManager::removeTagFromComboBox(const KisTagSP tag)"); ENTER_FUNCTION(); // QList resources = d->model->currentlyVisibleResources(); // Q_FOREACH (KoResourceSP resource, resources) { // removeResourceTag(resource, tag); // } // d->model->tagCategoryRemoved(tag); // d->lastDeletedTag = TaggedResourceSet(tag, resources); // d->tagChooser->setUndeletionCandidate(tag); } void KisResourceTaggingManager::removeResourceTag(KoResourceSP resource, const KisTagSP tag) { ENTER_FUNCTION(); int previousIndex = d->tagChooser->currentIndex(); bool success = d->tagModel->untagResource(tag, resource); fprintf(stderr, "remove Resource tag: %d\n", success); d->tagChooser->setCurrentIndex(previousIndex); } void KisResourceTaggingManager::renameTag(const KisTagSP oldTag, const KisTagSP newName) { ENTER_FUNCTION(); //d->tagModel // if (!d->model->tagNamesList().contains(newName)) { // QList resources = d->model->currentlyVisibleResources(); // Q_FOREACH (KoResourceSP resource, resources) { // removeResourceTag(resource, oldName); // addResourceTag(resource, newName); // } // contextCreateNewTag(newName); // d->model->tagCategoryRemoved(oldName); // d->model->tagCategoryAdded(newName); // } } void KisResourceTaggingManager::updateTaggedResourceView() { ENTER_FUNCTION(); // d->model->setCurrentTag(d->currentTag); // d->model->updateServer(); // d->originalResources = d->model->currentlyVisibleResources(); emit updateView(); } void KisResourceTaggingManager::tagChooserIndexChanged(const KisTagSP tag) { ENTER_FUNCTION(); d->model->setTag(tag); d->currentTag = tag; /* if (!d->tagChooser->selectedTagIsReadOnly()) { d->currentTag = d->tagChooser->currentlySelectedTag(); d->tagFilter->allowSave(true); // d->model->enableResourceFiltering(true); } else { // d->model->enableResourceFiltering(false); d->tagFilter->allowSave(false); d->currentTag.clear(); } */ d->tagFilter->clear(); d->tagFilter->allowSave(tag->id() >= 0); // disallow save if the chosen tag has negative id (i.e. 'All' tag) updateTaggedResourceView(); } void KisResourceTaggingManager::tagSearchLineEditTextChanged(const QString& lineEditText) { fprintf(stderr, "void KisResourceTaggingManager::tagSearchLineEditTextChanged(const QString& lineEditText): %s \n", lineEditText.toStdString().c_str()); d->model->setSearchBoxText(lineEditText); ENTER_FUNCTION() << ppVar(lineEditText); emit updateView(); } void KisResourceTaggingManager::tagSaveButtonPressed() { fprintf(stderr, "void KisResourceTaggingManager::tagSaveButtonPressed()\n"); int previousTagIndex = d->tagChooser->currentIndex(); KisTagSP tag = d->tagChooser->currentlySelectedTag(); // untag all previous resources int allResources = d->resourceSourceModel->rowCount(); for (int i = 0; i < allResources; i++) { QModelIndex index = d->resourceSourceModel->index(i, 0); KoResourceSP resource = d->resourceSourceModel->resourceForIndex(index); QVector tags = d->resourceSourceModel->tagsForResource(resource->resourceId()); QVector::iterator iter = std::find_if(tags.begin(), tags.end(), [tag](KisTagSP tagFromResource) { return tagFromResource->url() == tag->url(); }); if (iter != tags.end()) { d->tagModel->untagResource(tag, resource); } } // tag all resources that are here now int rows = d->model->rowCount(); for (int i = 0; i < rows; i++) { QModelIndex index = d->model->index(i, 0); KoResourceSP resource = d->model->resourceForIndex(index); if (!tag.isNull() && !resource.isNull()) { d->tagModel->tagResource(tag, resource); } } d->tagChooser->setCurrentIndex(previousTagIndex); ENTER_FUNCTION(); updateTaggedResourceView(); } void KisResourceTaggingManager::contextMenuRequested(KoResourceSP resource, QPoint pos) { ENTER_FUNCTION(); // No visible tag chooser usually means no intended tag interaction, // context menu makes no sense then either fprintf(stderr, "context menu requested!"); if (!resource || !d->tagChooser->isVisible()) return; KisResourceItemChooserContextMenu menu(resource, d->tagChooser->currentlySelectedTag()); connect(&menu, SIGNAL(resourceTagAdditionRequested(KoResourceSP,const KisTagSP)), this, SLOT(contextAddTagToResource(KoResourceSP,const KisTagSP))); connect(&menu, SIGNAL(resourceTagRemovalRequested(KoResourceSP,const KisTagSP)), this, SLOT(contextRemoveTagFromResource(KoResourceSP,const KisTagSP))); connect(&menu, SIGNAL(resourceAssignmentToNewTagRequested(KoResourceSP,const KisTagSP)), this, SLOT(contextCreateNewTag(KoResourceSP,const KisTagSP))); menu.exec(pos); } KisTagChooserWidget *KisResourceTaggingManager::tagChooserWidget() { return d->tagChooser; } KisTagFilterWidget *KisResourceTaggingManager::tagFilterWidget() { return d->tagFilter; } diff --git a/libs/resourcewidgets/KisResourceTaggingManager.h b/libs/resourcewidgets/KisResourceTaggingManager.h index 7cbb980b67..21b8cae92b 100644 --- a/libs/resourcewidgets/KisResourceTaggingManager.h +++ b/libs/resourcewidgets/KisResourceTaggingManager.h @@ -1,102 +1,103 @@ /* * This file is part of the KDE project * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Jan Hambrecht * Copyright (c) 2007 Sven Langkamp * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2011 José Luis Vergara * Copyright (c) 2013 Sascha Suelzer * Copyright (c) 2019 Boudewijn Rempt + * Copyright (c) 2020 Agata Cacko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KISRESOURCETAGGINGMANAGER_H #define KISRESOURCETAGGINGMANAGER_H #include #include #include #include #include #include class QWidget; class QStringList; class QString; class QPoint; class KisTagFilterWidget; class KisTagChooserWidget; class KisTagFilterResourceProxyModel; /** * @brief The KisResourceTaggingManager class is ... * * XXX: this needs to be documented! */ class KisResourceTaggingManager : public QObject { Q_OBJECT public: explicit KisResourceTaggingManager(QString resourceType, KisTagFilterResourceProxyModel *model, QWidget *parent); ~KisResourceTaggingManager() override; void showTaggingBar(bool show); void contextMenuRequested(KoResourceSP currentResource, QPoint pos); void allowTagModification( bool set ); bool allowTagModification(); KisTagFilterWidget *tagFilterWidget(); KisTagChooserWidget *tagChooserWidget(); Q_SIGNALS: void updateView(); private Q_SLOTS: void undeleteTag(const KisTagSP tagToUndelete); void purgeTagUndeleteList(); void contextCreateNewTag(KoResourceSP resource, const KisTagSP tag); void contextCreateNewTag(const KisTagSP tag); void syncTagBoxEntryRemoval(const KisTagSP tag); void syncTagBoxEntryAddition(const KisTagSP tag); void syncTagBoxEntries(); void tagSaveButtonPressed(); void contextRemoveTagFromResource(KoResourceSP resource, const KisTagSP tag); void contextAddTagToResource(KoResourceSP resource, const KisTagSP tag); void renameTag(const KisTagSP oldName, const KisTagSP newName); void tagChooserIndexChanged(const KisTagSP lineEditText); void tagSearchLineEditTextChanged(const QString &lineEditText); void removeTagFromComboBox(const KisTagSP tag); private: void enableContextMenu(bool enable); void removeResourceTag(KoResourceSP resource, const KisTagSP tagName); void addResourceTag(KoResourceSP resource, const KisTagSP tagName); void updateTaggedResourceView(); class Private; Private* const d; }; #endif // KORESOURCETAGGINGINTERFACE_H diff --git a/libs/resourcewidgets/KisTagChooserWidget.cpp b/libs/resourcewidgets/KisTagChooserWidget.cpp index 58c8180a14..00169ef95c 100644 --- a/libs/resourcewidgets/KisTagChooserWidget.cpp +++ b/libs/resourcewidgets/KisTagChooserWidget.cpp @@ -1,265 +1,266 @@ /* * This file is part of the KDE project * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Jan Hambrecht * Copyright (c) 2007 Sven Langkamp * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2011 José Luis Vergara * Copyright (c) 2013 Sascha Suelzer + * Copyright (c) 2020 Agata Cacko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisTagChooserWidget.h" #include #include #include #include #include #include #include #include "KisResourceItemChooserContextMenu.h" #include "KisTagToolButton.h" #include "kis_debug.h" #include class Q_DECL_HIDDEN KisTagChooserWidget::Private { public: QComboBox *comboBox; KisTagToolButton *tagToolButton; QList readOnlyTags; QList tags; KisTagModel* model; QScopedPointer activeFilterModel; Private(KisTagModel* model) : activeFilterModel(new KisActiveFilterTagProxyModel(0)) { activeFilterModel->setSourceModel(model); } }; KisTagChooserWidget::KisTagChooserWidget(KisTagModel* model, QWidget* parent) : QWidget(parent) , d(new Private(model)) { d->comboBox = new QComboBox(this); d->comboBox->setToolTip(i18n("Tag")); d->comboBox->setSizePolicy(QSizePolicy::MinimumExpanding , QSizePolicy::Fixed ); d->comboBox->setModel(d->activeFilterModel.get()); d->model = model; QGridLayout* comboLayout = new QGridLayout(this); comboLayout->addWidget(d->comboBox, 0, 0); d->tagToolButton = new KisTagToolButton(this); comboLayout->addWidget(d->tagToolButton, 0, 1); comboLayout->setSpacing(0); comboLayout->setMargin(0); comboLayout->setColumnStretch(0, 3); this->setEnabled(true); connect(d->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(tagChanged(int))); connect(d->tagToolButton, SIGNAL(popupMenuAboutToShow()), this, SLOT (tagOptionsContextMenuAboutToShow())); connect(d->tagToolButton, SIGNAL(newTagRequested(KisTagSP)), this, SLOT(insertItem(KisTagSP))); connect(d->tagToolButton, SIGNAL(deletionOfCurrentTagRequested()), this, SLOT(contextDeleteCurrentTag())); connect(d->tagToolButton, SIGNAL(renamingOfCurrentTagRequested(KisTagSP)), this, SLOT(tagRenamingRequested(KisTagSP))); connect(d->tagToolButton, SIGNAL(undeletionOfTagRequested(KisTagSP)), this, SIGNAL(tagUndeletionRequested(KisTagSP))); connect(d->tagToolButton, SIGNAL(purgingOfTagUndeleteListRequested()), this, SIGNAL(tagUndeletionListPurgeRequested())); } KisTagChooserWidget::~KisTagChooserWidget() { delete d; } void KisTagChooserWidget::contextDeleteCurrentTag() { ENTER_FUNCTION(); fprintf(stderr, "void KisTagChooserWidget::contextDeleteCurrentTag()\n"); KisTagSP currentTag = currentlySelectedTag(); if (!currentTag.isNull() && currentTag->id() >= 0) { fprintf(stderr, "trying to remove item: %s\n", currentTag->name().toUtf8().toStdString().c_str()); d->model->removeTag(currentTag); setCurrentIndex(0); } } void KisTagChooserWidget::tagChanged(int tagIndex) { ENTER_FUNCTION(); fprintf(stderr, "void KisTagChooserWidget::tagChanged(int) %d\n", tagIndex); if (tagIndex >= 0) { emit tagChosen(currentlySelectedTag()); KisTagSP tag = currentlySelectedTag(); if (tag->id() < 0) { fprintf(stderr, "tag name: %s, url: %s, id: %d", tag->name().toUtf8().toStdString().c_str(), tag->url().toUtf8().toStdString().c_str(), tag->id()); } } else { fprintf(stderr, "Requested -1 index; previous: %d\n", d->comboBox->currentIndex()); } } void KisTagChooserWidget::tagRenamingRequested(const KisTagSP newName) { // TODO: RESOURCES: it should use QString, not KisTagSP int previousIndex = d->comboBox->currentIndex(); ENTER_FUNCTION(); KisTagSP currentTag = currentlySelectedTag(); QString name = newName.isNull() ? "" : newName->name(); bool canRenameCurrentTag = !currentTag.isNull() && currentTag->id() < 0; fprintf(stderr, "renaming tag requested! to: %s\n", name.toUtf8().toStdString().c_str()); if (canRenameCurrentTag && !name.isEmpty()) { d->model->renameTag(currentTag, newName->name()); setCurrentIndex(previousIndex); } } void KisTagChooserWidget::setUndeletionCandidate(const KisTagSP tag) { ENTER_FUNCTION(); d->tagToolButton->setUndeletionCandidate(tag); } void KisTagChooserWidget::setCurrentIndex(int index) { fprintf(stderr, "set current index: %d", index); ENTER_FUNCTION(); d->comboBox->setCurrentIndex(index); } int KisTagChooserWidget::currentIndex() const { return d->comboBox->currentIndex(); } void KisTagChooserWidget::addReadOnlyItem(KisTagSP tag) { d->model->addTag(tag); ENTER_FUNCTION(); } KisTagSP KisTagChooserWidget::insertItem(KisTagSP tag) { // TODO: RESOURCES: this function should use QString, not KisTagSP int previous = d->comboBox->currentIndex(); if(tag.isNull() || tag->name().isNull() || tag->name().isEmpty()) { fprintf(stderr, "inserting item is empty\n"); return KisTagSP(); } fprintf(stderr, "inserting item!!! %s\n", tag->name().toUtf8().toStdString().c_str()); tag->setUrl(tag->name()); tag->setComment(tag->name()); tag->setActive(true); tag->setValid(true); ENTER_FUNCTION(); bool added = d->model->addTag(tag); fprintf(stderr, "added = %d\n", added); if (added) { for (int i = 0; i < d->model->rowCount(); i++) { QModelIndex index = d->model->index(i, 0); KisTagSP temp = d->model->tagForIndex(index); if (!temp.isNull() && temp->url() == tag->url()) { setCurrentIndex(i); return temp; } } } setCurrentIndex(previous); return KisTagSP(); } KisTagSP KisTagChooserWidget::currentlySelectedTag() { int row = d->comboBox->currentIndex(); if (row < 0) { return KisTagSP(); } if (d->comboBox->currentData().data()) { fprintf(stderr, "current data type = %s\n", d->comboBox->currentData().typeName()); } else { fprintf(stderr, "current data type = (null)\n"); } QModelIndex index = d->model->index(row, 0); KisTagSP tag = d->model->tagForIndex(index); fprintf(stderr, "current tag: %s\n", tag.isNull() ? "(null)" : tag->name().toStdString().c_str()); fprintf(stderr, "current index = %d\n", row); ENTER_FUNCTION() << tag; return tag; } bool KisTagChooserWidget::selectedTagIsReadOnly() { ENTER_FUNCTION(); return false; } void KisTagChooserWidget::addItems(QList tags) { ENTER_FUNCTION(); warnKrita << "not implemented"; Q_FOREACH(KisTagSP tag, tags) { insertItem(tag); } } void KisTagChooserWidget::clear() { ENTER_FUNCTION(); } void KisTagChooserWidget::tagOptionsContextMenuAboutToShow() { ENTER_FUNCTION(); /* only enable the save button if the selected tag set is editable */ d->tagToolButton->readOnlyMode(selectedTagIsReadOnly()); emit popupMenuAboutToShow(); } void KisTagChooserWidget::showTagToolButton(bool show) { ENTER_FUNCTION(); d->tagToolButton->setVisible(show); } diff --git a/libs/resourcewidgets/KisTagChooserWidget.h b/libs/resourcewidgets/KisTagChooserWidget.h index 48d5dff084..e8c0c6d4d9 100644 --- a/libs/resourcewidgets/KisTagChooserWidget.h +++ b/libs/resourcewidgets/KisTagChooserWidget.h @@ -1,107 +1,108 @@ /* * This file is part of the KDE project * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Jan Hambrecht * Copyright (c) 2007 Sven Langkamp * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2011 José Luis Vergara * Copyright (c) 2013 Sascha Suelzer * Copyright (c) 2019 Boudewijn Rempt + * Copyright (c) 2020 Agata Cacko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KISTAGCHOOSERWIDGET_H #define KISTAGCHOOSERWIDGET_H #include #include "kritaresourcewidgets_export.h" #include #include /// /// \brief The KisTagChooserWidget class is responsible /// /// for all the logic that tags combobox has in various resource choosers. /// (Example of usage: tag combobox in Brushes docker). /// It uses KisTagModel as a model for items in the combobox. /// It is also responsible for the popup for tag removal, renaming and creation /// that appears on the right side of the tag combobox. /// All the logic for adding and removing tags is done through KisTagModel. /// /// For logic related to tagging and untagging resources, check KisTaggingManager /// and KisItemChooserContextMenu. /// class KRITARESOURCEWIDGETS_EXPORT KisTagChooserWidget : public QWidget { Q_OBJECT public: explicit KisTagChooserWidget(KisTagModel* model, QWidget* parent); ~KisTagChooserWidget() override; /// \brief setCurrentIndex sets the current index in the combobox /// \param index index is the /// void setCurrentIndex(int index); int currentIndex() const; /// \brief currentlySelectedTag returns the current tag from combobox /// \return the tag that is currently selected in the tag combobox /// KisTagSP currentlySelectedTag(); /// /// \brief selectedTagIsReadOnly checks whether the tag is readonly (generated by Krita) /// \return true if the tag was generated by Krita, false if it's just a normal tag /// bool selectedTagIsReadOnly(); void addItems(QList tagNames); void addReadOnlyItem(KisTagSP tagName); void clear(); void setUndeletionCandidate(const KisTagSP tag); void showTagToolButton(bool show); Q_SIGNALS: void newTagRequested(const KisTagSP tag); void tagDeletionRequested(const KisTagSP tag); void tagRenamingRequested(const KisTagSP oldTag, const KisTagSP newTag); void tagUndeletionRequested(const KisTagSP tag); void tagUndeletionListPurgeRequested(); void popupMenuAboutToShow(); void tagChosen(const KisTagSP tag); public Q_SLOTS: KisTagSP insertItem(KisTagSP tag); void tagChanged(int index); private Q_SLOTS: void tagRenamingRequested(const KisTagSP newName); void tagOptionsContextMenuAboutToShow(); void contextDeleteCurrentTag(); private: class Private; Private* const d; }; ; #endif // KOTAGCHOOSERWIDGET_H diff --git a/libs/resourcewidgets/KisTagToolButton.cpp b/libs/resourcewidgets/KisTagToolButton.cpp index f71f0ecba8..044fc3605f 100644 --- a/libs/resourcewidgets/KisTagToolButton.cpp +++ b/libs/resourcewidgets/KisTagToolButton.cpp @@ -1,148 +1,149 @@ /* * This file is part of the KDE project * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Jan Hambrecht * Copyright (c) 2007 Sven Langkamp * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2011 José Luis Vergara * Copyright (c) 2013 Sascha Suelzer + * Copyright (c) 2020 Agata Cacko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisTagToolButton.h" #include #include #include #include #include "KisResourceItemChooserContextMenu.h" #include "kis_debug.h" class KisTagToolButton::Private { public: QToolButton* tagToolButton; QAction* action_undeleteTag; QAction* action_deleteTag; KoLineEditAction* action_renameTag; QAction* action_purgeTagUndeleteList; KisTagSP undeleteCandidate; }; KisTagToolButton::KisTagToolButton(QWidget* parent) :QWidget(parent), d(new Private()) { QGridLayout* buttonLayout = new QGridLayout(this); buttonLayout->setMargin(0); buttonLayout->setSpacing(0); d->tagToolButton = new QToolButton(this); d->tagToolButton->setIcon(koIcon("bookmarks")); d->tagToolButton->setText(i18n("Tag")); d->tagToolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); d->tagToolButton->setToolTip(i18nc("@info:tooltip", "Show the tag box options.")); d->tagToolButton->setPopupMode(QToolButton::InstantPopup); d->tagToolButton->setEnabled(true); QMenu* popup = new QMenu(this); KoLineEditAction* addTagAction = new KoLineEditAction(popup); addTagAction->setPlaceholderText(i18n("New tag")); addTagAction->setIcon(koIcon("document-new")); addTagAction->closeParentOnTrigger(true); popup->addAction(addTagAction); connect(addTagAction, SIGNAL(triggered(KisTagSP)), this, SIGNAL(newTagRequested(KisTagSP))); d->action_renameTag = new KoLineEditAction(popup); d->action_renameTag->setPlaceholderText(i18n("Rename tag")); d->action_renameTag->setIcon(koIcon("edit-rename")); d->action_renameTag->closeParentOnTrigger(true); popup->addAction(d->action_renameTag); connect(d->action_renameTag, SIGNAL(triggered(KisTagSP)), this, SIGNAL(renamingOfCurrentTagRequested(KisTagSP))); popup->addSeparator(); d->action_deleteTag = new QAction(popup); d->action_deleteTag->setText(i18n("Delete this tag")); d->action_deleteTag->setIcon(koIcon("edit-delete")); popup->addAction(d->action_deleteTag); connect(d->action_deleteTag, SIGNAL(triggered()), this, SIGNAL(deletionOfCurrentTagRequested())); popup->addSeparator(); d->action_undeleteTag = new QAction(popup); d->action_undeleteTag->setIcon(koIcon("edit-redo")); d->action_undeleteTag->setVisible(false); popup->addAction(d->action_undeleteTag); connect(d->action_undeleteTag, SIGNAL(triggered()), this, SLOT(onTagUndeleteClicked())); d->action_purgeTagUndeleteList = new QAction(popup); d->action_purgeTagUndeleteList->setText(i18n("Clear undelete list")); d->action_purgeTagUndeleteList->setIcon(koIcon("edit-clear")); d->action_purgeTagUndeleteList->setVisible(false); popup->addAction(d->action_purgeTagUndeleteList); connect(d->action_purgeTagUndeleteList, SIGNAL(triggered()), this, SIGNAL(purgingOfTagUndeleteListRequested())); connect(popup, SIGNAL(aboutToShow()), this, SIGNAL(popupMenuAboutToShow())); d->tagToolButton->setMenu(popup); buttonLayout->addWidget(d->tagToolButton); } KisTagToolButton::~KisTagToolButton() { delete d; } void KisTagToolButton::readOnlyMode(bool activate) { ENTER_FUNCTION(); activate = !activate; d->action_renameTag->setVisible(activate); d->action_deleteTag->setVisible(activate); } void KisTagToolButton::setUndeletionCandidate(const KisTagSP deletedTag) { ENTER_FUNCTION(); d->undeleteCandidate = deletedTag; d->action_undeleteTag->setText(i18n("Undelete") +" "+ deletedTag->name()); d->action_undeleteTag->setVisible(!deletedTag->name().isEmpty()); d->action_purgeTagUndeleteList->setVisible(!deletedTag->name().isEmpty()); } void KisTagToolButton::onTagUndeleteClicked() { ENTER_FUNCTION(); emit undeletionOfTagRequested(d->undeleteCandidate); } diff --git a/libs/resourcewidgets/KisTagToolButton.h b/libs/resourcewidgets/KisTagToolButton.h index 883d00a98b..5dc7e8f114 100644 --- a/libs/resourcewidgets/KisTagToolButton.h +++ b/libs/resourcewidgets/KisTagToolButton.h @@ -1,59 +1,61 @@ /* * This file is part of the KDE project * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Jan Hambrecht * Copyright (c) 2007 Sven Langkamp * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2011 José Luis Vergara * Copyright (c) 2013 Sascha Suelzer + * Copyright (c) 2020 Agata Cacko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KISTAGTOOLBUTTON_H #define KISTAGTOOLBUTTON_H #include #include + class KisTagToolButton : public QWidget { Q_OBJECT private: explicit KisTagToolButton(QWidget* parent = 0); ~KisTagToolButton() override; void readOnlyMode(bool activate); void setUndeletionCandidate(const KisTagSP deletedTag); Q_SIGNALS: void newTagRequested(const KisTagSP tag); void renamingOfCurrentTagRequested(const KisTagSP tag); void deletionOfCurrentTagRequested(); void undeletionOfTagRequested(const KisTagSP tag); void purgingOfTagUndeleteListRequested(); void popupMenuAboutToShow(); private Q_SLOTS: void onTagUndeleteClicked(); private: class Private; Private* const d; friend class KisTagChooserWidget; }; #endif // KOTAGTOOLBUTTON_H