Warning, file /office/kmymoney/kmymoney/widgets/registersearchline.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2007-2018 Thomas Baumgart <tbaumgart@kde.org>
0003     SPDX-FileCopyrightText: 2017-2018 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "registersearchline.h"
0008 
0009 // ----------------------------------------------------------------------------
0010 // QT Includes
0011 
0012 #include <QLabel>
0013 #include <QTimer>
0014 #include <QScrollBar>
0015 #include <QHBoxLayout>
0016 #include <QHash>
0017 #include <QIcon>
0018 
0019 // ----------------------------------------------------------------------------
0020 // KDE Includes
0021 
0022 #include <KComboBox>
0023 #include <KLocalizedString>
0024 
0025 // ----------------------------------------------------------------------------
0026 // Project Includes
0027 
0028 #include "kmymoneyutils.h"
0029 #include "register.h"
0030 #include "registeritem.h"
0031 #include "registerfilter.h"
0032 #include "icons/icons.h"
0033 #include "widgetenums.h"
0034 
0035 using namespace eWidgets;
0036 using namespace KMyMoneyRegister;
0037 using namespace Icons;
0038 
0039 class RegisterSearchLine::RegisterSearchLinePrivate
0040 {
0041 public:
0042     RegisterSearchLinePrivate() :
0043         reg(0),
0044         combo(0),
0045         queuedSearches(0),
0046         status(eRegister::ItemState::Any) {}
0047 
0048     Register* reg;
0049     KComboBox* combo;
0050     QString search;
0051     int queuedSearches;
0052     eRegister::ItemState status;
0053 };
0054 
0055 RegisterSearchLine::RegisterSearchLine(QWidget* parent, Register* reg) :
0056     KLineEdit(parent),
0057     d(new RegisterSearchLinePrivate)
0058 {
0059     setClearButtonEnabled(true);
0060 
0061     if (!parentWidget()->layout())
0062         parentWidget()->setLayout(new QHBoxLayout);
0063     parentWidget()->layout()->addWidget(this);
0064     d->reg = reg;
0065     connect(this, &QLineEdit::textChanged, this, &RegisterSearchLine::queueSearch);
0066 
0067     QLabel* label = new QLabel(i18nc("label for status combo", "Stat&us"), parentWidget());
0068     parentWidget()->layout()->addWidget(label);
0069     d->combo = new KComboBox(parentWidget());
0070     parentWidget()->layout()->addWidget(d->combo);
0071     // don't change the order of the following lines unless updating
0072     // the case labels in RegisterSearchLine::itemMatches() at the same time
0073     d->combo->insertItem((int)eRegister::ItemState::Any, Icons::get(Icon::Unknown), i18n("Any status"));
0074     d->combo->insertItem((int)eRegister::ItemState::Imported, Icons::get(Icon::DocumentImport), i18n("Imported"));
0075     d->combo->insertItem((int)eRegister::ItemState::Matched, Icons::get(Icon::TransactionMatch), i18n("Matched"));
0076     d->combo->insertItem((int)eRegister::ItemState::Erroneous, Icons::get(Icon::Warning), i18n("Erroneous"));
0077     d->combo->insertItem((int)eRegister::ItemState::Scheduled, Icons::get(Icon::Schedule), i18n("Scheduled"));
0078     d->combo->insertItem((int)eRegister::ItemState::NotMarked, i18n("Not marked"));
0079     d->combo->insertItem((int)eRegister::ItemState::NotReconciled, i18n("Not reconciled"));
0080     d->combo->insertItem((int)eRegister::ItemState::Cleared, i18nc("Reconciliation state 'Cleared'", "Cleared"));
0081     d->combo->setCurrentIndex((int)eRegister::ItemState::Any);
0082     connect(d->combo, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &RegisterSearchLine::slotStatusChanged);
0083     label->setBuddy(d->combo);
0084 
0085     if (reg) {
0086         connect(reg, &QObject::destroyed, this, &RegisterSearchLine::registerDestroyed);
0087         connect(reg, &Register::itemAdded, this, &RegisterSearchLine::itemAdded);
0088     } else {
0089         setEnabled(false);
0090     }
0091 }
0092 
0093 RegisterSearchLine::~RegisterSearchLine()
0094 {
0095     delete d;
0096 }
0097 
0098 void RegisterSearchLine::setRegister(Register* reg)
0099 {
0100     if (d->reg) {
0101         disconnect(d->reg, &QObject::destroyed, this, &RegisterSearchLine::registerDestroyed);
0102         disconnect(d->reg, &Register::itemAdded, this, &RegisterSearchLine::itemAdded);
0103     }
0104 
0105     d->reg = reg;
0106 
0107     if (reg) {
0108         connect(reg, &QObject::destroyed, this, &RegisterSearchLine::registerDestroyed);
0109         connect(reg, &Register::itemAdded, this, &RegisterSearchLine::itemAdded);
0110     }
0111 
0112     setEnabled(reg != 0);
0113 }
0114 
0115 void RegisterSearchLine::slotStatusChanged(int status)
0116 {
0117     d->status = static_cast<eRegister::ItemState>(status);
0118     updateSearch();
0119 }
0120 
0121 void RegisterSearchLine::queueSearch(const QString& search)
0122 {
0123     d->queuedSearches++;
0124     d->search = search;
0125     QTimer::singleShot(200, this, SLOT(activateSearch()));
0126 }
0127 
0128 void RegisterSearchLine::activateSearch()
0129 {
0130     --(d->queuedSearches);
0131     if (d->queuedSearches == 0)
0132         updateSearch(d->search);
0133 }
0134 
0135 void RegisterSearchLine::updateSearch(const QString& s)
0136 {
0137     if (!d->reg)
0138         return;
0139 
0140     d->search = s.isNull() ? text() : s;
0141 
0142     // keep track of the current focus item
0143     RegisterItem* focusItem = d->reg->focusItem();
0144 
0145     bool enabled = d->reg->updatesEnabled();
0146     d->reg->setUpdatesEnabled(false);
0147 
0148     bool scrollBarVisible = d->reg->verticalScrollBar()->isVisible();
0149 
0150     RegisterFilter filter(d->search, d->status);
0151     RegisterItem* p = d->reg->firstItem();
0152     for (; p; p = p->nextItem()) {
0153         p->setVisible(p->matches(filter));
0154     }
0155     d->reg->suppressAdjacentMarkers();
0156     d->reg->updateAlternate();
0157     d->reg->setUpdatesEnabled(enabled);
0158 
0159     // if focus item is still visible, then make sure we have
0160     // it on screen
0161     if (focusItem && focusItem->isVisible()) {
0162         d->reg->update();
0163         /* it's totally fine to call ensureFocusItemVisible instantly
0164          * while narrowing (by adding another letter) filtered results
0165          * because removing items from QTableWidget is fast
0166          * but while widening (by removing some letter) filtered results
0167          * QTableWidget lags and ensureFocusItemVisible() happens before
0168          * its update and focused item isn't made visible therefore
0169         */
0170         QTimer::singleShot(500, d->reg, SLOT(ensureFocusItemVisible()));
0171     }
0172     // if the scrollbar's visibility changed, we need to resize the contents
0173     if (scrollBarVisible != d->reg->verticalScrollBar()->isVisible()) {
0174         d->reg->resize((int)eTransaction::Column::Detail);
0175     }
0176 }
0177 
0178 void RegisterSearchLine::itemAdded(RegisterItem* item) const
0179 {
0180     item->setVisible(item->matches(RegisterFilter(text(), d->status)));
0181 }
0182 
0183 void RegisterSearchLine::registerDestroyed()
0184 {
0185     d->reg = 0;
0186     setEnabled(false);
0187 }
0188 
0189 
0190 class RegisterSearchLineWidget::RegisterSearchLineWidgetPrivate
0191 {
0192 public:
0193     RegisterSearchLineWidgetPrivate() :
0194         reg(0),
0195         searchLine(0) {}
0196 
0197     Register* reg;
0198     RegisterSearchLine* searchLine;
0199 };
0200 
0201 
0202 RegisterSearchLineWidget::RegisterSearchLineWidget(Register* reg, QWidget* parent) :
0203     QWidget(parent),
0204     d(new RegisterSearchLineWidgetPrivate)
0205 {
0206     d->reg = reg;
0207     createWidgets();
0208 }
0209 
0210 RegisterSearchLineWidget::~RegisterSearchLineWidget()
0211 {
0212     delete d;
0213 }
0214 
0215 RegisterSearchLine* RegisterSearchLineWidget::createSearchLine(Register* reg)
0216 {
0217     if (!d->searchLine)
0218         d->searchLine = new RegisterSearchLine(this, reg);
0219     return d->searchLine;
0220 }
0221 
0222 void RegisterSearchLineWidget::createWidgets()
0223 {
0224     QHBoxLayout *searchLineLayout = new QHBoxLayout(this);
0225     searchLineLayout->setSpacing(0);
0226     searchLineLayout->setContentsMargins(0, 0, 0, 0);
0227     QLabel *label = new QLabel(i18nc("Filter widget label", "Fi&lter:"), this);
0228     searchLineLayout->addWidget(label);
0229 
0230     d->searchLine = createSearchLine(d->reg);
0231     d->searchLine->show();
0232 
0233     label->setBuddy(d->searchLine);
0234     label->show();
0235 }
0236 
0237 
0238 RegisterSearchLine* RegisterSearchLineWidget::searchLine() const
0239 {
0240     return d->searchLine;
0241 }