File indexing completed on 2024-05-19 04:29:28

0001 /*
0002  * SPDX-FileCopyrightText: 2021 Agata Cacko <cacko.azh@gmail.com>
0003  * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "KisTagSelectionWidget.h"
0009 
0010 #include <QProcessEnvironment>
0011 #include <QFileInfo>
0012 #include <QMessageBox>
0013 #include <QStandardPaths>
0014 #include <QGridLayout>
0015 #include <QTableWidget>
0016 #include <QPainter>
0017 #include <QListWidget>
0018 #include <QAction>
0019 #include <QMouseEvent>
0020 #include <QMenu>
0021 #include <QPair>
0022 #include <QApplication>
0023 #include <QInputDialog>
0024 #include <QPainterPath>
0025 
0026 #include <KoFileDialog.h>
0027 #include <kis_icon.h>
0028 #include <KoID.h>
0029 
0030 #include <kis_debug.h>
0031 #include <kis_global.h>
0032 #include <TagActions.h>
0033 
0034 #include <KisWrappableHBoxLayout.h>
0035 #include <kis_signals_blocker.h>
0036 
0037 
0038 #include "kis_icon.h"
0039 
0040 
0041 WdgCloseableLabel::WdgCloseableLabel(KoID tag, bool editable, bool semiSelected, QWidget *parent)
0042     : QWidget(parent)
0043     , m_editable(editable)
0044     , m_semiSelected(semiSelected)
0045     , m_tag(tag)
0046 {
0047     QHBoxLayout *layout = new QHBoxLayout(this);
0048     layout->setContentsMargins(8, 0, 0, 0);
0049     layout->setSpacing(2);
0050 
0051     m_textLabel = new QLabel(parent);
0052     m_textLabel->setText(tag.name());
0053     m_textLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
0054     layout->addWidget(m_textLabel);
0055     layout->insertStretch(2, 1);
0056     if (m_editable) {
0057         m_closeIconLabel = new QPushButton(parent);
0058         m_closeIconLabel->setFlat(true);
0059         m_closeIconLabel->setIcon(KisIconUtils::loadIcon("docker_close"));
0060         m_closeIconLabel->setToolTip(i18n("Remove from tag"));
0061         m_closeIconLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
0062         m_closeIconLabel->setEnabled(m_editable);
0063         m_closeIconLabel->setMaximumSize(QSize(1, 1) * m_size);
0064 
0065         connect(m_closeIconLabel, &QAbstractButton::clicked, this, [&]() {
0066             emit sigRemoveTagFromSelection(m_tag);
0067         });
0068         layout->addWidget(m_closeIconLabel);
0069     }
0070     setLayout(layout);
0071 }
0072 
0073 WdgCloseableLabel::~WdgCloseableLabel()
0074 {
0075 
0076 }
0077 
0078 void WdgCloseableLabel::paintEvent(QPaintEvent *event)
0079 {
0080     QPainter painter(this);
0081 
0082     QColor backGroundColor = qApp->palette().light().color();
0083     QColor foregroundColor = qApp->palette().windowText().color();
0084     qreal r1 = 0.65;
0085     qreal r2 = 1 - r1;
0086     QColor outlineColor = QColor::fromRgb(256*(r1*backGroundColor.redF() + r2*foregroundColor.redF()),
0087                                           256*(r1*backGroundColor.greenF() + r2*foregroundColor.greenF()),
0088                                           256*(r1*backGroundColor.blueF() + r2*foregroundColor.blueF()));
0089 
0090 
0091     QBrush windowB = qApp->palette().window();
0092     QBrush windowTextB = qApp->palette().windowText();
0093 
0094     QWidget::paintEvent(event);
0095     painter.setRenderHint(QPainter::Antialiasing);
0096     QPainterPath path;
0097     path.addRoundedRect(this->rect(), 6, 6);
0098 
0099     // good color:
0100     painter.fillPath(path, qApp->palette().light());
0101 
0102     if (m_semiSelected) {
0103 
0104         QPen penwt = QPen(outlineColor, 1);
0105         penwt.setStyle(Qt::DashLine);
0106 
0107         QPainterPath outlinePath;
0108         outlinePath.addRoundedRect(this->rect().adjusted(1, 1, -1, -1), 4, 4);
0109 
0110         painter.setPen(penwt);
0111         painter.drawPath(outlinePath);
0112     }
0113 
0114 }
0115 
0116 WdgAddTagButton::WdgAddTagButton(QWidget *parent, bool createNew)
0117     : QToolButton(parent),
0118     m_createNew(createNew)
0119 {
0120     setPopupMode(QToolButton::InstantPopup);
0121     setIcon(KisIconUtils::loadIcon("list-add"));
0122     setToolTip(i18n("Assign to tag"));
0123     setContentsMargins(0, 0, 0, 0);
0124     QSize defaultSize = QSize(1, 1)*m_size;
0125     setMinimumSize(defaultSize);
0126     setMaximumSize(defaultSize);
0127 
0128     connect(this, SIGNAL(triggered(QAction*)), SLOT(slotAddNewTag(QAction*)));
0129 
0130     if (m_createNew) {
0131         UserInputTagAction *newTag = new UserInputTagAction(this);
0132         newTag->setCloseParentOnTrigger(false);
0133 
0134         connect(newTag, SIGNAL(triggered(QString)), this, SLOT(slotCreateNewTag(QString)), Qt::UniqueConnection);
0135         m_createNewTagAction = newTag;
0136     } else {
0137         m_noTags = new QAction("No tags present");
0138         QFont font = m_noTags->font();
0139         font.setItalic(true);
0140         m_noTags->setFont(font);
0141     }
0142 
0143 }
0144 
0145 WdgAddTagButton::~WdgAddTagButton()
0146 {
0147 
0148 }
0149 
0150 void WdgAddTagButton::setAvailableTagsList(QList<KoID> &notSelected)
0151 {
0152     QList<QAction*> actionsToRemove = actions();
0153     Q_FOREACH(QAction* action, actionsToRemove) {
0154         removeAction(action);
0155     }
0156 
0157     Q_FOREACH(KoID tag, notSelected) {
0158         QAction* action = new QAction(tag.name());
0159         action->setData(QVariant::fromValue<KoID>(tag));
0160         addAction(action);
0161     }
0162     
0163     QAction *separator = new QAction(this);
0164     separator->setSeparator(true);
0165     addAction(separator);
0166 
0167     if (m_createNew) {
0168         addAction(m_createNewTagAction);
0169         setDefaultAction(0);
0170     } else {
0171         if (notSelected.count() == 0) {
0172             addAction(m_noTags);
0173         }
0174     }
0175 }
0176 
0177 void WdgAddTagButton::slotFinishLastAction()
0178 {
0179     if (m_lastAction == CreateNewTag) {
0180         emit sigCreateNewTag(m_lastTagToCreate);
0181     } else {
0182         emit sigAddNewTag(m_lastTagToAdd);
0183     }
0184 }
0185 
0186 void WdgAddTagButton::slotAddNewTag(QAction *action)
0187 {
0188     if (action == m_createNewTagAction) {
0189         m_lastTagToCreate = action->data().toString();
0190         m_lastAction = CreateNewTag;
0191         slotFinishLastAction();
0192         KisSignalsBlocker b(m_createNewTagAction);
0193         m_createNewTagAction->setText("");
0194     } else if (!action->data().isNull() && action->data().canConvert<KoID>()) {
0195         m_lastTagToAdd = action->data().value<KoID>();
0196         m_lastAction = AddNewTag;
0197         slotFinishLastAction();
0198     }
0199 
0200 
0201     if (this->menu()) {
0202         this->menu()->close();
0203     }
0204 }
0205 
0206 void WdgAddTagButton::slotCreateNewTag(QString tagName)
0207 {
0208     m_lastTagToCreate = tagName;
0209     m_lastAction = CreateNewTag;
0210     slotFinishLastAction();
0211     KisSignalsBlocker b(m_createNewTagAction);
0212     m_createNewTagAction->setText("");
0213 
0214 
0215     if (this->menu()) {
0216         this->menu()->close();
0217     }
0218 }
0219 
0220 void WdgAddTagButton::paintEvent(QPaintEvent *event)
0221 {
0222     Q_UNUSED(event);
0223 
0224     QPainter painter(this);
0225     painter.setRenderHint(QPainter::Antialiasing);
0226     QPainterPath path;
0227     path.addRoundedRect(this->rect(), 6, 6);
0228     painter.fillPath(path, qApp->palette().light());
0229     painter.setPen(QPen(qApp->palette().windowText(), painter.pen().widthF()));
0230     QIcon icon = this->icon();
0231     QSize size = this->rect().size()*0.6;
0232 
0233     QSize iconSize = icon.actualSize(size);
0234     QPixmap pix = icon.pixmap(iconSize);
0235     QSize realSize = iconSize.scaled(iconSize, Qt::KeepAspectRatio);//pix.rect().size();
0236     qreal hack = 0.5;
0237     QPointF p = this->rect().topLeft() + QPointF(this->rect().width()/2 - realSize.width()/2 - hack, this->rect().height()/2 - realSize.height()/2 - hack);
0238     painter.setOpacity(!isEnabled() ? 0.3 : 1.0);
0239     painter.drawPixmap(p, pix);
0240     painter.setOpacity(1.0);
0241 }
0242 
0243 KisTagSelectionWidget::KisTagSelectionWidget(QWidget *parent, bool createNew)
0244     : QWidget(parent),
0245     m_createNew(createNew)
0246 {
0247     m_layout = new KisWrappableHBoxLayout(this);
0248     m_addTagButton = new WdgAddTagButton(this, m_createNew);
0249 
0250     m_layout->addWidget(m_addTagButton);
0251     connect(m_addTagButton, SIGNAL(sigCreateNewTag(QString)), this, SIGNAL(sigCreateNewTag(QString)), Qt::UniqueConnection);
0252     connect(m_addTagButton, SIGNAL(sigAddNewTag(KoID)), this, SIGNAL(sigAddTagToSelection(KoID)), Qt::UniqueConnection);
0253 
0254     setLayout(m_layout);
0255 }
0256 
0257 KisTagSelectionWidget::~KisTagSelectionWidget()
0258 {
0259 
0260 }
0261 
0262 void KisTagSelectionWidget::setTagList(bool editable, QList<KoID> &selected, QList<KoID> &notSelected)
0263 {
0264     QList<KoID> semiSelected;
0265     setTagList(editable, selected, notSelected, semiSelected);
0266 }
0267 
0268 void KisTagSelectionWidget::setTagList(bool editable, QList<KoID> &selected, QList<KoID> &notSelected, QList<KoID> &semiSelected)
0269 {
0270     m_editable = editable;
0271     QLayoutItem *item;
0272 
0273     disconnect(m_addTagButton, SIGNAL(sigCreateNewTag(QString)), this, SIGNAL(sigCreateNewTag(QString)));
0274     disconnect(m_addTagButton, SIGNAL(sigAddNewTag(KoID)), this, SIGNAL(sigAddTagToSelection(KoID)));
0275 
0276     while((item = m_layout->takeAt(0))) {
0277         if (item->widget()) {
0278             if (!dynamic_cast<WdgAddTagButton*>(item->widget())) {
0279                 delete item->widget();
0280             }
0281         }
0282         delete item;
0283     }
0284 
0285 
0286     WdgAddTagButton* addTagButton = dynamic_cast<WdgAddTagButton*>(m_addTagButton);
0287     KIS_SAFE_ASSERT_RECOVER_RETURN(addTagButton);
0288     addTagButton->setAvailableTagsList(notSelected);
0289 
0290     Q_FOREACH(KoID tag, selected) {
0291         WdgCloseableLabel* label = new WdgCloseableLabel(tag, m_editable, false, this);
0292         connect(label, SIGNAL(sigRemoveTagFromSelection(KoID)), this, SLOT(slotRemoveTagFromSelection(KoID)), Qt::UniqueConnection);
0293         m_layout->addWidget(label);
0294     }
0295 
0296     Q_FOREACH(KoID tag, semiSelected) {
0297         WdgCloseableLabel* label = new WdgCloseableLabel(tag, m_editable, true, this);
0298         connect(label, SIGNAL(sigRemoveTagFromSelection(KoID)), this, SLOT(slotRemoveTagFromSelection(KoID)), Qt::UniqueConnection);
0299         m_layout->addWidget(label);
0300     }
0301 
0302     m_layout->addWidget(m_addTagButton);
0303     m_addTagButton->setVisible(m_editable);
0304 
0305 
0306     connect(m_addTagButton, SIGNAL(sigCreateNewTag(QString)), this, SIGNAL(sigCreateNewTag(QString)), Qt::UniqueConnection);
0307     connect(m_addTagButton, SIGNAL(sigAddNewTag(KoID)), this, SIGNAL(sigAddTagToSelection(KoID)), Qt::UniqueConnection);
0308 
0309     if (m_editable) {
0310     }
0311 
0312     if (layout()) {
0313         layout()->invalidate();
0314     }
0315 }
0316 
0317 void KisTagSelectionWidget::slotAddTagToSelection(QAction *action)
0318 {
0319     if (!action) return;
0320 
0321     if (!action->data().isNull()) {
0322         KoID custom = action->data().value <KoID>();
0323         emit sigAddTagToSelection(custom);
0324     }
0325 }
0326 
0327 void KisTagSelectionWidget::slotRemoveTagFromSelection(KoID tag)
0328 {
0329     emit sigRemoveTagFromSelection(tag);
0330 }