File indexing completed on 2024-05-19 05:08:35
0001 /* 0002 SPDX-FileCopyrightText: 2009-2016 Cristian Oneț <onet.cristian@gmail.com> 0003 SPDX-FileCopyrightText: 2009-2010 Alvaro Soliverez <asoliverez@gmail.com> 0004 SPDX-FileCopyrightText: 2010-2020 Thomas Baumgart <tbaumgart@kde.org> 0005 SPDX-FileCopyrightText: 2017-2018 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com> 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "ktagcontainer.h" 0010 0011 // ---------------------------------------------------------------------------- 0012 // QT Includes 0013 0014 #include <QAbstractItemModel> 0015 #include <QAbstractItemView> 0016 #include <QComboBox> 0017 #include <QEvent> 0018 #include <QHBoxLayout> 0019 #include <QKeyEvent> 0020 #include <QLineEdit> 0021 0022 // ---------------------------------------------------------------------------- 0023 // KDE Includes 0024 0025 #include <KLocalizedString> 0026 0027 // ---------------------------------------------------------------------------- 0028 // Project Includes 0029 0030 #include "ktaglabel.h" 0031 #include "idfilter.h" 0032 #include "mymoneyenums.h" 0033 0034 class KTagContainerPrivate 0035 { 0036 Q_DISABLE_COPY(KTagContainerPrivate) 0037 Q_DECLARE_PUBLIC(KTagContainer) 0038 0039 public: 0040 KTagContainerPrivate(KTagContainer* parent) 0041 : q_ptr(parent) 0042 , m_tagCombo(nullptr) 0043 , m_idFilter(new IdFilter(parent)) 0044 , m_skipSelection(true) 0045 , m_selectAfterFocusOut(false) 0046 { 0047 } 0048 0049 void addTagWidget(int row) 0050 { 0051 Q_Q(KTagContainer); 0052 const auto idx = m_tagCombo->model()->index(row, 0); 0053 const auto id = idx.data(eMyMoney::Model::IdRole).toString(); 0054 q->addTagWidget(id); 0055 } 0056 0057 QStringList tagIdList() const 0058 { 0059 QStringList tags; 0060 for(const auto tag : qAsConst(m_tagLabelList)) { 0061 tags << tag->id(); 0062 } 0063 return tags; 0064 } 0065 0066 KTagContainer* q_ptr; 0067 QComboBox* m_tagCombo; 0068 QScopedPointer<IdFilter> m_idFilter; 0069 QList<KTagLabel*> m_tagLabelList; 0070 bool m_skipSelection; 0071 bool m_selectAfterFocusOut; 0072 }; 0073 0074 KTagContainer::KTagContainer(QWidget* parent) 0075 : QWidget(parent) 0076 , d_ptr(new KTagContainerPrivate(this)) 0077 { 0078 Q_D(KTagContainer); 0079 d->m_tagCombo = new QComboBox(this); 0080 d->m_tagCombo->setEditable(true); 0081 d->m_tagCombo->setInsertPolicy(QComboBox::NoInsert); 0082 0083 QHBoxLayout *layout = new QHBoxLayout; 0084 layout->setContentsMargins(0, 0, 0, 0); 0085 layout->setSpacing(0); 0086 layout->addWidget(d->m_tagCombo, 100); 0087 setLayout(layout); 0088 setFocusProxy(d->m_tagCombo); 0089 d->m_tagCombo->lineEdit()->setPlaceholderText(i18nc("@info:placeholder tag combo box", "Tag")); 0090 0091 d->m_idFilter.data()->setSortLocaleAware(true); 0092 d->m_idFilter.data()->sort(0); 0093 0094 connect(d->m_tagCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int row) { 0095 Q_D(KTagContainer); 0096 if (!d->m_skipSelection) { 0097 d->addTagWidget(row); 0098 } 0099 }); 0100 0101 connect(d->m_tagCombo, QOverload<int>::of(&QComboBox::activated), this, [=](int row) { 0102 Q_D(KTagContainer); 0103 if (d->m_selectAfterFocusOut) { 0104 d->addTagWidget(row); 0105 d->m_selectAfterFocusOut = false; 0106 } 0107 }); 0108 0109 d->m_tagCombo->installEventFilter(this); 0110 d->m_tagCombo->view()->installEventFilter(this); 0111 } 0112 0113 KTagContainer::~KTagContainer() 0114 { 0115 Q_D(KTagContainer); 0116 delete d; 0117 } 0118 0119 bool KTagContainer::eventFilter(QObject* o, QEvent* e) 0120 { 0121 Q_D(KTagContainer); 0122 if (o == d->m_tagCombo->view()) { 0123 if (e->type() == QEvent::KeyPress) { 0124 QKeyEvent* kev = static_cast<QKeyEvent*>(e); 0125 switch (kev->key()) { 0126 case Qt::Key_Escape: 0127 case Qt::Key_F4: 0128 d->m_skipSelection = true; 0129 break; 0130 default: 0131 break; 0132 } 0133 } else if (e->type() == QEvent::Show) { 0134 d->m_skipSelection = false; 0135 } 0136 0137 } else if (o == d->m_tagCombo) { 0138 if (e->type() == QEvent::FocusOut) { 0139 const auto row = d->m_tagCombo->currentIndex(); 0140 if (row > 0) { 0141 d->addTagWidget(row); 0142 } else { 0143 d->m_selectAfterFocusOut = true; 0144 } 0145 } 0146 } 0147 return false; 0148 } 0149 0150 void KTagContainer::setModel(QAbstractItemModel* model) 0151 { 0152 Q_D(KTagContainer); 0153 const bool needSetSourceModel = d->m_idFilter->sourceModel() == nullptr; 0154 d->m_idFilter->setSourceModel(model); 0155 if (needSetSourceModel) { 0156 d->m_tagCombo->setModel(d->m_idFilter.data()); 0157 } 0158 } 0159 0160 QComboBox* KTagContainer::tagCombo() 0161 { 0162 Q_D(KTagContainer); 0163 return d->m_tagCombo; 0164 } 0165 0166 const QList<QString> KTagContainer::selectedTags() 0167 { 0168 Q_D(KTagContainer); 0169 return d->m_idFilter->filterList(); 0170 } 0171 0172 void KTagContainer::loadTags(const QList<QString>& idList) 0173 { 0174 Q_D(KTagContainer); 0175 // reset filter 0176 d->m_idFilter->setFilterList(QStringList()); 0177 qDeleteAll(d->m_tagLabelList); 0178 d->m_tagLabelList.clear(); 0179 for (const auto& id : idList) { 0180 addTagWidget(id); 0181 } 0182 } 0183 0184 void KTagContainer::addTagWidget(const QString& id) 0185 { 0186 Q_D(KTagContainer); 0187 0188 d->m_skipSelection = true; 0189 if (id.isEmpty() || d->m_idFilter->filterList().contains(id)) 0190 return; 0191 0192 // set index to the empty item since we remove 0193 // the selected item as part of this method 0194 d->m_tagCombo->setCurrentIndex(0); 0195 0196 const auto tagName = d->m_tagCombo->itemText(d->m_tagCombo->findData(QVariant(id), Qt::UserRole, Qt::MatchExactly)); 0197 KTagLabel* t = new KTagLabel(id, tagName, this); 0198 connect(t, &KTagLabel::clicked, this, &KTagContainer::slotRemoveTagWidget); 0199 d->m_tagLabelList.append(t); 0200 d->m_idFilter->addFilter(id); 0201 layout()->addWidget(t); 0202 0203 Q_EMIT tagsChanged(d->tagIdList()); 0204 } 0205 0206 void KTagContainer::slotRemoveTagWidget() 0207 { 0208 Q_D(KTagContainer); 0209 const auto tagLabel = qobject_cast<KTagLabel *>(sender()); 0210 d->m_idFilter->removeFilter(tagLabel->id()); 0211 int index = d->m_tagLabelList.indexOf(tagLabel); 0212 d->m_tagLabelList.removeAt(index); 0213 delete tagLabel; 0214 0215 Q_EMIT tagsChanged(d->tagIdList()); 0216 0217 d->m_tagCombo->setCurrentIndex(0); 0218 d->m_tagCombo->setFocus(); 0219 }