File indexing completed on 2024-05-12 05:07:48

0001 /*
0002     SPDX-FileCopyrightText: 2016-2022 Thomas Baumgart <tbaumgart@kde.org>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "newspliteditor.h"
0007 
0008 // ----------------------------------------------------------------------------
0009 // QT Includes
0010 
0011 #include <QAction>
0012 #include <QCompleter>
0013 #include <QConcatenateTablesProxyModel>
0014 #include <QDate>
0015 #include <QDebug>
0016 #include <QHeaderView>
0017 #include <QSortFilterProxyModel>
0018 #include <QStringList>
0019 #include <QTreeView>
0020 
0021 // ----------------------------------------------------------------------------
0022 // KDE Includes
0023 
0024 #include <KLocalizedString>
0025 
0026 // ----------------------------------------------------------------------------
0027 // Project Includes
0028 
0029 #include "accountcreator.h"
0030 #include "accountsmodel.h"
0031 #include "costcentermodel.h"
0032 #include "creditdebitedit.h"
0033 #include "icons.h"
0034 #include "journalmodel.h"
0035 #include "kcurrencycalculator.h"
0036 #include "kmymoneyaccountcombo.h"
0037 #include "kmymoneysettings.h"
0038 #include "kmymoneyutils.h"
0039 #include "menuenums.h"
0040 #include "mymoneyaccount.h"
0041 #include "mymoneyenums.h"
0042 #include "mymoneyexception.h"
0043 #include "mymoneyfile.h"
0044 #include "mymoneysecurity.h"
0045 #include "payeecreator.h"
0046 #include "payeesmodel.h"
0047 #include "securitiesmodel.h"
0048 #include "splitmodel.h"
0049 #include "splitview.h"
0050 #include "tagcreator.h"
0051 #include "tagsmodel.h"
0052 #include "widgethintframe.h"
0053 
0054 #include "ui_newspliteditor.h"
0055 
0056 using namespace Icons;
0057 
0058 struct NewSplitEditor::Private
0059 {
0060     Q_DISABLE_COPY_MOVE(Private)
0061 
0062     Private(NewSplitEditor* parent)
0063         : q(parent)
0064         , ui(new Ui_NewSplitEditor)
0065         , tabOrderUi(nullptr)
0066         , accountsModel(new AccountNamesFilterProxyModel(parent))
0067         , payeesModel(new QSortFilterProxyModel(parent))
0068         , costCenterModel(new QSortFilterProxyModel(parent))
0069         , splitModel(nullptr)
0070         , accepted(false)
0071         , costCenterRequired(false)
0072         , showValuesInverted(false)
0073         , loadingSplit(false)
0074         , isIncomeExpense(false)
0075         , readOnly(false)
0076         , postDate(QDate::currentDate())
0077         , frameCollection(nullptr)
0078     {
0079         accountsModel->setObjectName("AccountNamesFilterProxyModel");
0080         costCenterModel->setObjectName("SortedCostCenterModel");
0081         payeesModel->setObjectName("SortedPayeesModel");
0082 
0083         costCenterModel->setSortLocaleAware(true);
0084         costCenterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
0085 
0086         payeesModel->setSortLocaleAware(true);
0087         payeesModel->setSortCaseSensitivity(Qt::CaseInsensitive);
0088     }
0089 
0090     ~Private()
0091     {
0092         delete ui;
0093     }
0094 
0095     bool checkForValidSplit(bool doUserInteraction = true);
0096 
0097     bool costCenterChanged(int costCenterIndex);
0098     bool categoryChanged(const QString& accountId);
0099     bool numberChanged(const QString& newNumber);
0100     bool amountChanged();
0101     void setupTabOrder();
0102     void createCategory();
0103     void createPayee();
0104     void createTag();
0105 
0106     NewSplitEditor* q;
0107     Ui_NewSplitEditor* ui;
0108     Ui_NewSplitEditor* tabOrderUi;
0109     AccountNamesFilterProxyModel* accountsModel;
0110     QSortFilterProxyModel* payeesModel;
0111     QSortFilterProxyModel* costCenterModel;
0112     SplitModel* splitModel;
0113     bool accepted;
0114     bool costCenterRequired;
0115     bool showValuesInverted;
0116     bool loadingSplit;
0117     bool isIncomeExpense;
0118     bool readOnly;
0119     MyMoneyAccount counterAccount;
0120     MyMoneyAccount category;
0121     MyMoneySecurity commodity;
0122     MyMoneyMoney value;
0123     MyMoneyMoney shares;
0124     QDate postDate;
0125     WidgetHintFrameCollection* frameCollection;
0126 };
0127 
0128 bool NewSplitEditor::Private::checkForValidSplit(bool doUserInteraction)
0129 {
0130     QStringList infos;
0131     bool rc = true;
0132     if(!costCenterChanged(ui->costCenterCombo->currentIndex())) {
0133         infos << ui->costCenterCombo->toolTip();
0134         rc = false;
0135     }
0136 
0137     if (!categoryChanged(ui->accountCombo->getSelected())) {
0138         infos << ui->accountCombo->toolTip();
0139         rc = false;
0140     }
0141 
0142     if(doUserInteraction) {
0143         /// @todo add dialog here that shows the @a infos
0144     }
0145     return rc;
0146 }
0147 
0148 bool NewSplitEditor::Private::costCenterChanged(int costCenterIndex)
0149 {
0150     bool rc = true;
0151     WidgetHintFrame::hide(ui->costCenterCombo,
0152                           i18nc("@info:tooltip costcenter combo in split editor", "The cost center this transaction should be assigned to."));
0153     if(costCenterIndex != -1) {
0154         if(costCenterRequired && ui->costCenterCombo->currentText().isEmpty()) {
0155             WidgetHintFrame::show(
0156                 ui->costCenterCombo,
0157                 i18nc("@info:tooltip costcenter combo in split editor", "A cost center assignment is required for a transaction in the selected category."));
0158             rc = false;
0159         }
0160     }
0161     return rc;
0162 }
0163 
0164 bool NewSplitEditor::Private::categoryChanged(const QString& accountId)
0165 {
0166     bool rc = true;
0167     isIncomeExpense = false;
0168     WidgetHintFrame::hide(ui->accountCombo, i18nc("@info:tooltip category combo in split editor", "The category this split should be assigned to."));
0169     if(!accountId.isEmpty()) {
0170         try {
0171             const auto account = MyMoneyFile::instance()->account(accountId);
0172             const bool isCategory = account.isIncomeExpense();
0173             ui->costCenterCombo->setEnabled(isCategory);
0174             ui->costCenterLabel->setEnabled(isCategory);
0175             ui->numberEdit->setDisabled(isCategory);
0176             ui->numberLabel->setDisabled(isCategory);
0177 
0178             if (isCategory) {
0179                 ui->numberEdit->clear();
0180             } else {
0181                 numberChanged(ui->numberEdit->text());
0182             }
0183 
0184             const auto accountIdx = MyMoneyFile::instance()->accountsModel()->indexById(accountId);
0185             const auto currencyId = accountIdx.data(eMyMoney::Model::AccountCurrencyIdRole).toString();
0186             const auto currency = MyMoneyFile::instance()->currenciesModel()->itemById(currencyId);
0187 
0188             // in case the commodity changes, we need to update the shares part
0189             if (currency.id() != ui->creditDebitEdit->sharesCommodity().id()) {
0190                 ui->creditDebitEdit->setSharesCommodity(currency);
0191                 const auto sharesAmount = ui->creditDebitEdit->value();
0192                 ui->creditDebitEdit->setShares(sharesAmount);
0193                 // switch to value display so that we show the transaction commodity
0194                 // for single currency data entry this does not have an effect
0195                 ui->creditDebitEdit->setDisplayState(MultiCurrencyEdit::DisplayValue);
0196 
0197                 if (!sharesAmount.isZero()) {
0198                     KCurrencyCalculator::updateConversion(ui->creditDebitEdit, postDate);
0199                 }
0200             }
0201 
0202             costCenterRequired = account.isCostCenterRequired();
0203             rc &= costCenterChanged(ui->costCenterCombo->currentIndex());
0204 
0205         } catch (MyMoneyException&) {
0206             qDebug() << "Ooops: invalid account id" << accountId << "in" << Q_FUNC_INFO;
0207         }
0208     } else {
0209         WidgetHintFrame::show(ui->accountCombo, i18nc("@info:tooltip category combo in split editor", "A category assignment is required for a split."));
0210         rc = false;
0211     }
0212     return rc;
0213 }
0214 
0215 bool NewSplitEditor::Private::numberChanged(const QString& newNumber)
0216 {
0217     bool rc = true;
0218     WidgetHintFrame::hide(ui->numberEdit, i18n("The check number used for this transaction."));
0219     if(!newNumber.isEmpty()) {
0220         const auto model = MyMoneyFile::instance()->journalModel();
0221         const auto rows = model->rowCount();
0222         const auto accountId = ui->accountCombo->getSelected();
0223         for (int row = 0; row < rows; ++row) {
0224             const auto idx = model->index(row, 0);
0225             if (idx.data(eMyMoney::Model::JournalSplitAccountIdRole).toString() == accountId) {
0226                 if (idx.data(eMyMoney::Model::JournalSplitNumberRole).toString() == newNumber) {
0227                     WidgetHintFrame::show(ui->numberEdit, i18n("The check number <b>%1</b> has already been used in this account.", newNumber));
0228                     rc = false;
0229                     break;
0230                 }
0231             }
0232         }
0233     }
0234     return rc;
0235 }
0236 
0237 bool NewSplitEditor::Private::amountChanged()
0238 {
0239     // bypass a simple reverse in sign because the exchange rate does not change
0240     if ((shares != -ui->creditDebitEdit->shares()) || (value != -ui->creditDebitEdit->value())) {
0241         // and if there is no real change, don't call the currency calculator
0242         if ((shares != ui->creditDebitEdit->shares()) || (value != ui->creditDebitEdit->value())) {
0243             KCurrencyCalculator::updateConversion(ui->creditDebitEdit, postDate);
0244             shares = ui->creditDebitEdit->shares();
0245             value = ui->creditDebitEdit->value();
0246         }
0247     } else {
0248         shares = -shares;
0249         value = -value;
0250     }
0251     return true;
0252 }
0253 
0254 void NewSplitEditor::Private::setupTabOrder()
0255 {
0256     const auto defaultTabOrder = QStringList{
0257         QLatin1String("creditDebitEdit"),
0258         QLatin1String("payeeEdit"),
0259         QLatin1String("numberEdit"),
0260         QLatin1String("accountCombo"),
0261         QLatin1String("costCenterCombo"),
0262         QLatin1String("tagContainer"),
0263         QLatin1String("memoEdit"),
0264         QLatin1String("enterButton"),
0265         QLatin1String("cancelButton"),
0266     };
0267     q->setProperty("kmm_defaulttaborder", defaultTabOrder);
0268     q->setProperty("kmm_currenttaborder", KMyMoneyUtils::tabOrder(QLatin1String("splitTransactionEditor"), defaultTabOrder));
0269 
0270     KMyMoneyUtils::setupTabOrder(q, q->property("kmm_currenttaborder").toStringList());
0271 }
0272 
0273 void NewSplitEditor::Private::createCategory()
0274 {
0275     // delay the execution of this code for 150ms so
0276     // that a click on the cancel or enter button has
0277     // a chance to be executed before.
0278     auto creator = new AccountCreator(q);
0279     creator->setComboBox(ui->accountCombo);
0280     creator->addButton(ui->cancelButton);
0281     creator->addButton(ui->enterButton);
0282     creator->setAccountType(eMyMoney::Account::Type::Expense);
0283     if (ui->creditDebitEdit->haveValue() && ui->creditDebitEdit->value().isPositive()) {
0284         creator->setAccountType(eMyMoney::Account::Type::Income);
0285     }
0286     creator->createAccount();
0287 }
0288 
0289 void NewSplitEditor::Private::createPayee()
0290 {
0291     auto creator = new PayeeCreator(q);
0292     creator->setComboBox(ui->payeeEdit);
0293     creator->addButton(ui->cancelButton);
0294     creator->addButton(ui->enterButton);
0295     creator->createPayee();
0296 }
0297 
0298 void NewSplitEditor::Private::createTag()
0299 {
0300     auto creator = new TagCreator(q);
0301     creator->setTagContainer(ui->tagContainer);
0302     creator->addButton(ui->cancelButton);
0303     creator->addButton(ui->enterButton);
0304     creator->createTag();
0305 }
0306 
0307 NewSplitEditor::NewSplitEditor(QWidget* parent, const MyMoneySecurity& commodity, const QString& counterAccountId)
0308     : QWidget(parent)
0309     , d(new Private(this))
0310 {
0311     d->commodity = commodity;
0312     auto const file = MyMoneyFile::instance();
0313     auto view = qobject_cast<SplitView*>(parent->parentWidget());
0314     Q_ASSERT(view != nullptr);
0315     d->splitModel = qobject_cast<SplitModel*>(view->model());
0316 
0317     auto const model = MyMoneyFile::instance()->accountsModel();
0318     d->counterAccount = model->itemById(counterAccountId);
0319 
0320     d->ui->setupUi(this);
0321     d->ui->enterButton->setIcon(Icons::get(Icon::DialogOK));
0322     d->ui->cancelButton->setIcon(Icons::get(Icon::DialogCancel));
0323 
0324     auto concatModel = new QConcatenateTablesProxyModel(parent);
0325     concatModel->addSourceModel(file->payeesModel()->emptyPayee());
0326     concatModel->addSourceModel(file->payeesModel());
0327     d->payeesModel->setSortRole(Qt::DisplayRole);
0328     d->payeesModel->setSourceModel(concatModel);
0329     d->payeesModel->sort(0);
0330 
0331     d->ui->payeeEdit->setEditable(true);
0332     d->ui->payeeEdit->lineEdit()->setClearButtonEnabled(true);
0333     d->ui->payeeEdit->setModel(d->payeesModel);
0334     d->ui->payeeEdit->setModelColumn(0);
0335     d->ui->payeeEdit->completer()->setCompletionMode(QCompleter::PopupCompletion);
0336     d->ui->payeeEdit->completer()->setFilterMode(Qt::MatchContains);
0337 
0338     d->accountsModel->addAccountGroup(QVector<eMyMoney::Account::Type> {eMyMoney::Account::Type::Asset, eMyMoney::Account::Type::Liability, eMyMoney::Account::Type::Income, eMyMoney::Account::Type::Expense, eMyMoney::Account::Type::Equity,});
0339     d->accountsModel->setHideEquityAccounts(false);
0340     d->accountsModel->setHideZeroBalancedEquityAccounts(false);
0341     d->accountsModel->setHideZeroBalancedAccounts(false);
0342     d->accountsModel->setShowAllEntries(KMyMoneySettings::showAllAccounts());
0343     d->accountsModel->setSourceModel(model);
0344     d->accountsModel->sort(AccountsModel::Column::AccountName);
0345     d->ui->accountCombo->setModel(d->accountsModel);
0346     d->ui->accountCombo->setSplitActionVisible(false);
0347 
0348     d->ui->tagContainer->setModel(file->tagsModel()->modelWithEmptyItem());
0349 
0350     d->costCenterModel->setSortRole(Qt::DisplayRole);
0351     d->costCenterModel->setSourceModel(MyMoneyFile::instance()->costCenterModel());
0352     d->costCenterModel->sort(AccountsModel::Column::AccountName);
0353 
0354     d->ui->costCenterCombo->setEditable(true);
0355     d->ui->costCenterCombo->setModel(d->costCenterModel);
0356     d->ui->costCenterCombo->setModelColumn(0);
0357     d->ui->costCenterCombo->completer()->setFilterMode(Qt::MatchContains);
0358 
0359     d->frameCollection = new WidgetHintFrameCollection(this);
0360     d->frameCollection->addFrame(new WidgetHintFrame(d->ui->costCenterCombo));
0361     d->frameCollection->addFrame(new WidgetHintFrame(d->ui->accountCombo));
0362     d->frameCollection->addFrame(new WidgetHintFrame(d->ui->numberEdit, WidgetHintFrame::Warning));
0363     d->frameCollection->addWidget(d->ui->enterButton);
0364 
0365     d->ui->creditDebitEdit->setAllowEmpty(true);
0366     d->ui->creditDebitEdit->setCommodity(commodity);
0367 
0368     connect(d->ui->numberEdit, &QLineEdit::textChanged, this, [&](const QString& txt) {
0369         d->numberChanged(txt);
0370     });
0371     connect(d->ui->costCenterCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [&](int costCenterIndex) {
0372         d->costCenterChanged(costCenterIndex);
0373     });
0374     connect(d->ui->accountCombo, &KMyMoneyAccountCombo::accountSelected, this, [&](const QString& categoryId) {
0375         d->categoryChanged(categoryId);
0376     });
0377     connect(d->ui->creditDebitEdit, &CreditDebitEdit::amountChanged, this, [&]() {
0378         d->amountChanged();
0379     });
0380 
0381     connect(d->ui->cancelButton, &QToolButton::clicked, this, &NewSplitEditor::reject);
0382     connect(d->ui->enterButton, &QToolButton::clicked, this, &NewSplitEditor::acceptEdit);
0383 
0384     d->ui->accountCombo->installEventFilter(this);
0385     d->ui->payeeEdit->installEventFilter(this);
0386 
0387     // setup the tab order
0388     d->setupTabOrder();
0389 
0390     // determine order of credit and debit edit widgets
0391     // based on their visual order in the ledger
0392     int creditColumn = SplitModel::Column::Payment;
0393     int debitColumn = SplitModel::Column::Deposit;
0394 
0395     QWidget* w(this);
0396     do {
0397         w = w->parentWidget();
0398         const auto v = qobject_cast<const QTableView*>(w);
0399         if (v) {
0400             creditColumn = v->horizontalHeader()->visualIndex(creditColumn);
0401             debitColumn = v->horizontalHeader()->visualIndex(debitColumn);
0402             break;
0403         }
0404     } while (w);
0405 
0406     // in case they are in the opposite order, we swap the edit widgets
0407     if (debitColumn < creditColumn) {
0408         d->ui->creditDebitEdit->swapCreditDebit();
0409     }
0410 
0411     // set focus to first tab field once we return to event loop
0412     const auto tabOrder = property("kmm_currenttaborder").toStringList();
0413     if (!tabOrder.isEmpty()) {
0414         const auto focusWidget = findChild<QWidget*>(tabOrder.first());
0415         if (focusWidget) {
0416             QMetaObject::invokeMethod(focusWidget, "setFocus", Qt::QueuedConnection);
0417         }
0418     }
0419 }
0420 
0421 NewSplitEditor::~NewSplitEditor()
0422 {
0423 }
0424 
0425 void NewSplitEditor::setAmountPlaceHolderText(const QAbstractItemModel* model)
0426 {
0427     d->ui->creditDebitEdit->setPlaceholderText(model->headerData(SplitModel::Column::Payment, Qt::Horizontal).toString(),
0428                                                model->headerData(SplitModel::Column::Deposit, Qt::Horizontal).toString());
0429 }
0430 
0431 void NewSplitEditor::setPostDate(const QDate& date)
0432 {
0433     d->postDate = date;
0434 }
0435 
0436 void NewSplitEditor::setShowValuesInverted(bool inverse)
0437 {
0438     d->showValuesInverted = inverse;
0439 }
0440 
0441 bool NewSplitEditor::showValuesInverted()
0442 {
0443     return d->showValuesInverted;
0444 }
0445 
0446 bool NewSplitEditor::accepted() const
0447 {
0448     return d->accepted;
0449 }
0450 
0451 void NewSplitEditor::acceptEdit()
0452 {
0453     if(d->checkForValidSplit()) {
0454         d->accepted = true;
0455         Q_EMIT done();
0456     }
0457 }
0458 
0459 void NewSplitEditor::reject()
0460 {
0461     Q_EMIT done();
0462 }
0463 
0464 void NewSplitEditor::keyPressEvent(QKeyEvent* event)
0465 {
0466     if (!event->modifiers() || (event->modifiers() & Qt::KeypadModifier && event->key() == Qt::Key_Enter)) {
0467         switch (event->key()) {
0468         case Qt::Key_Enter:
0469         case Qt::Key_Return:
0470         {
0471             if(focusWidget() == d->ui->cancelButton) {
0472                 reject();
0473             } else {
0474                 if (d->ui->enterButton->isEnabled() && !d->readOnly) {
0475                     d->ui->enterButton->setFocus();
0476                     d->ui->enterButton->click();
0477                 }
0478                 return;
0479             }
0480         }
0481         break;
0482 
0483         case Qt::Key_Escape:
0484             reject();
0485             break;
0486 
0487         default:
0488             event->ignore();
0489             return;
0490         }
0491     } else {
0492         const auto keySeq = QKeySequence(event->modifiers() | event->key());
0493 
0494         if (keySeq.matches(pActions[eMenu::Action::EditTabOrder]->shortcut())) {
0495             QPointer<TabOrderDialog> tabOrderDialog = new TabOrderDialog(this);
0496             auto tabOrderWidget = static_cast<TabOrderEditorInterface*>(qt_metacast("TabOrderEditorInterface"));
0497             if (tabOrderWidget) {
0498                 tabOrderDialog->setTarget(tabOrderWidget);
0499                 auto tabOrder = property("kmm_defaulttaborder").toStringList();
0500                 tabOrderDialog->setDefaultTabOrder(tabOrder);
0501                 tabOrder = property("kmm_currenttaborder").toStringList();
0502                 tabOrderDialog->setTabOrder(tabOrder);
0503 
0504                 if ((tabOrderDialog->exec() == QDialog::Accepted) && tabOrderDialog) {
0505                     tabOrderWidget->storeTabOrder(tabOrderDialog->tabOrder());
0506                     d->setupTabOrder();
0507                 }
0508             }
0509             tabOrderDialog->deleteLater();
0510         }
0511         event->ignore();
0512     }
0513 }
0514 
0515 QString NewSplitEditor::accountId() const
0516 {
0517     return d->ui->accountCombo->getSelected();
0518 }
0519 
0520 void NewSplitEditor::setAccountId(const QString& id)
0521 {
0522     d->ui->accountCombo->clearEditText();
0523     d->ui->accountCombo->setSelected(id);
0524 }
0525 
0526 
0527 QString NewSplitEditor::memo() const
0528 {
0529     return d->ui->memoEdit->toPlainText();
0530 }
0531 
0532 void NewSplitEditor::setMemo(const QString& memo)
0533 {
0534     d->ui->memoEdit->setPlainText(memo);
0535 }
0536 
0537 MyMoneyMoney NewSplitEditor::shares() const
0538 {
0539     return d->ui->creditDebitEdit->shares();
0540 }
0541 
0542 void NewSplitEditor::setShares(const MyMoneyMoney& amount)
0543 {
0544     d->shares = amount;
0545     d->ui->creditDebitEdit->setShares(amount);
0546 }
0547 
0548 MyMoneyMoney NewSplitEditor::value() const
0549 {
0550     return d->ui->creditDebitEdit->value();
0551 }
0552 
0553 void NewSplitEditor::setValue(const MyMoneyMoney& amount)
0554 {
0555     d->value = amount;
0556     d->ui->creditDebitEdit->setValue(amount);
0557 }
0558 
0559 QString NewSplitEditor::costCenterId() const
0560 {
0561     const int row = d->ui->costCenterCombo->currentIndex();
0562     QModelIndex index = d->ui->costCenterCombo->model()->index(row, 0);
0563     return d->ui->costCenterCombo->model()->data(index, eMyMoney::Model::Roles::IdRole).toString();
0564 }
0565 
0566 void NewSplitEditor::setCostCenterId(const QString& id)
0567 {
0568     const auto baseIdx = MyMoneyFile::instance()->costCenterModel()->indexById(id);
0569     if (baseIdx.isValid()) {
0570         const auto index = MyMoneyFile::baseModel()->mapFromBaseSource(d->costCenterModel, baseIdx);
0571         if(index.isValid()) {
0572             d->ui->costCenterCombo->setCurrentIndex(index.row());
0573         }
0574     }
0575 }
0576 
0577 QString NewSplitEditor::number() const
0578 {
0579     return d->ui->numberEdit->text();
0580 }
0581 
0582 void NewSplitEditor::setNumber(const QString& number)
0583 {
0584     d->ui->numberEdit->setText(number);
0585 }
0586 
0587 QString NewSplitEditor::payeeId() const
0588 {
0589     const auto idx = d->payeesModel->index(d->ui->payeeEdit->currentIndex(), 0);
0590     return idx.data(eMyMoney::Model::IdRole).toString();
0591 }
0592 
0593 void NewSplitEditor::setPayeeId(const QString& id)
0594 {
0595     QModelIndexList indexes = d->payeesModel->match(d->payeesModel->index(0, 0), eMyMoney::Model::IdRole, QVariant(id), 1, Qt::MatchFlags(Qt::MatchFlags(Qt::MatchExactly | Qt::MatchCaseSensitive | Qt::MatchRecursive)));
0596     int row(0);
0597     if (!indexes.isEmpty()) {
0598         row = indexes.first().row();
0599     }
0600     d->ui->payeeEdit->setCurrentIndex(row);
0601 }
0602 
0603 void NewSplitEditor::setTagIdList(const QList<QString>& tagIds)
0604 {
0605     d->ui->tagContainer->loadTags(tagIds);
0606 }
0607 
0608 QList<QString> NewSplitEditor::tagIdList() const
0609 {
0610     return d->ui->tagContainer->selectedTags();
0611 }
0612 
0613 void NewSplitEditor::startLoadingSplit()
0614 {
0615     d->loadingSplit = true;
0616 }
0617 
0618 void NewSplitEditor::finishLoadingSplit()
0619 {
0620     d->loadingSplit = false;
0621 }
0622 
0623 void NewSplitEditor::setReadOnly(bool readOnly)
0624 {
0625     if (d->readOnly != readOnly) {
0626         d->readOnly = readOnly;
0627         if (readOnly) {
0628             d->frameCollection->removeWidget(d->ui->enterButton);
0629             d->ui->enterButton->setDisabled(true);
0630         } else {
0631             // no need to enable the enter button here as the
0632             // framewidget will take care of it anyway
0633             d->frameCollection->addWidget(d->ui->enterButton);
0634         }
0635     }
0636 }
0637 
0638 void NewSplitEditor::setupUi(QWidget* parent)
0639 {
0640     if (d->tabOrderUi == nullptr) {
0641         d->tabOrderUi = new Ui::NewSplitEditor;
0642     }
0643     d->tabOrderUi->setupUi(parent);
0644 }
0645 
0646 void NewSplitEditor::storeTabOrder(const QStringList& tabOrder)
0647 {
0648     KMyMoneyUtils::storeTabOrder(QLatin1String("splitTransactionEditor"), tabOrder);
0649 }
0650 
0651 bool NewSplitEditor::focusNextPrevChild(bool next)
0652 {
0653     auto rc = KMyMoneyUtils::tabFocusHelper(this, next);
0654 
0655     if (rc == false) {
0656         rc = QWidget::focusNextPrevChild(next);
0657     }
0658     return rc;
0659 }
0660 
0661 bool NewSplitEditor::eventFilter(QObject* o, QEvent* e)
0662 {
0663     auto cb = qobject_cast<QComboBox*>(o);
0664     if (o) {
0665         // filter out wheel events for combo boxes if the popup view is not visible
0666         if ((e->type() == QEvent::Wheel) && !cb->view()->isVisible()) {
0667             return true;
0668         }
0669 
0670         if (e->type() == QEvent::FocusOut) {
0671             if (o == d->ui->accountCombo) {
0672                 if (!d->ui->accountCombo->popup()->isVisible() && !cb->currentText().isEmpty()) {
0673                     const auto accountId = d->ui->accountCombo->getSelected();
0674                     const auto accountIdx = MyMoneyFile::instance()->accountsModel()->indexById(accountId);
0675                     if (!accountIdx.isValid() || accountIdx.data(eMyMoney::Model::AccountFullNameRole).toString().compare(cb->currentText())) {
0676                         d->createCategory();
0677                     }
0678                 }
0679 
0680             } else if (o == d->ui->payeeEdit) {
0681                 if (!cb->currentText().isEmpty()) {
0682                     const auto index(cb->findText(cb->currentText(), Qt::MatchExactly | Qt::MatchCaseSensitive));
0683                     if (index != -1) {
0684                         cb->setCurrentIndex(index);
0685                     } else {
0686                         d->createPayee();
0687                     }
0688                 }
0689             } else if (o == d->ui->tagContainer->tagCombo()) {
0690                 if (!cb->currentText().isEmpty()) {
0691                     const auto index(cb->findText(cb->currentText(), Qt::MatchExactly | Qt::MatchCaseSensitive));
0692                     if (index != -1) {
0693                         cb->setCurrentIndex(index);
0694                     } else {
0695                         d->createTag();
0696                     }
0697                 }
0698             }
0699         }
0700     }
0701     return QWidget::eventFilter(o, e);
0702 }