diff --git a/libs/resourcewidgets/KisResourceTaggingManager.cpp b/libs/resourcewidgets/KisResourceTaggingManager.cpp index cafd1fa485..32e47d0359 100644 --- a/libs/resourcewidgets/KisResourceTaggingManager.cpp +++ b/libs/resourcewidgets/KisResourceTaggingManager.cpp @@ -1,225 +1,217 @@ /* * 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->tagFilter, SIGNAL(saveButtonClicked()), this, SLOT(tagSaveButtonPressed())); connect(d->tagFilter, SIGNAL(filterTextChanged(QString)), this, SLOT(tagSearchLineEditTextChanged(QString))); } 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::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::contextAddTagToResource(KoResourceSP resource, const KisTagSP tag) { fprintf(stderr, "void KisResourceTaggingManager::contextAddTagToResource(KoResourceSP resource, const KisTagSP tag)"); ENTER_FUNCTION(); d->tagModel->tagResource(tag, resource); } void KisResourceTaggingManager::contextRemoveTagFromResource(KoResourceSP resource, const KisTagSP tag) { fprintf(stderr, "void KisResourceTaggingManager::contextRemoveTagFromResource(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::tagChooserIndexChanged(const KisTagSP tag) { ENTER_FUNCTION(); d->model->setTag(tag); d->currentTag = tag; d->tagFilter->clear(); d->tagFilter->allowSave(tag->id() >= 0); // disallow save if the chosen tag has negative id (i.e. 'All' tag) } 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); } 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(); } 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/KisTagChooserWidget.cpp b/libs/resourcewidgets/KisTagChooserWidget.cpp index ddf3780a47..91f628467a 100644 --- a/libs/resourcewidgets/KisTagChooserWidget.cpp +++ b/libs/resourcewidgets/KisTagChooserWidget.cpp @@ -1,279 +1,301 @@ /* * 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; + KisTagSP rememberedTag; 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, SLOT(tagUndeletionRequested(KisTagSP))); connect(d->tagToolButton, SIGNAL(purgingOfTagUndeleteListRequested()), this, SIGNAL(tagUndeletionListPurgeRequested())); + connect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(slotModelAboutToBeReset())); + connect(d->model, SIGNAL(modelReset()), this, SLOT(slotModelReset())); + + } 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); d->tagToolButton->setUndeletionCandidate(currentTag); } } 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::tagUndeletionRequested(const KisTagSP tag) { int previousIndex = d->comboBox->currentIndex(); ENTER_FUNCTION(); fprintf(stderr, "undeleting tag requested! to: %s\n", tag->name().toUtf8().toStdString().c_str()); bool success = d->model->changeTagActive(tag, true); setCurrentIndex(previousIndex); if (success) { d->tagToolButton->setUndeletionCandidate(KisTagSP()); setCurrentItem(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(); } -void KisTagChooserWidget::setCurrentItem(KisTagSP tag) +bool KisTagChooserWidget::setCurrentItem(KisTagSP tag) { 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 true; } } + return false; } 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) { - setCurrentItem(tag); - return currentlySelectedTag(); + bool found = setCurrentItem(tag); + if (found) { + return currentlySelectedTag(); + } else { + return KisTagSP(); + } } 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 currentlySelectedTag()->id() < 0; } 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); } + +void KisTagChooserWidget::slotModelAboutToBeReset() +{ + d->rememberedTag = currentlySelectedTag(); +} + +void KisTagChooserWidget::slotModelReset() +{ + bool selected = setCurrentItem(d->rememberedTag); + if (!selected) { + setCurrentIndex(0); // last used tag was most probably removed + } +} diff --git a/libs/resourcewidgets/KisTagChooserWidget.h b/libs/resourcewidgets/KisTagChooserWidget.h index 28028e7957..7d355561bd 100644 --- a/libs/resourcewidgets/KisTagChooserWidget.h +++ b/libs/resourcewidgets/KisTagChooserWidget.h @@ -1,108 +1,110 @@ /* * 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 (via KisTagToolButton) /// 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 showTagToolButton(bool show); Q_SIGNALS: void newTagRequested(const KisTagSP tag); void tagDeletionRequested(const KisTagSP tag); void tagRenamingRequested(const KisTagSP oldTag, const KisTagSP newTag); 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 tagUndeletionRequested(const KisTagSP tag); void tagOptionsContextMenuAboutToShow(); void contextDeleteCurrentTag(); + void slotModelAboutToBeReset(); + void slotModelReset(); private: - void setCurrentItem(KisTagSP tag); + bool setCurrentItem(KisTagSP tag); private: class Private; Private* const d; }; #endif // KOTAGCHOOSERWIDGET_H