LCOV - code coverage report
Current view: top level - src/qt - bitcoinamountfield.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 0 148 0.0 %
Date: 2015-10-12 22:39:14 Functions: 0 28 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2011-2014 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include "bitcoinamountfield.h"
       6             : 
       7             : #include "bitcoinunits.h"
       8             : #include "guiconstants.h"
       9             : #include "qvaluecombobox.h"
      10             : 
      11             : #include <QApplication>
      12             : #include <QAbstractSpinBox>
      13             : #include <QHBoxLayout>
      14             : #include <QKeyEvent>
      15             : #include <QLineEdit>
      16             : 
      17             : /** QSpinBox that uses fixed-point numbers internally and uses our own
      18             :  * formatting/parsing functions.
      19             :  */
      20           0 : class AmountSpinBox: public QAbstractSpinBox
      21             : {
      22             :     Q_OBJECT
      23             : 
      24             : public:
      25           0 :     explicit AmountSpinBox(QWidget *parent):
      26             :         QAbstractSpinBox(parent),
      27             :         currentUnit(BitcoinUnits::BTC),
      28           0 :         singleStep(100000) // satoshis
      29             :     {
      30           0 :         setAlignment(Qt::AlignRight);
      31             : 
      32           0 :         connect(lineEdit(), SIGNAL(textEdited(QString)), this, SIGNAL(valueChanged()));
      33           0 :     }
      34             : 
      35           0 :     QValidator::State validate(QString &text, int &pos) const
      36             :     {
      37           0 :         if(text.isEmpty())
      38             :             return QValidator::Intermediate;
      39           0 :         bool valid = false;
      40           0 :         parse(text, &valid);
      41             :         /* Make sure we return Intermediate so that fixup() is called on defocus */
      42           0 :         return valid ? QValidator::Intermediate : QValidator::Invalid;
      43             :     }
      44             : 
      45           0 :     void fixup(QString &input) const
      46             :     {
      47           0 :         bool valid = false;
      48           0 :         CAmount val = parse(input, &valid);
      49           0 :         if(valid)
      50             :         {
      51           0 :             input = BitcoinUnits::format(currentUnit, val, false, BitcoinUnits::separatorAlways);
      52           0 :             lineEdit()->setText(input);
      53             :         }
      54           0 :     }
      55             : 
      56           0 :     CAmount value(bool *valid_out=0) const
      57             :     {
      58           0 :         return parse(text(), valid_out);
      59             :     }
      60             : 
      61           0 :     void setValue(const CAmount& value)
      62             :     {
      63           0 :         lineEdit()->setText(BitcoinUnits::format(currentUnit, value, false, BitcoinUnits::separatorAlways));
      64             :         Q_EMIT valueChanged();
      65           0 :     }
      66             : 
      67           0 :     void stepBy(int steps)
      68             :     {
      69           0 :         bool valid = false;
      70           0 :         CAmount val = value(&valid);
      71           0 :         val = val + steps * singleStep;
      72           0 :         val = qMin(qMax(val, CAmount(0)), BitcoinUnits::maxMoney());
      73           0 :         setValue(val);
      74           0 :     }
      75             : 
      76           0 :     void setDisplayUnit(int unit)
      77             :     {
      78           0 :         bool valid = false;
      79           0 :         CAmount val = value(&valid);
      80             : 
      81           0 :         currentUnit = unit;
      82             : 
      83           0 :         if(valid)
      84           0 :             setValue(val);
      85             :         else
      86           0 :             clear();
      87           0 :     }
      88             : 
      89           0 :     void setSingleStep(const CAmount& step)
      90             :     {
      91           0 :         singleStep = step;
      92           0 :     }
      93             : 
      94           0 :     QSize minimumSizeHint() const
      95             :     {
      96           0 :         if(cachedMinimumSizeHint.isEmpty())
      97             :         {
      98           0 :             ensurePolished();
      99             : 
     100           0 :             const QFontMetrics fm(fontMetrics());
     101           0 :             int h = lineEdit()->minimumSizeHint().height();
     102           0 :             int w = fm.width(BitcoinUnits::format(BitcoinUnits::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::separatorAlways));
     103           0 :             w += 2; // cursor blinking space
     104             : 
     105           0 :             QStyleOptionSpinBox opt;
     106           0 :             initStyleOption(&opt);
     107             :             QSize hint(w, h);
     108             :             QSize extra(35, 6);
     109           0 :             opt.rect.setSize(hint + extra);
     110           0 :             extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
     111           0 :                                                     QStyle::SC_SpinBoxEditField, this).size();
     112             :             // get closer to final result by repeating the calculation
     113           0 :             opt.rect.setSize(hint + extra);
     114           0 :             extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
     115           0 :                                                     QStyle::SC_SpinBoxEditField, this).size();
     116             :             hint += extra;
     117             :             hint.setHeight(h);
     118             : 
     119           0 :             opt.rect = rect();
     120             : 
     121           0 :             cachedMinimumSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this)
     122           0 :                                     .expandedTo(QApplication::globalStrut());
     123             :         }
     124           0 :         return cachedMinimumSizeHint;
     125             :     }
     126             : 
     127             : private:
     128             :     int currentUnit;
     129             :     CAmount singleStep;
     130             :     mutable QSize cachedMinimumSizeHint;
     131             : 
     132             :     /**
     133             :      * Parse a string into a number of base monetary units and
     134             :      * return validity.
     135             :      * @note Must return 0 if !valid.
     136             :      */
     137           0 :     CAmount parse(const QString &text, bool *valid_out=0) const
     138             :     {
     139           0 :         CAmount val = 0;
     140           0 :         bool valid = BitcoinUnits::parse(currentUnit, text, &val);
     141           0 :         if(valid)
     142             :         {
     143           0 :             if(val < 0 || val > BitcoinUnits::maxMoney())
     144           0 :                 valid = false;
     145             :         }
     146           0 :         if(valid_out)
     147           0 :             *valid_out = valid;
     148           0 :         return valid ? val : 0;
     149             :     }
     150             : 
     151             : protected:
     152           0 :     bool event(QEvent *event)
     153             :     {
     154           0 :         if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease)
     155             :         {
     156           0 :             QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
     157           0 :             if (keyEvent->key() == Qt::Key_Comma)
     158             :             {
     159             :                 // Translate a comma into a period
     160           0 :                 QKeyEvent periodKeyEvent(event->type(), Qt::Key_Period, keyEvent->modifiers(), ".", keyEvent->isAutoRepeat(), keyEvent->count());
     161           0 :                 return QAbstractSpinBox::event(&periodKeyEvent);
     162             :             }
     163             :         }
     164           0 :         return QAbstractSpinBox::event(event);
     165             :     }
     166             : 
     167           0 :     StepEnabled stepEnabled() const
     168             :     {
     169           0 :         if (isReadOnly()) // Disable steps when AmountSpinBox is read-only
     170             :             return StepNone;
     171           0 :         if (text().isEmpty()) // Allow step-up with empty field
     172             :             return StepUpEnabled;
     173             : 
     174             :         StepEnabled rv = 0;
     175           0 :         bool valid = false;
     176           0 :         CAmount val = value(&valid);
     177           0 :         if(valid)
     178             :         {
     179           0 :             if(val > 0)
     180             :                 rv |= StepDownEnabled;
     181           0 :             if(val < BitcoinUnits::maxMoney())
     182             :                 rv |= StepUpEnabled;
     183             :         }
     184             :         return rv;
     185             :     }
     186             : 
     187             : Q_SIGNALS:
     188             :     void valueChanged();
     189             : };
     190             : 
     191             : #include "bitcoinamountfield.moc"
     192             : 
     193           0 : BitcoinAmountField::BitcoinAmountField(QWidget *parent) :
     194             :     QWidget(parent),
     195           0 :     amount(0)
     196             : {
     197           0 :     amount = new AmountSpinBox(this);
     198           0 :     amount->setLocale(QLocale::c());
     199           0 :     amount->installEventFilter(this);
     200           0 :     amount->setMaximumWidth(170);
     201             : 
     202           0 :     QHBoxLayout *layout = new QHBoxLayout(this);
     203           0 :     layout->addWidget(amount);
     204           0 :     unit = new QValueComboBox(this);
     205           0 :     unit->setModel(new BitcoinUnits(this));
     206           0 :     layout->addWidget(unit);
     207           0 :     layout->addStretch(1);
     208           0 :     layout->setContentsMargins(0,0,0,0);
     209             : 
     210           0 :     setLayout(layout);
     211             : 
     212           0 :     setFocusPolicy(Qt::TabFocus);
     213           0 :     setFocusProxy(amount);
     214             : 
     215             :     // If one if the widgets changes, the combined content changes as well
     216           0 :     connect(amount, SIGNAL(valueChanged()), this, SIGNAL(valueChanged()));
     217           0 :     connect(unit, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int)));
     218             : 
     219             :     // Set default based on configuration
     220           0 :     unitChanged(unit->currentIndex());
     221           0 : }
     222             : 
     223           0 : void BitcoinAmountField::clear()
     224             : {
     225           0 :     amount->clear();
     226           0 :     unit->setCurrentIndex(0);
     227           0 : }
     228             : 
     229           0 : void BitcoinAmountField::setEnabled(bool fEnabled)
     230             : {
     231           0 :     amount->setEnabled(fEnabled);
     232           0 :     unit->setEnabled(fEnabled);
     233           0 : }
     234             : 
     235           0 : bool BitcoinAmountField::validate()
     236             : {
     237           0 :     bool valid = false;
     238             :     value(&valid);
     239           0 :     setValid(valid);
     240           0 :     return valid;
     241             : }
     242             : 
     243           0 : void BitcoinAmountField::setValid(bool valid)
     244             : {
     245           0 :     if (valid)
     246           0 :         amount->setStyleSheet("");
     247             :     else
     248           0 :         amount->setStyleSheet(STYLE_INVALID);
     249           0 : }
     250             : 
     251           0 : bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event)
     252             : {
     253           0 :     if (event->type() == QEvent::FocusIn)
     254             :     {
     255             :         // Clear invalid flag on focus
     256           0 :         setValid(true);
     257             :     }
     258           0 :     return QWidget::eventFilter(object, event);
     259             : }
     260             : 
     261           0 : QWidget *BitcoinAmountField::setupTabChain(QWidget *prev)
     262             : {
     263           0 :     QWidget::setTabOrder(prev, amount);
     264           0 :     QWidget::setTabOrder(amount, unit);
     265           0 :     return unit;
     266             : }
     267             : 
     268           0 : CAmount BitcoinAmountField::value(bool *valid_out) const
     269             : {
     270           0 :     return amount->value(valid_out);
     271             : }
     272             : 
     273           0 : void BitcoinAmountField::setValue(const CAmount& value)
     274             : {
     275           0 :     amount->setValue(value);
     276           0 : }
     277             : 
     278           0 : void BitcoinAmountField::setReadOnly(bool fReadOnly)
     279             : {
     280           0 :     amount->setReadOnly(fReadOnly);
     281           0 : }
     282             : 
     283           0 : void BitcoinAmountField::unitChanged(int idx)
     284             : {
     285             :     // Use description tooltip for current unit for the combobox
     286           0 :     unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString());
     287             : 
     288             :     // Determine new unit ID
     289           0 :     int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt();
     290             : 
     291           0 :     amount->setDisplayUnit(newUnit);
     292           0 : }
     293             : 
     294           0 : void BitcoinAmountField::setDisplayUnit(int newUnit)
     295             : {
     296           0 :     unit->setValue(newUnit);
     297           0 : }
     298             : 
     299           0 : void BitcoinAmountField::setSingleStep(const CAmount& step)
     300             : {
     301           0 :     amount->setSingleStep(step);
     302           0 : }

Generated by: LCOV version 1.11