File indexing completed on 2024-05-12 05:07:55
0001 /* 0002 SPDX-FileCopyrightText: 2004-2020 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 "kmymoneyaccountcombo.h" 0008 0009 // ---------------------------------------------------------------------------- 0010 // QT Includes 0011 0012 #include <QAction> 0013 #include <QEvent> 0014 #include <QKeyEvent> 0015 #include <QLineEdit> 0016 #include <QList> 0017 #include <QRegularExpression> 0018 #include <QTreeView> 0019 0020 // ---------------------------------------------------------------------------- 0021 // KDE Includes 0022 0023 #include <KLocalizedString> 0024 0025 // ---------------------------------------------------------------------------- 0026 // Project Includes 0027 0028 #include "mymoneyfile.h" 0029 #include "mymoneyenums.h" 0030 #include "accountsmodel.h" 0031 #include "icons.h" 0032 0033 class KMyMoneyAccountCombo::Private 0034 { 0035 public: 0036 Private(KMyMoneyAccountCombo* q) 0037 : m_q(q) 0038 , m_popupView(nullptr) 0039 , m_splitAction(nullptr) 0040 , m_inMakeCompletion(false) 0041 { 0042 m_q->setInsertPolicy(QComboBox::NoInsert); 0043 m_q->setMinimumWidth(m_q->fontMetrics().horizontalAdvance(QLatin1Char('W')) * 15); 0044 m_q->setMaxVisibleItems(15); 0045 } 0046 0047 KMyMoneyAccountCombo* m_q; 0048 QTreeView* m_popupView; 0049 QAction* m_splitAction; 0050 QString m_lastSelectedAccount; 0051 QModelIndex m_lastSelectedIndex; 0052 bool m_inMakeCompletion; 0053 0054 void selectFirstMatchingItem() 0055 { 0056 if(m_popupView) { 0057 QSignalBlocker blocker(m_popupView); 0058 m_popupView->setCurrentIndex(QModelIndex()); 0059 const auto rows = m_q->model()->rowCount(); 0060 const auto filterModel = qobject_cast<AccountNamesFilterProxyModel*>(m_q->model()); 0061 const auto filterExp = filterModel->filterRegularExpression(); 0062 for (auto i = 0; i < rows; ++i) { 0063 QModelIndex childIndex = filterModel->index(i, 0); 0064 if (filterModel->hasChildren(childIndex)) { 0065 // search the first match by walking down the first leaf 0066 do { 0067 childIndex = filterModel->index(0, 0, childIndex); 0068 if (filterModel->flags(childIndex) & Qt::ItemIsSelectable) { 0069 if (filterExp.match(childIndex.data(eMyMoney::Model::AccountFullHierarchyNameRole).toString()).hasMatch()) { 0070 break; 0071 } 0072 } 0073 } while (filterModel->hasChildren(childIndex)); 0074 0075 // make it the current selection if it's selectable 0076 if (filterModel->flags(childIndex) & Qt::ItemIsSelectable) { 0077 m_popupView->setCurrentIndex(childIndex); 0078 } 0079 break; 0080 } 0081 } 0082 } 0083 } 0084 0085 /** 0086 * Find which item has the @a id and return its index 0087 * into the model of the KMyMoneyAccountCombo. In case 0088 * no item is found, an invalid QModelIndex will be 0089 * returned. If the current selection is pointing to 0090 * one of the favorite accounts, the index for the 0091 * corresponding entry in the hierarchy will be returned. 0092 */ 0093 QModelIndex findMatchingItem(const QString& id) 0094 { 0095 const auto startRow = 0096 m_q->model()->index(0, 0).data(eMyMoney::Model::Roles::IdRole).toString() == MyMoneyAccount::stdAccName(eMyMoney::Account::Standard::Favorite) ? 1 0097 : 0; 0098 // Note: Without Qt::MatchWrap we might not get results for credit card 0099 const auto list = m_q->model()->match(m_q->model()->index(startRow, 0), 0100 eMyMoney::Model::Roles::IdRole, 0101 QVariant(id), 0102 1, 0103 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap | Qt::MatchRecursive)); 0104 if (!list.isEmpty()) { 0105 return list.first(); 0106 } 0107 return {}; 0108 } 0109 0110 /** 0111 * Set the current index based on the QModelIndex @a idx. 0112 * While setting the index, the signals sent out by the 0113 * KMyMoneyAccountCombo are blocked. 0114 */ 0115 void setCurrentIndex(const QModelIndex& idx) 0116 { 0117 QSignalBlocker blocker(m_q); 0118 m_q->setRootModelIndex(idx.parent()); 0119 m_q->setCurrentIndex(idx.row()); 0120 m_q->setRootModelIndex(QModelIndex()); 0121 } 0122 0123 void showSplitAction(bool show) 0124 { 0125 if (show && !m_splitAction) { 0126 m_splitAction = m_q->lineEdit()->addAction(Icons::get(Icons::Icon::Split), QLineEdit::TrailingPosition); 0127 // this for some reason does not work and I had to 0128 // add logic to the eventFilter below to catch this 0129 // key-sequence. Left it here, since it does not hurt either. 0130 m_splitAction->setShortcut(QKeySequence(QStringLiteral("Ctrl+ "))); 0131 m_splitAction->setToolTip(i18nc("@info:tooltip icon in category to open the split editor", "Click this icon to open the split editor")); 0132 m_q->connect(m_splitAction, &QAction::triggered, m_q, &KMyMoneyAccountCombo::splitDialogRequest); 0133 0134 } else if(!show && m_splitAction) { 0135 m_q->lineEdit()->removeAction(m_splitAction); 0136 m_splitAction->deleteLater(); 0137 m_splitAction = nullptr; 0138 } 0139 } 0140 }; 0141 0142 0143 0144 0145 0146 KMyMoneyAccountCombo::KMyMoneyAccountCombo(QSortFilterProxyModel *model, QWidget *parent) 0147 : KComboBox(parent) 0148 , d(new Private(this)) 0149 { 0150 init(); 0151 setModel(model); 0152 } 0153 0154 KMyMoneyAccountCombo::KMyMoneyAccountCombo(QWidget *parent) 0155 : KComboBox(parent) 0156 , d(new Private(this)) 0157 { 0158 init(); 0159 } 0160 0161 void KMyMoneyAccountCombo::init() 0162 { 0163 setMaxVisibleItems(15); 0164 setSizeAdjustPolicy(QComboBox::AdjustToContents); 0165 } 0166 0167 KMyMoneyAccountCombo::~KMyMoneyAccountCombo() 0168 { 0169 } 0170 0171 void KMyMoneyAccountCombo::setEditable(bool isEditable) 0172 { 0173 KComboBox::setEditable(isEditable); 0174 // don't do the standard behavior 0175 if(lineEdit()) { 0176 lineEdit()->setClearButtonEnabled(true); 0177 connect(lineEdit(), &QLineEdit::textEdited, this, &KMyMoneyAccountCombo::makeCompletion, Qt::UniqueConnection); 0178 installEventFilter(this); 0179 d->showSplitAction(true); 0180 } 0181 } 0182 0183 void KMyMoneyAccountCombo::setSplitActionVisible(bool show) 0184 { 0185 if (lineEdit()) { 0186 d->showSplitAction(show); 0187 } 0188 } 0189 0190 void KMyMoneyAccountCombo::wheelEvent(QWheelEvent *ev) 0191 { 0192 Q_UNUSED(ev) 0193 // don't change anything with the help of the wheel, yet (due to the tree model) 0194 } 0195 0196 void KMyMoneyAccountCombo::expandAll() 0197 { 0198 if (d->m_popupView) 0199 d->m_popupView->expandAll(); 0200 } 0201 0202 void KMyMoneyAccountCombo::collapseAll() 0203 { 0204 if (d->m_popupView) 0205 d->m_popupView->collapseAll(); 0206 } 0207 0208 void KMyMoneyAccountCombo::activated() 0209 { 0210 auto accountId = view()->currentIndex().data(eMyMoney::Model::Roles::IdRole).toString(); 0211 if (!accountId.isEmpty() && !(lineEdit() && lineEdit()->text().isEmpty())) { 0212 selectItem(view()->currentIndex()); 0213 } 0214 } 0215 0216 bool KMyMoneyAccountCombo::eventFilter(QObject* o, QEvent* e) 0217 { 0218 if(isEditable()) { 0219 if (o == d->m_popupView) { 0220 // propagate all relevant key press events to the lineEdit widget 0221 if(e->type() == QEvent::KeyPress) { 0222 QKeyEvent* kev = static_cast<QKeyEvent*>(e); 0223 bool forLineEdit = (kev->text().length() > 0); 0224 switch(kev->key()) { 0225 case Qt::Key_Tab: 0226 case Qt::Key_Backtab: { 0227 const auto idx = view()->currentIndex(); 0228 const auto accountId = idx.data(eMyMoney::Model::Roles::IdRole).toString(); 0229 if (!accountId.isEmpty()) { 0230 d->m_lastSelectedAccount = accountId; 0231 QSignalBlocker blocker(lineEdit()); 0232 lineEdit()->setText(idx.data(eMyMoney::Model::Roles::AccountFullNameRole).toString()); 0233 d->setCurrentIndex(d->findMatchingItem(accountId)); 0234 Q_EMIT accountSelected(accountId); 0235 } 0236 hidePopup(); 0237 break; 0238 } 0239 0240 case Qt::Key_Escape: 0241 case Qt::Key_Up: 0242 case Qt::Key_Down: 0243 forLineEdit = false; 0244 break; 0245 default: 0246 break; 0247 } 0248 if(forLineEdit) { 0249 return lineEdit()->event(e); 0250 } 0251 } else if(e->type() == QEvent::KeyRelease) { 0252 QKeyEvent* kev = static_cast<QKeyEvent*>(e); 0253 switch(kev->key()) { 0254 case Qt::Key_Escape: 0255 hidePopup(); 0256 return true; 0257 0258 case Qt::Key_Enter: 0259 case Qt::Key_Return: 0260 activated(); 0261 hidePopup(); 0262 break; 0263 default: 0264 break; 0265 } 0266 0267 } else if(e->type() == QEvent::FocusOut) { 0268 hidePopup(); 0269 } 0270 0271 } else if(o == this) { 0272 if(e->type() == QEvent::KeyPress) { 0273 const auto kev = static_cast<QKeyEvent*>(e); 0274 if (kev->modifiers() & Qt::ControlModifier && kev->key() == Qt::Key_Space) { 0275 Q_EMIT splitDialogRequest(); 0276 return true; 0277 } 0278 } 0279 } 0280 } 0281 return KComboBox::eventFilter(o, e); 0282 } 0283 0284 void KMyMoneyAccountCombo::setSelected(const QString& id) 0285 { 0286 if (id.isEmpty()) { 0287 d->m_lastSelectedAccount.clear(); 0288 d->m_popupView->selectionModel()->clearSelection(); 0289 d->m_popupView->setCurrentIndex(QModelIndex()); 0290 setRootModelIndex(QModelIndex()); 0291 setCurrentIndex(-1); 0292 Q_EMIT accountSelected(id); 0293 return; 0294 } 0295 0296 if (id == d->m_lastSelectedAccount) { 0297 // nothing to do 0298 return; 0299 } 0300 0301 // make sure, we have all items available for search 0302 if(isEditable()) { 0303 lineEdit()->clear(); 0304 } 0305 0306 // reset the filter of the model 0307 auto* filterModel = qobject_cast<QSortFilterProxyModel*>(model()); 0308 filterModel->setFilterFixedString(QString()); 0309 0310 const auto idx = d->findMatchingItem(id); 0311 if (idx.isValid()) { 0312 // make sure the popup is closed from here on 0313 hidePopup(); 0314 d->m_lastSelectedAccount = id; 0315 d->setCurrentIndex(idx); 0316 Q_EMIT accountSelected(id); 0317 } 0318 } 0319 0320 const QString& KMyMoneyAccountCombo::getSelected() const 0321 { 0322 return d->m_lastSelectedAccount; 0323 } 0324 0325 void KMyMoneyAccountCombo::setModel(QSortFilterProxyModel *model) 0326 { 0327 // CAUTION! Assumption is being made that AccountName column number is always 0 0328 if (AccountsModel::Column::AccountName != 0) { 0329 qFatal("AccountsModel::Column::AccountName must be 0 in accountsmodel.h"); 0330 } 0331 0332 // since we create a new popup view, we get rid of an existing one 0333 delete d->m_popupView; 0334 0335 // call base class implementation 0336 KComboBox::setModel(model); 0337 0338 // setup filtering criteria 0339 model->setFilterKeyColumn(AccountsModel::Column::AccountName); 0340 model->setFilterRole(eMyMoney::Model::Roles::AccountFullHierarchyNameRole); 0341 0342 // create popup view, attach model and allow to select a single item 0343 d->m_popupView = new QTreeView(this); 0344 d->m_popupView->setModel(model); 0345 d->m_popupView->setSelectionMode(QAbstractItemView::SingleSelection); 0346 setView(d->m_popupView); 0347 0348 // setup view parameters 0349 d->m_popupView->setHeaderHidden(true); 0350 d->m_popupView->setRootIsDecorated(true); 0351 d->m_popupView->setAlternatingRowColors(true); 0352 d->m_popupView->setAnimated(true); 0353 0354 d->m_popupView->expandAll(); 0355 connect(d->m_popupView, &QTreeView::activated, this, &KMyMoneyAccountCombo::selectItem); 0356 0357 d->m_popupView->installEventFilter(this); 0358 0359 // for some unknown reason, the first selection with the mouse (not with the keyboard) 0360 // after the qlineedit had been cleared using the clear button does not trigger the 0361 // activated() signal of d->m_popupView. This is a workaround to catch this scenario 0362 // and still get valid settings. 0363 connect(this, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [&](int index) { 0364 if (index != -1) { 0365 const auto idx = d->m_popupView->currentIndex(); 0366 if (idx.isValid()) { 0367 if (d->m_lastSelectedAccount.isEmpty() || (idx.data(eMyMoney::Model::IdRole).toString() != d->m_lastSelectedAccount)) { 0368 selectItem(idx); 0369 } 0370 } 0371 } 0372 }); 0373 0374 if(isEditable()) { 0375 connect(lineEdit(), &QLineEdit::textEdited, this, &KMyMoneyAccountCombo::makeCompletion, Qt::UniqueConnection); 0376 } else { 0377 connect(this, static_cast<void (KComboBox::*)(int)>(&KMyMoneyAccountCombo::KComboBox::activated), this, &KMyMoneyAccountCombo::activated); 0378 } 0379 0380 // since the standard QComboBox implementation does not deal with data changes in tree models 0381 // we make sure that a possible account name change gets propagated to our widget 0382 connect(model, &QAbstractItemModel::dataChanged, this, [&](const QModelIndex& topLeft, const QModelIndex& bottomRight) { 0383 const auto currentIdx = currentIndex(); 0384 if (currentIdx >= topLeft.row() && currentIdx <= bottomRight.row()) { 0385 setRootModelIndex(topLeft.parent()); 0386 const auto accountId = itemData(currentIdx, eMyMoney::Model::IdRole).toString(); 0387 const QString text = itemText(currentIdx); 0388 setRootModelIndex(QModelIndex()); 0389 // we need to check for the account id because the row is 0390 // ambiguous as it may come from a different sub-tree in the model 0391 if (accountId == d->m_lastSelectedAccount) { 0392 if (lineEdit()) { 0393 lineEdit()->setText(text); 0394 auto dummyResizeEvent = QResizeEvent(QSize(), QSize()); 0395 resizeEvent(&dummyResizeEvent); 0396 } else { 0397 Q_EMIT currentTextChanged(text); 0398 } 0399 update(); 0400 } 0401 } 0402 }); 0403 } 0404 0405 void KMyMoneyAccountCombo::selectItem(const QModelIndex& index) 0406 { 0407 if (d->m_inMakeCompletion) 0408 return; 0409 0410 if (!index.isValid()) 0411 return; 0412 0413 if (index.model() != model()) { 0414 qDebug() << "KMyMoneyAccountCombo::selectItem called with wrong model" << index; 0415 } 0416 if (index.model()->flags(index) & Qt::ItemIsSelectable) { 0417 // delay the call until the next time in the event loop 0418 QMetaObject::invokeMethod(this, "setSelected", Qt::QueuedConnection, Q_ARG(QString, index.data(eMyMoney::Model::Roles::IdRole).toString())); 0419 } 0420 } 0421 0422 void KMyMoneyAccountCombo::makeCompletion(const QString& txt) 0423 { 0424 if(!d->m_inMakeCompletion) { 0425 d->m_inMakeCompletion = true; 0426 if (txt.isEmpty()) { 0427 setSelected(QString()); 0428 } else { 0429 AccountNamesFilterProxyModel* filterModel = qobject_cast<AccountNamesFilterProxyModel*>(model()); 0430 0431 if(filterModel) { 0432 const auto completionStr = QStringLiteral(".*"); 0433 // for some reason it helps to avoid internal errors if we 0434 // clear the filter before setting it to a new value 0435 filterModel->setFilterFixedString(QString()); 0436 if (txt.contains(MyMoneyFile::AccountSeparator) == 0) { 0437 const auto filterString = QString::fromLatin1("%1%2%3").arg(completionStr, QRegularExpression::escape(txt), completionStr); 0438 filterModel->setFilterRegularExpression(QRegularExpression(filterString, QRegularExpression::CaseInsensitiveOption)); 0439 } else { 0440 QStringList parts = txt.split(MyMoneyFile::AccountSeparator /*, Qt::SkipEmptyParts */); 0441 QString pattern; 0442 QStringList::iterator it; 0443 for (it = parts.begin(); it != parts.end(); ++it) { 0444 if (pattern.length() > 1) 0445 pattern += MyMoneyFile::AccountSeparator; 0446 pattern += QRegularExpression::escape(QString(*it).trimmed()) + completionStr; 0447 } 0448 filterModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption)); 0449 // if we don't have a match, we try it again, but this time 0450 // we add a wildcard for the top level 0451 if (filterModel->visibleItems() == 0) { 0452 // for some reason it helps to avoid internal errors if we 0453 // clear the filter before setting it to a new value 0454 filterModel->setFilterFixedString(QString()); 0455 pattern = pattern.prepend(completionStr + MyMoneyFile::AccountSeparator); 0456 filterModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption)); 0457 } 0458 } 0459 0460 // if nothing is shown, we might as well close the popup 0461 switch(filterModel->visibleItems()) { 0462 case 0: 0463 hidePopup(); 0464 break; 0465 default: 0466 expandAll(); 0467 showPopup(); 0468 d->selectFirstMatchingItem(); 0469 break; 0470 } 0471 0472 // we don't have a selection since the user edits the name 0473 d->m_lastSelectedAccount.clear(); 0474 0475 // keep current text in edit widget no matter what 0476 QSignalBlocker blocker(lineEdit()); 0477 lineEdit()->setText(txt); 0478 } 0479 } 0480 d->m_inMakeCompletion = false; 0481 } 0482 } 0483 0484 void KMyMoneyAccountCombo::showPopup() 0485 { 0486 if(d->m_popupView) { 0487 d->m_popupView->show(); 0488 } 0489 KComboBox::showPopup(); 0490 } 0491 0492 void KMyMoneyAccountCombo::hidePopup() 0493 { 0494 if(d->m_popupView) { 0495 d->m_popupView->hide(); 0496 } 0497 KComboBox::hidePopup(); 0498 } 0499 0500 QTreeView* KMyMoneyAccountCombo::popup() const 0501 { 0502 return d->m_popupView; 0503 } 0504 0505 void KMyMoneyAccountCombo::clearSelection() 0506 { 0507 d->m_lastSelectedAccount.clear(); 0508 setCurrentIndex(-1); 0509 clearEditText(); 0510 } 0511 0512 class KMyMoneyAccountComboSplitHelperPrivate 0513 { 0514 Q_DISABLE_COPY(KMyMoneyAccountComboSplitHelperPrivate) 0515 Q_DECLARE_PUBLIC(KMyMoneyAccountComboSplitHelper) 0516 0517 public: 0518 KMyMoneyAccountComboSplitHelperPrivate(KMyMoneyAccountComboSplitHelper* qq) 0519 : q_ptr(qq) 0520 , m_accountCombo(nullptr) 0521 , m_splitModel(nullptr) 0522 , m_norecursive(false) 0523 { 0524 } 0525 0526 KMyMoneyAccountComboSplitHelper* q_ptr; 0527 QComboBox* m_accountCombo; 0528 QAbstractItemModel* m_splitModel; 0529 bool m_norecursive; 0530 }; 0531 0532 0533 KMyMoneyAccountComboSplitHelper::KMyMoneyAccountComboSplitHelper(QComboBox* accountCombo, QAbstractItemModel* model) 0534 : QObject(accountCombo) 0535 , d_ptr(new KMyMoneyAccountComboSplitHelperPrivate(this)) 0536 { 0537 Q_D(KMyMoneyAccountComboSplitHelper); 0538 d->m_accountCombo = accountCombo; 0539 d->m_splitModel = model; 0540 0541 connect(model, &QAbstractItemModel::dataChanged, this, &KMyMoneyAccountComboSplitHelper::updateWidget); 0542 connect(model, &QAbstractItemModel::rowsRemoved, this, &KMyMoneyAccountComboSplitHelper::updateWidget, Qt::QueuedConnection); 0543 connect(model, &QAbstractItemModel::modelReset, this, &KMyMoneyAccountComboSplitHelper::updateWidget, Qt::QueuedConnection); 0544 connect(model, &QAbstractItemModel::destroyed, this, &KMyMoneyAccountComboSplitHelper::modelDestroyed); 0545 0546 accountCombo->installEventFilter(this); 0547 if (accountCombo->lineEdit()) { 0548 accountCombo->lineEdit()->installEventFilter(this); 0549 } 0550 updateWidget(); 0551 } 0552 0553 KMyMoneyAccountComboSplitHelper::~KMyMoneyAccountComboSplitHelper() 0554 { 0555 } 0556 0557 bool KMyMoneyAccountComboSplitHelper::eventFilter(QObject* watched, QEvent* event) 0558 { 0559 Q_D(KMyMoneyAccountComboSplitHelper); 0560 if (d->m_splitModel && (d->m_splitModel->rowCount() > 1)) { 0561 const auto type = event->type(); 0562 if (watched == d->m_accountCombo) { 0563 if (type == QEvent::FocusIn) { 0564 // select the complete text (which is readonly) 0565 // to signal focus in the lineedit widget to the user 0566 const auto lineEdit = d->m_accountCombo->lineEdit(); 0567 if (lineEdit) { 0568 lineEdit->end(false); 0569 lineEdit->home(true); 0570 } 0571 } 0572 } 0573 if ((type == QEvent::MouseButtonPress) 0574 || (type == QEvent::MouseButtonRelease) 0575 || (type == QEvent::MouseButtonDblClick)) { 0576 // suppress opening the combo box 0577 // or selecting text in the lineedit 0578 return true; 0579 } 0580 if (type == QEvent::KeyPress) { 0581 auto kev = static_cast<QKeyEvent*>(event); 0582 // swallow all keypress except Ctrl+Space, Return, 0583 // Enter, Tab, BackTab and Esc 0584 switch(kev->key()) { 0585 case Qt::Key_Enter: 0586 case Qt::Key_Return: 0587 case Qt::Key_Escape: 0588 case Qt::Key_Tab: 0589 case Qt::Key_Backtab: 0590 return false; 0591 0592 case Qt::Key_Space: 0593 return !(kev->modifiers() & Qt::ControlModifier); 0594 0595 default: 0596 break; 0597 } 0598 return true; 0599 } 0600 0601 } 0602 return QObject::eventFilter(watched, event); 0603 } 0604 0605 void KMyMoneyAccountComboSplitHelper::modelDestroyed() 0606 { 0607 Q_D(KMyMoneyAccountComboSplitHelper); 0608 d->m_splitModel = nullptr; 0609 } 0610 0611 void KMyMoneyAccountComboSplitHelper::updateWidget() 0612 { 0613 Q_D(KMyMoneyAccountComboSplitHelper); 0614 // sanity check 0615 if (!d->m_accountCombo || !d->m_splitModel || d->m_norecursive) 0616 return; 0617 0618 d->m_norecursive = true; 0619 0620 QModelIndexList indexes; 0621 bool disabled = false; 0622 0623 const auto rows = d->m_splitModel->rowCount(); 0624 const auto accountCombo = qobject_cast<KMyMoneyAccountCombo*>(d->m_accountCombo); 0625 switch (rows) { 0626 case 0: 0627 d->m_accountCombo->setCurrentIndex(-1); 0628 d->m_accountCombo->setCurrentText(QString()); 0629 break; 0630 case 1: 0631 indexes = d->m_accountCombo->model()->match(d->m_accountCombo->model()->index(0,0), 0632 eMyMoney::Model::IdRole, 0633 d->m_splitModel->index(0, 0).data(eMyMoney::Model::SplitAccountIdRole).toString(), 0634 1, 0635 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap | Qt::MatchRecursive)); 0636 if (indexes.isEmpty()) { 0637 if (accountCombo) { 0638 accountCombo->clearSelection(); 0639 } else { 0640 d->m_accountCombo->setCurrentIndex(-1); 0641 d->m_accountCombo->setCurrentText(QString()); 0642 } 0643 } else { 0644 const auto idx = indexes.first(); 0645 if (accountCombo) { 0646 const auto accountId = idx.data(eMyMoney::Model::IdRole).toString(); 0647 accountCombo->setSelected(accountId); 0648 } else { 0649 QSignalBlocker comboBoxBlocker(d->m_accountCombo); 0650 d->m_accountCombo->setRootModelIndex(idx.parent()); 0651 d->m_accountCombo->setCurrentIndex(idx.row()); 0652 d->m_accountCombo->setRootModelIndex(QModelIndex()); 0653 } 0654 } 0655 break; 0656 default: 0657 { 0658 QSignalBlocker lineEditBlocker(d->m_accountCombo->lineEdit()); 0659 QString txt, sep; 0660 for (int row = 0; row < rows; ++row) { 0661 const auto idx = d->m_splitModel->index(row, 0); 0662 indexes = d->m_accountCombo->model()->match(d->m_accountCombo->model()->index(0,0), 0663 eMyMoney::Model::IdRole, 0664 idx.data(eMyMoney::Model::SplitAccountIdRole).toString(), 0665 1, 0666 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchWrap | Qt::MatchRecursive)); 0667 if (!indexes.isEmpty()) { 0668 txt += sep + indexes.first().data(eMyMoney::Model::AccountNameRole).toString(); 0669 sep = QStringLiteral(", "); 0670 } 0671 } 0672 d->m_accountCombo->lineEdit()->setText(txt); 0673 d->m_accountCombo->lineEdit()->home(false); 0674 disabled = true; 0675 } 0676 break; 0677 } 0678 d->m_accountCombo->hidePopup(); 0679 d->m_accountCombo->lineEdit()->setReadOnly(disabled); 0680 0681 Q_EMIT accountComboEnabled(!disabled); 0682 Q_EMIT accountComboDisabled(disabled); 0683 0684 d->m_norecursive = false; 0685 }