File indexing completed on 2024-05-19 05:08:30
0001 /* 0002 SPDX-FileCopyrightText: 2010-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 "amountedit.h" 0008 0009 // ---------------------------------------------------------------------------- 0010 // QT Includes 0011 0012 #include <QDebug> 0013 #include <QFrame> 0014 #include <QKeyEvent> 0015 #include <QLocale> 0016 #include <QStyle> 0017 #include <QToolButton> 0018 0019 // ---------------------------------------------------------------------------- 0020 // KDE Includes 0021 0022 #include <KConfigGroup> 0023 #include <KLocalizedString> 0024 #include <KSharedConfig> 0025 0026 // ---------------------------------------------------------------------------- 0027 // Project Includes 0028 0029 #include "amountvalidator.h" 0030 #include "kmymoneycalculator.h" 0031 #include "mymoneysecurity.h" 0032 #include "icons.h" 0033 #include "popuppositioner.h" 0034 0035 using namespace Icons; 0036 0037 class AmountEditHelper 0038 { 0039 public: 0040 AmountEditHelper() : q(nullptr) {} 0041 ~AmountEditHelper() { 0042 delete q; 0043 } 0044 AmountEdit *q; 0045 }; 0046 0047 Q_GLOBAL_STATIC(AmountEditHelper, s_globalAmountEdit) 0048 0049 AmountEdit* AmountEdit::global() 0050 { 0051 if (!s_globalAmountEdit()->q) { 0052 s_globalAmountEdit()->q = new AmountEdit(0, 2); 0053 } 0054 0055 return s_globalAmountEdit()->q; 0056 } 0057 0058 class AmountEditPrivate 0059 { 0060 Q_DISABLE_COPY(AmountEditPrivate) 0061 Q_DECLARE_PUBLIC(AmountEdit) 0062 0063 public: 0064 enum Item { 0065 NoItem = 0x0, 0066 ShowCalculator = 0x1, 0067 ShowCurrencySymbol = 0x02, 0068 ShowAll = 0x3, 0069 }; 0070 Q_DECLARE_FLAGS(Items, Item) 0071 0072 explicit AmountEditPrivate(AmountEdit* qq) 0073 : q_ptr(qq) 0074 , m_calculatorFrame(nullptr) 0075 , m_calculator(nullptr) 0076 , m_calculatorButton(nullptr) 0077 , m_prec(2) 0078 , m_allowEmpty(false) 0079 , m_actionIcons(NoItem) 0080 , m_initialExchangeRate(MyMoneyMoney::ONE) 0081 , m_state(AmountEdit::DisplayValue) 0082 , sharesSet(false) 0083 , valueSet(false) 0084 , m_isCashAmount(false) 0085 { 0086 m_calculatorFrame = new QFrame; 0087 m_calculatorFrame->setWindowFlags(Qt::Popup); 0088 0089 m_calculatorFrame->setFrameStyle(QFrame::Panel | QFrame::Raised); 0090 m_calculatorFrame->setLineWidth(3); 0091 0092 m_calculator = new KMyMoneyCalculator(m_calculatorFrame); 0093 m_calculatorFrame->hide(); 0094 } 0095 0096 void init() 0097 { 0098 Q_Q(AmountEdit); 0099 // Yes, just a simple double validator ! 0100 auto validator = new AmountValidator(q); 0101 q->setValidator(validator); 0102 q->setAlignment(Qt::AlignRight | Qt::AlignVCenter); 0103 0104 const auto btnSize = q->sizeHint().height() - 5; 0105 0106 m_calculatorButton = new QToolButton(q); 0107 m_calculatorButton->setIcon(Icons::get(Icon::Calculator)); 0108 m_calculatorButton->setCursor(Qt::ArrowCursor); 0109 m_calculatorButton->setStyleSheet("QToolButton { border: none; padding: 2px}"); 0110 m_calculatorButton->setFixedSize(btnSize, btnSize); 0111 m_calculatorButton->setFocusPolicy(Qt::ClickFocus); 0112 0113 q->connect(m_calculatorButton, &QAbstractButton::clicked, q, &AmountEdit::slotCalculatorOpen); 0114 0115 m_currencyButton = new QToolButton(q); 0116 m_currencyButton->setCursor(Qt::ArrowCursor); 0117 m_currencyButton->setAutoRaise(true); 0118 m_currencyButton->hide(); 0119 m_currencyButton->setFocusPolicy(Qt::ClickFocus); 0120 0121 // setup items 0122 KSharedConfig::Ptr kconfig = KSharedConfig::openConfig(); 0123 KConfigGroup grp = kconfig->group("General Options"); 0124 q->setCalculatorButtonVisible(!grp.readEntry("DontShowCalculatorButton", false)); 0125 q->setCurrencySymbol(QString(), QString()); 0126 0127 updateLineEditSize(m_currencyButton, true); 0128 0129 q->connect(q, &QLineEdit::textChanged, q, &AmountEdit::theTextChanged); 0130 q->connect(m_calculator, &KMyMoneyCalculator::signalResultAvailable, q, &AmountEdit::slotCalculatorResult); 0131 q->connect(m_calculator, &KMyMoneyCalculator::signalQuit, q, &AmountEdit::slotCalculatorClose); 0132 } 0133 0134 /** 0135 * Internal helper function for value() and ensureFractionalPart(). 0136 */ 0137 void ensureFractionalPart(QString& s) const 0138 { 0139 s = MyMoneyMoney(s).formatMoney(QString(), precision(m_state), false); 0140 } 0141 0142 /** 0143 * This method opens the calculator and replays the key 0144 * event pointed to by @p ev. If @p ev is 0, then no key 0145 * event is replayed. 0146 * 0147 * @param ev pointer to QKeyEvent that started the calculator. 0148 */ 0149 void calculatorOpen(QKeyEvent* k) 0150 { 0151 Q_Q(AmountEdit); 0152 m_calculator->setInitialValues(q->text(), k); 0153 0154 // do not open the calculator in read-only mode 0155 if (q->isReadOnly()) 0156 return; 0157 0158 // show calculator and update size 0159 m_calculatorFrame->show(); 0160 m_calculatorFrame->setGeometry(m_calculator->geometry()); 0161 0162 PopupPositioner pos(q, m_calculatorFrame, PopupPositioner::BottemLeft); 0163 m_calculator->setFocus(); 0164 } 0165 0166 void updateLineEditSize(QWidget* widget, int w, int h) 0167 { 0168 Q_Q(AmountEdit); 0169 widget->resize(w, h); 0170 0171 int height = q->sizeHint().height(); 0172 int frameWidth = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth); 0173 const int btnHeight = height - 2*frameWidth; 0174 const int btnX = (height - btnHeight) / 2; 0175 const int currencyX = (height - h) / 2; 0176 0177 int gaps = 0; 0178 gaps += m_actionIcons.testFlag(ShowCalculator) ? 1 : 0; 0179 gaps += m_actionIcons.testFlag(ShowCurrencySymbol) ? 1 : 0; 0180 0181 m_calculatorButton->move(q->width() - m_calculatorButton->width() - frameWidth, btnX); 0182 widget->move(q->width() - m_calculatorButton->width() - widget->width() - gaps * frameWidth, currencyX); 0183 0184 const int padding = m_calculatorButton->width() + widget->width() + ((gaps - 1) * frameWidth); 0185 q->setStyleSheet(QString("QLineEdit { padding-right: %1px }").arg(padding)); 0186 q->setMinimumHeight(height); 0187 } 0188 0189 void cut() 0190 { 0191 Q_Q(AmountEdit); 0192 // only cut if parts of the text are selected 0193 if (q->hasSelectedText() && (q->text() != q->selectedText())) { 0194 cut(); 0195 } 0196 } 0197 0198 bool hasMultipleCurrencies() const 0199 { 0200 return m_sharesCommodity.id().compare(m_valueCommodity.id()); 0201 } 0202 0203 void updateLineEditSize(QToolButton* button, bool ofs = false) 0204 { 0205 Q_Q(AmountEdit); 0206 const int currencyWidth = q->fontMetrics().boundingRect(button->text()).width() + 10; 0207 const auto frameWidth = ofs ? q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth) : 0; 0208 0209 const int currencyHeight = button->height() - frameWidth; 0210 0211 AmountEditPrivate::updateLineEditSize(button, currencyWidth, currencyHeight); 0212 } 0213 0214 void setCurrencySymbol(const QString& symbol, const QString& name) 0215 { 0216 m_currencyButton->setText(symbol); 0217 m_currencyButton->setToolTip(name); 0218 m_currencyButton->setHidden(symbol.isEmpty()); 0219 m_actionIcons.setFlag(AmountEditPrivate::ShowCurrencySymbol, !symbol.isEmpty()); 0220 updateLineEditSize(m_currencyButton); 0221 } 0222 0223 void updateWidgets() 0224 { 0225 Q_Q(AmountEdit); 0226 if (hasMultipleCurrencies()) { 0227 m_currencyButton->setEnabled(true); 0228 QString currentCurrency; 0229 QString otherCurrency; 0230 // prevent to change the values due to emitted textChanged() signals 0231 QSignalBlocker block(q); 0232 if (m_state == AmountEdit::DisplayShares) { 0233 currentCurrency = m_sharesCommodity.name(); 0234 otherCurrency = m_valueCommodity.name(); 0235 setCurrencySymbol(m_sharesCommodity.tradingSymbol(), currentCurrency); 0236 q->QLineEdit::setText(m_sharesText); 0237 } else { 0238 currentCurrency = m_valueCommodity.name(); 0239 otherCurrency = m_sharesCommodity.name(); 0240 setCurrencySymbol(m_valueCommodity.tradingSymbol(), m_valueCommodity.name()); 0241 q->QLineEdit::setText(m_valueText); 0242 } 0243 0244 m_currencyButton->setToolTip(i18nc("@info:tooltip Swap currencies for entry/display", 0245 "Value are presented in %1. Press this button to switch the currency to %2.", 0246 currentCurrency, 0247 otherCurrency)); 0248 0249 } else { 0250 if (!m_valueCommodity.id().isEmpty()) { 0251 m_currencyButton->setEnabled(false); 0252 m_currencyButton->setToolTip(i18nc("@info:tooltip Swap currencies for entry/display", "Values are presented in %1.", m_valueCommodity.name())); 0253 setCurrencySymbol(m_valueCommodity.tradingSymbol(), m_valueCommodity.name()); 0254 0255 } else { 0256 // hide the currency symbol 0257 setCurrencySymbol(QString(), QString()); 0258 } 0259 } 0260 } 0261 0262 void swapCommodities() 0263 { 0264 Q_Q(AmountEdit); 0265 q->setDisplayState((m_state == AmountEdit::DisplayShares) ? AmountEdit::DisplayValue : AmountEdit::DisplayShares); 0266 } 0267 0268 MyMoneyMoney adjustToPrecision(AmountEdit::DisplayState state, const MyMoneyMoney& amount) const 0269 { 0270 auto money(amount); 0271 const MyMoneySecurity& sec((state == AmountEdit::DisplayValue) ? m_valueCommodity : m_sharesCommodity); 0272 if (!sec.id().isEmpty()) { 0273 const auto fraction = m_isCashAmount ? sec.smallestCashFraction() : sec.smallestAccountFraction(); 0274 money = money.convert(fraction); 0275 } else if (m_prec != -1) 0276 money = money.convert(MyMoneyMoney::precToDenom(m_prec)); 0277 return money; 0278 } 0279 0280 int precision(AmountEdit::DisplayState state) const 0281 { 0282 const MyMoneySecurity& sec((state == AmountEdit::DisplayValue) ? m_valueCommodity : m_sharesCommodity); 0283 auto prec(m_prec); 0284 0285 if (!sec.id().isEmpty()) { 0286 prec = MyMoneyMoney::denomToPrec(m_isCashAmount ? sec.smallestCashFraction() : sec.smallestAccountFraction()); 0287 } 0288 return prec; 0289 } 0290 0291 void setValueText(const QString& txt) 0292 { 0293 Q_Q(AmountEdit); 0294 m_valueText = txt; 0295 if (q->isEnabled() && !txt.isEmpty()) { 0296 ensureFractionalPart(m_valueText); 0297 } 0298 // only update text if it really differs 0299 if (m_state == AmountEdit::DisplayValue && m_valueText.compare(q->QLineEdit::text())) { 0300 // prevent to change the values due to emitted textChanged() signals 0301 QSignalBlocker block(q); 0302 q->QLineEdit::setText(m_valueText); 0303 } 0304 } 0305 0306 void setSharesText(const QString& txt) 0307 { 0308 Q_Q(AmountEdit); 0309 m_sharesText = txt; 0310 if (q->isEnabled() && !txt.isEmpty()) { 0311 ensureFractionalPart(m_sharesText); 0312 } 0313 // only update text if it really differs 0314 if (m_state == AmountEdit::DisplayShares && m_sharesText.compare(q->QLineEdit::text())) { 0315 // prevent to change the values due to emitted textChanged() signals 0316 QSignalBlocker block(q); 0317 q->QLineEdit::setText(m_sharesText); 0318 } 0319 } 0320 0321 AmountEdit* q_ptr; 0322 QFrame* m_calculatorFrame; 0323 KMyMoneyCalculator* m_calculator; 0324 QToolButton* m_calculatorButton; 0325 QToolButton* m_currencyButton; 0326 int m_prec; 0327 bool m_allowEmpty; 0328 QString m_previousText; // keep track of what has been typed 0329 0330 QString m_valueText; // keep track of what was the original value 0331 QString m_sharesText; // keep track of what was the original value 0332 0333 QFlags<Item> m_actionIcons; 0334 0335 MyMoneyMoney m_value; // original amount when starting editing 0336 MyMoneyMoney m_shares; // original amount when starting editing 0337 MyMoneyMoney m_initialExchangeRate; 0338 0339 MyMoneySecurity m_sharesCommodity; 0340 MyMoneySecurity m_valueCommodity; 0341 0342 /** 0343 * Which part is displayed 0344 */ 0345 AmountEdit::DisplayState m_state; 0346 0347 bool sharesSet; 0348 bool valueSet; 0349 bool m_isCashAmount; 0350 }; 0351 0352 Q_DECLARE_OPERATORS_FOR_FLAGS(AmountEditPrivate::Items) 0353 0354 void AmountEdit::setReadOnly(bool ro) 0355 { 0356 Q_D(AmountEdit); 0357 d->m_calculatorButton->setEnabled(!ro); 0358 QLineEdit::setReadOnly(ro); 0359 } 0360 0361 AmountEdit::AmountEdit(QWidget *parent, const int prec) : 0362 QLineEdit(parent), 0363 d_ptr(new AmountEditPrivate(this)) 0364 { 0365 Q_D(AmountEdit); 0366 d->m_prec = prec; 0367 if (prec < -1 || prec > 20) { 0368 d->m_prec = AmountEdit::global()->standardPrecision(); 0369 } 0370 0371 d->init(); 0372 0373 connect(d->m_currencyButton, &QToolButton::clicked, this, [&]() { 0374 Q_D(AmountEdit); 0375 d->swapCommodities(); 0376 }); 0377 } 0378 0379 AmountEdit::AmountEdit(const MyMoneySecurity& sec, QWidget *parent) : 0380 QLineEdit(parent), 0381 d_ptr(new AmountEditPrivate(this)) 0382 { 0383 Q_D(AmountEdit); 0384 d->m_prec = MyMoneyMoney::denomToPrec(sec.smallestAccountFraction()); 0385 d->init(); 0386 } 0387 0388 AmountEdit::AmountEdit(QWidget* parent, const int prec, AmountEditPrivate* dd) 0389 : QLineEdit(parent) 0390 , d_ptr(dd) 0391 { 0392 Q_D(AmountEdit); 0393 d->m_prec = prec; 0394 if (prec < -1 || prec > 20) { 0395 d->m_prec = AmountEdit::global()->standardPrecision(); 0396 } 0397 d->init(); 0398 } 0399 0400 AmountEdit::~AmountEdit() 0401 { 0402 Q_D(AmountEdit); 0403 delete d; 0404 } 0405 0406 void AmountEdit::setStandardPrecision(int prec) 0407 { 0408 if (prec >= 0 && prec < 20) { 0409 global()->d_ptr->m_prec = prec; 0410 } 0411 } 0412 0413 int AmountEdit::standardPrecision() 0414 { 0415 return global()->d_ptr->m_prec; 0416 } 0417 0418 0419 void AmountEdit::resizeEvent(QResizeEvent* event) 0420 { 0421 Q_UNUSED(event); 0422 Q_D(AmountEdit); 0423 d->updateLineEditSize(d->m_currencyButton); 0424 } 0425 0426 void AmountEdit::focusInEvent(QFocusEvent* event) 0427 { 0428 QLineEdit::focusInEvent(event); 0429 if ((event->reason() == Qt::MouseFocusReason) || (event->reason() == Qt::ActiveWindowFocusReason)) { 0430 if (!hasSelectedText()) { 0431 // we need to wait until all processing is done before 0432 // we can successfully call selectAll. Hence the 0433 // delayed execution when we return back to the event loop 0434 metaObject()->invokeMethod(this, &QLineEdit::selectAll, Qt::QueuedConnection); 0435 } 0436 } 0437 } 0438 0439 void AmountEdit::focusOutEvent(QFocusEvent* event) 0440 { 0441 Q_D(AmountEdit); 0442 QLineEdit::focusOutEvent(event); 0443 0444 // make sure we have a zero value in case the current text 0445 // is empty but this is not allowed 0446 if (text().isEmpty() && !d->m_allowEmpty) { 0447 QLineEdit::setText(QLatin1String("0")); 0448 } 0449 0450 // make sure we have a fractional part 0451 if (!text().isEmpty()) 0452 ensureFractionalPart(); 0453 0454 // in case the widget contains a different value we emit 0455 // the amountChanged signal 0456 if ((d->m_value != value()) || (d->m_shares != shares())) { 0457 d->m_value = value(); 0458 d->m_shares = shares(); 0459 Q_EMIT amountChanged(); 0460 } 0461 } 0462 0463 void AmountEdit::keyPressEvent(QKeyEvent* event) 0464 { 0465 Q_D(AmountEdit); 0466 switch(event->key()) { 0467 case Qt::Key_Plus: 0468 case Qt::Key_Minus: 0469 d->cut(); 0470 if (text().length() == 0) { 0471 break; 0472 } 0473 // in case of '-' we do not enter the calculator when 0474 // the current position is the beginning and there is 0475 // no '-' sign at the first position. 0476 if (event->key() == Qt::Key_Minus) { 0477 if (cursorPosition() == 0 && text().at(0) != '-') { 0478 break; 0479 } 0480 } 0481 // intentional fall through 0482 0483 case Qt::Key_Slash: 0484 case Qt::Key_Asterisk: 0485 case Qt::Key_Percent: 0486 d->cut(); 0487 d->calculatorOpen(event); 0488 return; 0489 0490 case Qt::Key_Return: 0491 case Qt::Key_Escape: 0492 case Qt::Key_Enter: 0493 break; 0494 0495 case Qt::Key_Space: 0496 if (event->modifiers() == Qt::ControlModifier) { 0497 event->accept(); 0498 d->m_currencyButton->animateClick(); 0499 return; 0500 } 0501 break; 0502 0503 default: 0504 // make sure to use the locale's decimalPoint when the 0505 // keypad comma/dot is pressed 0506 QString keyText = event->text(); 0507 int key = event->key(); 0508 if (event->modifiers() & Qt::KeypadModifier) { 0509 if ((key == Qt::Key_Period) || (key == Qt::Key_Comma)) { 0510 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0511 key = QLocale().decimalPoint().unicode(); 0512 #else 0513 key = QLocale().decimalPoint().unicode()->toLatin1(); // TODO Test this 0514 #endif 0515 keyText = QLocale().decimalPoint(); 0516 } 0517 } 0518 // create a (possibly adjusted) copy of the event 0519 QKeyEvent newEvent(event->type(), 0520 key, 0521 event->modifiers(), 0522 event->nativeScanCode(), 0523 event->nativeVirtualKey(), 0524 event->nativeModifiers(), 0525 keyText, 0526 event->isAutoRepeat(), 0527 event->count()); 0528 0529 // in case all text is selected and the user presses the decimal point 0530 // we fill the widget with the leading "0". The outcome of this will be 0531 // that the widget then contains "0.". 0532 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0533 if ((newEvent.key() == QLocale().decimalPoint().unicode()) && (selectedText() == text())) { 0534 #else 0535 if ((newEvent.key() == QLocale().decimalPoint().at(0).unicode()) && (selectedText() == text())) { 0536 #endif 0537 QLineEdit::setText(QLatin1String("0")); 0538 } 0539 *event = newEvent; 0540 } 0541 0542 // in case we have not processed anything, we 0543 // need to call the base class implementation 0544 QLineEdit::keyPressEvent(event); 0545 } 0546 0547 0548 void AmountEdit::setPrecision(const int prec) 0549 { 0550 Q_D(AmountEdit); 0551 if (prec >= -1 && prec <= 20) { 0552 if (prec != d->m_prec) { 0553 d->m_prec = prec; 0554 // update current display 0555 setValue(value()); 0556 } 0557 } 0558 } 0559 0560 int AmountEdit::precision() const 0561 { 0562 Q_D(const AmountEdit); 0563 return d->m_prec; 0564 } 0565 0566 int AmountEdit::precision(MultiCurrencyEdit::DisplayState state) const 0567 { 0568 Q_D(const AmountEdit); 0569 return d->precision(state); 0570 } 0571 0572 MultiCurrencyEdit::DisplayState AmountEdit::displayState() const 0573 { 0574 Q_D(const AmountEdit); 0575 return d->m_state; 0576 } 0577 0578 bool AmountEdit::isValid() const 0579 { 0580 return !(text().isEmpty()); 0581 } 0582 0583 MyMoneyMoney AmountEdit::value() const 0584 { 0585 Q_D(const AmountEdit); 0586 MyMoneyMoney money(d->m_valueText); 0587 return d->adjustToPrecision(AmountEdit::DisplayValue, money); 0588 } 0589 0590 void AmountEdit::setValue(const MyMoneyMoney& amount) 0591 { 0592 Q_D(AmountEdit); 0593 if (d->sharesSet && !d->valueSet) { 0594 qWarning() << objectName() << "Call AmountEdit::setValue() before AmountEdit::setShares(). Fix source code!"; 0595 } 0596 if (d->valueSet && (amount == d->m_value)) 0597 return; 0598 0599 d->valueSet = true; 0600 d->m_value = amount; 0601 const auto txt(amount.formatMoney(QString(), d->precision(AmountEdit::DisplayValue), false)); 0602 d->setValueText(txt); 0603 0604 if (!hasMultipleCurrencies()) { 0605 setShares(amount); 0606 } 0607 } 0608 0609 MyMoneyMoney AmountEdit::shares() const 0610 { 0611 Q_D(const AmountEdit); 0612 MyMoneyMoney money(d->m_sharesText); 0613 return d->adjustToPrecision(AmountEdit::DisplayShares, money); 0614 } 0615 0616 void AmountEdit::setShares(const MyMoneyMoney& amount) 0617 { 0618 Q_D(AmountEdit); 0619 d->sharesSet = !d->valueSet; 0620 d->m_shares = amount; 0621 0622 const auto txt(amount.formatMoney(QString(), d->precision(AmountEdit::DisplayShares), false)); 0623 d->setSharesText(txt); 0624 0625 if (!d->m_shares.isZero()) { 0626 d->m_initialExchangeRate = d->m_value / d->m_shares; 0627 } 0628 } 0629 0630 void AmountEdit::clear() 0631 { 0632 Q_D(AmountEdit); 0633 d->m_sharesText.clear(); 0634 d->m_valueText.clear(); 0635 QLineEdit::clear(); 0636 d->m_previousText.clear(); 0637 } 0638 0639 void AmountEdit::theTextChanged(const QString & theText) 0640 { 0641 Q_D(AmountEdit); 0642 0643 const auto initiallyValid = isValid(); 0644 QLocale locale; 0645 QString dec = locale.groupSeparator(); 0646 QString l_text = theText; 0647 QString nsign, psign; 0648 nsign = locale.negativeSign(); 0649 psign = locale.positiveSign(); 0650 0651 auto i = 0; 0652 if (isEnabled()) { 0653 QValidator::State state = validator()->validate(l_text, i); 0654 if (state == QValidator::Intermediate) { 0655 if (l_text.length() == 1) { 0656 if (l_text != dec && l_text != nsign && l_text != psign) 0657 state = QValidator::Invalid; 0658 } 0659 } 0660 if (state == QValidator::Invalid) 0661 QLineEdit::setText(d->m_previousText); 0662 else { 0663 d->m_previousText = l_text; 0664 0665 if (!l_text.isEmpty()) { 0666 // adjust value or shares depending on state 0667 // by using the initialExchangeRate 0668 if (d->m_state == AmountEdit::DisplayValue) { 0669 d->m_valueText = l_text; 0670 MyMoneyMoney amount(l_text); 0671 d->adjustToPrecision(AmountEdit::DisplayValue, amount); 0672 amount /= d->m_initialExchangeRate; 0673 d->m_sharesText = amount.formatMoney(QString(), d->precision(AmountEdit::DisplayShares), false); 0674 } else { 0675 d->m_sharesText = l_text; 0676 MyMoneyMoney amount(l_text); 0677 d->adjustToPrecision(AmountEdit::DisplayShares, amount); 0678 amount *= d->m_initialExchangeRate; 0679 d->m_valueText = amount.formatMoney(QString(), d->precision(AmountEdit::DisplayValue), false); 0680 } 0681 } 0682 Q_EMIT validatedTextChanged(text()); 0683 } 0684 } 0685 0686 if (initiallyValid != isValid()) { 0687 Q_EMIT validityChanged(isValid()); 0688 } 0689 } 0690 0691 void AmountEdit::slotCalculatorOpen() 0692 { 0693 Q_D(AmountEdit); 0694 d->calculatorOpen(0); 0695 } 0696 0697 void AmountEdit::slotCalculatorClose() 0698 { 0699 Q_D(AmountEdit); 0700 if (d->m_calculator != 0) { 0701 d->m_calculatorFrame->hide(); 0702 } 0703 } 0704 0705 void AmountEdit::setText(const QString& txt) 0706 { 0707 Q_D(AmountEdit); 0708 if (!d->hasMultipleCurrencies()) { 0709 QLineEdit::setText(txt); 0710 } else { 0711 switch (d->m_state) { 0712 case MultiCurrencyEdit::DisplayShares: 0713 d->m_sharesText = txt; 0714 break; 0715 case MultiCurrencyEdit::DisplayValue: 0716 d->m_valueText = txt; 0717 break; 0718 } 0719 d->updateWidgets(); 0720 } 0721 } 0722 0723 void AmountEdit::slotCalculatorResult() 0724 { 0725 Q_D(AmountEdit); 0726 slotCalculatorClose(); 0727 if (d->m_calculator != 0) { 0728 MyMoneyMoney amount(d->m_calculator->result()); 0729 amount = d->adjustToPrecision(d->m_state, amount); 0730 setText(amount.formatMoney(QString(), d->precision(d->m_state), false)); 0731 } 0732 } 0733 0734 void AmountEdit::setCalculatorButtonVisible(const bool show) 0735 { 0736 Q_D(AmountEdit); 0737 if (d->m_calculatorButton->isVisible() != show) { 0738 d->m_calculatorButton->setVisible(show); 0739 d->m_actionIcons.setFlag(AmountEditPrivate::ShowCalculator, show); 0740 d->updateLineEditSize(d->m_currencyButton); 0741 Q_EMIT calculatorButtonVisibilityChanged(show); 0742 } 0743 } 0744 0745 void AmountEdit::setAllowEmpty(bool allowed) 0746 { 0747 Q_D(AmountEdit); 0748 if (d->m_allowEmpty != allowed) { 0749 d->m_allowEmpty = allowed; 0750 Q_EMIT allowEmptyChanged(allowed); 0751 } 0752 } 0753 0754 bool AmountEdit::isEmptyAllowed() const 0755 { 0756 Q_D(const AmountEdit); 0757 return d->m_allowEmpty; 0758 } 0759 0760 bool AmountEdit::isCalculatorButtonVisible() const 0761 { 0762 Q_D(const AmountEdit); 0763 return d->m_calculatorButton->isVisible(); 0764 } 0765 0766 void AmountEdit::ensureFractionalPart() 0767 { 0768 Q_D(AmountEdit); 0769 QString s(text()); 0770 d->ensureFractionalPart(s); 0771 // by setting the text only when it's different then the one that it is already there 0772 // we preserve the edit widget's state (like the selection for example) during a 0773 // call to ensureFractionalPart() that does not change anything 0774 if (s != text()) 0775 QLineEdit::setText(s); 0776 } 0777 0778 void AmountEdit::setCurrencySymbol(const QString& symbol, const QString& name) 0779 { 0780 Q_D(AmountEdit); 0781 d->setCurrencySymbol(symbol, name); 0782 } 0783 0784 void AmountEdit::setDisplayState(AmountEdit::DisplayState state) 0785 { 0786 Q_D(AmountEdit); 0787 if (state != d->m_state) { 0788 d->m_state = state; 0789 d->updateWidgets(); 0790 Q_EMIT displayStateChanged(state); 0791 } 0792 } 0793 0794 void AmountEdit::setShowShares(bool show) 0795 { 0796 if (!show) { 0797 setShowValue(); 0798 return; 0799 } 0800 setDisplayState(AmountEdit::DisplayShares); 0801 } 0802 0803 void AmountEdit::setShowValue(bool show) 0804 { 0805 if (!show) { 0806 setShowShares(); 0807 return; 0808 } 0809 setDisplayState(AmountEdit::DisplayValue); 0810 } 0811 0812 void AmountEdit::setCommodity(const MyMoneySecurity& commodity) 0813 { 0814 Q_D(AmountEdit); 0815 d->m_sharesCommodity = commodity; 0816 d->m_valueCommodity = commodity; 0817 d->updateWidgets(); 0818 } 0819 0820 void AmountEdit::setSharesCommodity(const MyMoneySecurity& commodity) 0821 { 0822 Q_D(AmountEdit); 0823 if (d->m_sharesCommodity.id() != commodity.id()) { 0824 d->m_sharesCommodity = commodity; 0825 d->updateWidgets(); 0826 } 0827 } 0828 0829 MyMoneySecurity AmountEdit::sharesCommodity() const 0830 { 0831 Q_D(const AmountEdit); 0832 return d->m_sharesCommodity; 0833 } 0834 0835 void AmountEdit::setValueCommodity(const MyMoneySecurity& commodity) 0836 { 0837 Q_D(AmountEdit); 0838 if (d->m_valueCommodity.id() != commodity.id()) { 0839 d->m_valueCommodity = commodity; 0840 d->updateWidgets(); 0841 } 0842 } 0843 0844 MyMoneySecurity AmountEdit::valueCommodity() const 0845 { 0846 Q_D(const AmountEdit); 0847 return d->m_valueCommodity; 0848 } 0849 0850 void AmountEdit::setInitialExchangeRate(const MyMoneyMoney& price) 0851 { 0852 Q_D(AmountEdit); 0853 d->m_initialExchangeRate = price; 0854 } 0855 0856 MyMoneyMoney AmountEdit::initialExchangeRate() const 0857 { 0858 Q_D(const AmountEdit); 0859 return d->m_initialExchangeRate; 0860 } 0861 0862 QWidget* AmountEdit::widget() 0863 { 0864 return this; 0865 } 0866 0867 bool AmountEdit::hasMultipleCurrencies() const 0868 { 0869 Q_D(const AmountEdit); 0870 return d->hasMultipleCurrencies(); 0871 }