+ improve QuantitySpinBox
This commit is contained in:
parent
3887080274
commit
3c754da0cb
|
@ -459,8 +459,7 @@ class PrefQuantitySpinBoxPrivate
|
|||
{
|
||||
public:
|
||||
PrefQuantitySpinBoxPrivate() :
|
||||
historySize(5),
|
||||
saveSize(5)
|
||||
historySize(5)
|
||||
{
|
||||
}
|
||||
~PrefQuantitySpinBoxPrivate()
|
||||
|
@ -470,7 +469,6 @@ public:
|
|||
QByteArray prefGrp;
|
||||
ParameterGrp::handle handle;
|
||||
int historySize;
|
||||
int saveSize;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -485,6 +483,8 @@ PrefQuantitySpinBox::~PrefQuantitySpinBox()
|
|||
|
||||
void PrefQuantitySpinBox::contextMenuEvent(QContextMenuEvent *event)
|
||||
{
|
||||
Q_D(PrefQuantitySpinBox);
|
||||
|
||||
QMenu *editMenu = lineEdit()->createStandardContextMenu();
|
||||
editMenu->setTitle(tr("Edit"));
|
||||
QMenu* menu = new QMenu(QString::fromAscii("PrefQuantitySpinBox"));
|
||||
|
@ -497,9 +497,9 @@ void PrefQuantitySpinBox::contextMenuEvent(QContextMenuEvent *event)
|
|||
std::vector<QAction *> actions;
|
||||
|
||||
// add the history menu part...
|
||||
std::vector<QString> history = getHistory();
|
||||
QStringList history = getHistory();
|
||||
|
||||
for (std::vector<QString>::const_iterator it = history.begin();it!= history.end();++it) {
|
||||
for (QStringList::const_iterator it = history.begin();it!= history.end();++it) {
|
||||
actions.push_back(menu->addAction(*it));
|
||||
values.push_back(*it);
|
||||
}
|
||||
|
@ -507,24 +507,23 @@ void PrefQuantitySpinBox::contextMenuEvent(QContextMenuEvent *event)
|
|||
// add the save value portion of the menu
|
||||
menu->addSeparator();
|
||||
QAction *saveValueAction = menu->addAction(tr("Save value"));
|
||||
std::vector<QString> savedValues = getSavedValues();
|
||||
|
||||
for (std::vector<QString>::const_iterator it = savedValues.begin();it!= savedValues.end();++it) {
|
||||
actions.push_back(menu->addAction(*it));
|
||||
values.push_back(*it);
|
||||
}
|
||||
QAction *clearListAction = menu->addAction(tr("Clear list"));
|
||||
clearListAction->setDisabled(history.empty());
|
||||
|
||||
// call the menu and wait until its back
|
||||
QAction *saveAction = menu->exec(event->globalPos());
|
||||
QAction *userAction = menu->exec(event->globalPos());
|
||||
|
||||
// look what the user has choosen
|
||||
if (saveAction == saveValueAction) {
|
||||
pushToSavedValues(this->text());
|
||||
if (userAction == saveValueAction) {
|
||||
pushToHistory(this->text());
|
||||
}
|
||||
else if (userAction == clearListAction) {
|
||||
d->handle->Clear();
|
||||
}
|
||||
else {
|
||||
int i=0;
|
||||
for (std::vector<QAction *>::const_iterator it = actions.begin();it!=actions.end();++it,i++) {
|
||||
if (*it == saveAction) {
|
||||
if (*it == userAction) {
|
||||
lineEdit()->setText(values[i]);
|
||||
break;
|
||||
}
|
||||
|
@ -544,32 +543,29 @@ void PrefQuantitySpinBox::pushToHistory(const QString &valueq)
|
|||
else
|
||||
val = valueq;
|
||||
|
||||
// check if already in:
|
||||
std::vector<QString> hist = getHistory();
|
||||
for (std::vector<QString>::const_iterator it = hist.begin();it!=hist.end();++it) {
|
||||
if (*it == val)
|
||||
return;
|
||||
}
|
||||
|
||||
std::string value(val.toUtf8());
|
||||
if (d->handle.isValid()) {
|
||||
for (int i = d->historySize -1 ; i>=0 ;i--) {
|
||||
QByteArray hist1 = "Hist";
|
||||
QByteArray hist0 = "Hist";
|
||||
hist1.append(QByteArray::number(i+1));
|
||||
hist0.append(QByteArray::number(i));
|
||||
std::string tHist = d->handle->GetASCII(hist0);
|
||||
if (!tHist.empty())
|
||||
d->handle->SetASCII(hist1,tHist.c_str());
|
||||
// do nothing if the given value is on top of the history
|
||||
std::string tHist = d->handle->GetASCII("Hist0");
|
||||
if (tHist != val.toUtf8().constData()) {
|
||||
for (int i = d->historySize -1 ; i>=0 ;i--) {
|
||||
QByteArray hist1 = "Hist";
|
||||
QByteArray hist0 = "Hist";
|
||||
hist1.append(QByteArray::number(i+1));
|
||||
hist0.append(QByteArray::number(i));
|
||||
std::string tHist = d->handle->GetASCII(hist0);
|
||||
if (!tHist.empty())
|
||||
d->handle->SetASCII(hist1,tHist.c_str());
|
||||
}
|
||||
d->handle->SetASCII("Hist0",value.c_str());
|
||||
}
|
||||
d->handle->SetASCII("Hist0",value.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<QString> PrefQuantitySpinBox::getHistory() const
|
||||
QStringList PrefQuantitySpinBox::getHistory() const
|
||||
{
|
||||
Q_D(const PrefQuantitySpinBox);
|
||||
std::vector<QString> res;
|
||||
QStringList res;
|
||||
|
||||
if (d->handle.isValid()) {
|
||||
std::string tmp;
|
||||
|
@ -583,56 +579,17 @@ std::vector<QString> PrefQuantitySpinBox::getHistory() const
|
|||
break; // end of history reached
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void PrefQuantitySpinBox::setToLastUsedValue()
|
||||
{
|
||||
std::vector<QString> hist = getHistory();
|
||||
QStringList hist = getHistory();
|
||||
if (!hist.empty())
|
||||
lineEdit()->setText(hist[0]);
|
||||
}
|
||||
|
||||
void PrefQuantitySpinBox::pushToSavedValues(const QString &valueq)
|
||||
{
|
||||
Q_D(PrefQuantitySpinBox);
|
||||
std::string value;
|
||||
value = valueq.toUtf8().constData();
|
||||
|
||||
if (d->handle.isValid()) {
|
||||
for (int i = d->saveSize -1 ; i>=0 ;i--) {
|
||||
QByteArray hist1 = "Save";
|
||||
QByteArray hist0 = "Save";
|
||||
hist1.append(QByteArray::number(i+1));
|
||||
hist0.append(QByteArray::number(i));
|
||||
std::string tHist = d->handle->GetASCII(hist0);
|
||||
if (!tHist.empty())
|
||||
d->handle->SetASCII(hist1,tHist.c_str());
|
||||
}
|
||||
d->handle->SetASCII("Save0",value.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<QString> PrefQuantitySpinBox::getSavedValues() const
|
||||
{
|
||||
Q_D(const PrefQuantitySpinBox);
|
||||
std::vector<QString> res;
|
||||
|
||||
if (d->handle.isValid()) {
|
||||
std::string tmp;
|
||||
for (int i = 0 ; i< d->saveSize ;i++) {
|
||||
QByteArray hist = "Save";
|
||||
hist.append(QByteArray::number(i));
|
||||
tmp = d->handle->GetASCII(hist);
|
||||
if (!tmp.empty())
|
||||
res.push_back(QString::fromUtf8(tmp.c_str()));
|
||||
else
|
||||
break; // end of history reached
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void PrefQuantitySpinBox::setParamGrpPath(const QByteArray& path)
|
||||
{
|
||||
Q_D(PrefQuantitySpinBox);
|
||||
|
|
|
@ -306,11 +306,7 @@ public:
|
|||
/// push a new value to the history, if no string given the actual text of the input field is used.
|
||||
void pushToHistory(const QString& value = QString());
|
||||
/// get the history of the field, newest first
|
||||
std::vector<QString> getHistory() const;
|
||||
/// push a new value to the history, if no string given the actual text of the input field is used.
|
||||
void pushToSavedValues(const QString& value);
|
||||
/// get the history of the field, newest first
|
||||
std::vector<QString> getSavedValues() const;
|
||||
QStringList getHistory() const;
|
||||
//@}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -48,38 +48,158 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
QString stripped(const QString &t, int *pos) const
|
||||
{
|
||||
QString text = t;
|
||||
const int s = text.size();
|
||||
text = text.trimmed();
|
||||
if (pos)
|
||||
(*pos) -= (s - text.size());
|
||||
return text;
|
||||
}
|
||||
|
||||
Base::Quantity validateAndInterpret(QString& input, int& pos, QValidator::State& state) const
|
||||
{
|
||||
Base::Quantity res;
|
||||
if (input.isEmpty()) {
|
||||
state = QValidator::Intermediate;
|
||||
return res;
|
||||
const double max = this->maximum;
|
||||
const double min = this->minimum;
|
||||
|
||||
QString copy = input;
|
||||
|
||||
int len = copy.size();
|
||||
const bool plus = max >= 0;
|
||||
const bool minus = min <= 0;
|
||||
|
||||
switch (len) {
|
||||
case 0:
|
||||
state = max != min ? QValidator::Intermediate : QValidator::Invalid;
|
||||
goto end;
|
||||
case 1:
|
||||
if (copy.at(0) == locale.decimalPoint()) {
|
||||
state = QValidator::Intermediate;
|
||||
copy.prepend(QLatin1Char('0'));
|
||||
pos++;
|
||||
len++;
|
||||
goto end;
|
||||
}
|
||||
else if (copy.at(0) == QLatin1Char('+')) {
|
||||
// the quantity parser doesn't allow numbers of the form '+1.0'
|
||||
state = QValidator::Invalid;
|
||||
goto end;
|
||||
}
|
||||
else if (copy.at(0) == QLatin1Char('-')) {
|
||||
if (minus)
|
||||
state = QValidator::Intermediate;
|
||||
else
|
||||
state = QValidator::Invalid;
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (copy.at(1) == locale.decimalPoint()
|
||||
&& (plus && copy.at(0) == QLatin1Char('+'))) {
|
||||
state = QValidator::Intermediate;
|
||||
goto end;
|
||||
}
|
||||
if (copy.at(1) == locale.decimalPoint()
|
||||
&& (minus && copy.at(0) == QLatin1Char('-'))) {
|
||||
state = QValidator::Intermediate;
|
||||
copy.insert(1, QLatin1Char('0'));
|
||||
pos++;
|
||||
len++;
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (copy.at(0) == locale.groupSeparator()) {
|
||||
state = QValidator::Invalid;
|
||||
goto end;
|
||||
}
|
||||
else if (len > 1) {
|
||||
const int dec = copy.indexOf(locale.decimalPoint());
|
||||
if (dec != -1) {
|
||||
if (dec + 1 < copy.size() && copy.at(dec + 1) == locale.decimalPoint() && pos == dec + 1) {
|
||||
copy.remove(dec + 1, 1);
|
||||
}
|
||||
else if (copy.indexOf(locale.decimalPoint(), dec + 1) != -1) {
|
||||
// trying to add a second decimal point is not allowed
|
||||
state = QValidator::Invalid;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
for (int i=dec + 1; i<copy.size(); ++i) {
|
||||
// a group separator after the decimal point is not allowed
|
||||
if (copy.at(i) == locale.groupSeparator()) {
|
||||
state = QValidator::Invalid;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
double value = min;
|
||||
|
||||
if (locale.negativeSign() != QLatin1Char('-'))
|
||||
copy.replace(locale.negativeSign(), QLatin1Char('-'));
|
||||
if (locale.positiveSign() != QLatin1Char('+'))
|
||||
copy.replace(locale.positiveSign(), QLatin1Char('+'));
|
||||
|
||||
try {
|
||||
res = Base::Quantity::parse(input);
|
||||
QString copy2 = copy;
|
||||
copy2.remove(locale.groupSeparator());
|
||||
|
||||
double factor;
|
||||
QString unitStr;
|
||||
res.getUserString(factor, unitStr);
|
||||
double value = res.getValue()/factor;
|
||||
// disallow to enter numbers out of range
|
||||
if (value > this->maximum || value < this->minimum)
|
||||
state = QValidator::Invalid;
|
||||
else
|
||||
state = QValidator::Acceptable;
|
||||
res = Base::Quantity::parse(copy2);
|
||||
value = res.getValue();
|
||||
ok = true;
|
||||
}
|
||||
catch (Base::Exception&) {
|
||||
// Actually invalid input but the newInput slot gives
|
||||
// some feedback
|
||||
state = QValidator::Intermediate;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
// input may not be finished
|
||||
state = QValidator::Intermediate;
|
||||
}
|
||||
else if (value >= min && value <= max) {
|
||||
if (copy.endsWith(locale.decimalPoint())) {
|
||||
// input shouldn't end with a decimal point
|
||||
state = QValidator::Intermediate;
|
||||
}
|
||||
else if (res.getUnit().isEmpty() && !this->unit.isEmpty()) {
|
||||
// if not dimensionless the input should have a dimension
|
||||
state = QValidator::Intermediate;
|
||||
}
|
||||
else if (res.getUnit() != this->unit) {
|
||||
state = QValidator::Invalid;
|
||||
}
|
||||
else {
|
||||
state = QValidator::Acceptable;
|
||||
}
|
||||
}
|
||||
else if (max == min) { // when max and min is the same the only non-Invalid input is max (or min)
|
||||
state = QValidator::Invalid;
|
||||
}
|
||||
else {
|
||||
if ((value >= 0 && value > max) || (value < 0 && value < min)) {
|
||||
state = QValidator::Invalid;
|
||||
}
|
||||
else {
|
||||
state = QValidator::Intermediate;
|
||||
}
|
||||
}
|
||||
end:
|
||||
if (state != QValidator::Acceptable) {
|
||||
res.setValue(max > 0 ? min : max);
|
||||
}
|
||||
|
||||
input = copy;
|
||||
return res;
|
||||
}
|
||||
|
||||
QLocale locale;
|
||||
bool validInput;
|
||||
QString errorText;
|
||||
QString validStr;
|
||||
Base::Quantity quantity;
|
||||
Base::Unit unit;
|
||||
double unitValue;
|
||||
|
@ -93,6 +213,7 @@ public:
|
|||
QuantitySpinBox::QuantitySpinBox(QWidget *parent)
|
||||
: QAbstractSpinBox(parent), d_ptr(new QuantitySpinBoxPrivate())
|
||||
{
|
||||
d_ptr->locale = locale();
|
||||
this->setContextMenuPolicy(Qt::DefaultContextMenu);
|
||||
QObject::connect(lineEdit(), SIGNAL(textChanged(QString)),
|
||||
this, SLOT(userInput(QString)));
|
||||
|
@ -145,54 +266,42 @@ bool QuantitySpinBox::hasValidInput() const
|
|||
return d->validInput;
|
||||
}
|
||||
|
||||
// Gets called after call of 'validateAndInterpret'
|
||||
void QuantitySpinBox::userInput(const QString & text)
|
||||
{
|
||||
Q_D(QuantitySpinBox);
|
||||
|
||||
if (text.isEmpty()) {
|
||||
d->errorText.clear();
|
||||
QString tmp = text;
|
||||
int pos;
|
||||
QValidator::State state;
|
||||
Base::Quantity res = d->validateAndInterpret(tmp, pos, state);
|
||||
if (state == QValidator::Acceptable) {
|
||||
d->validInput = true;
|
||||
return;
|
||||
d->validStr = text;
|
||||
}
|
||||
|
||||
Base::Quantity res;
|
||||
try {
|
||||
QString input = text;
|
||||
fixup(input);
|
||||
res = Base::Quantity::parse(input);
|
||||
else if (state == QValidator::Intermediate) {
|
||||
tmp = tmp.trimmed();
|
||||
tmp += QLatin1Char(' ');
|
||||
tmp += d->unitStr;
|
||||
Base::Quantity res2 = d->validateAndInterpret(tmp, pos, state);
|
||||
if (state == QValidator::Acceptable) {
|
||||
d->validInput = true;
|
||||
d->validStr = tmp;
|
||||
res = res2;
|
||||
}
|
||||
else {
|
||||
d->validInput = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Base::Exception &e) {
|
||||
d->errorText = QString::fromAscii(e.what());
|
||||
parseError(d->errorText);
|
||||
else {
|
||||
d->validInput = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.getUnit().isEmpty())
|
||||
res.setUnit(d->unit);
|
||||
|
||||
// check if unit fits!
|
||||
if (!d->unit.isEmpty() && !res.getUnit().isEmpty() && d->unit != res.getUnit()){
|
||||
parseError(QString::fromAscii("Wrong unit"));
|
||||
d->validInput = false;
|
||||
return;
|
||||
}
|
||||
|
||||
d->errorText.clear();
|
||||
d->validInput = true;
|
||||
|
||||
if (res.getValue() > d->maximum){
|
||||
res.setValue(d->maximum);
|
||||
d->errorText = tr("Maximum reached");
|
||||
}
|
||||
if (res.getValue() < d->minimum){
|
||||
res.setValue(d->minimum);
|
||||
d->errorText = tr("Minimum reached");
|
||||
}
|
||||
|
||||
double dFactor;
|
||||
res.getUserString(dFactor,d->unitStr);
|
||||
d->unitValue = res.getValue()/dFactor;
|
||||
double factor;
|
||||
res.getUserString(factor,d->unitStr);
|
||||
d->unitValue = res.getValue()/factor;
|
||||
d->quantity = res;
|
||||
|
||||
// signaling
|
||||
|
@ -276,7 +385,7 @@ void QuantitySpinBox::setRange(double minimum, double maximum)
|
|||
QAbstractSpinBox::StepEnabled QuantitySpinBox::stepEnabled() const
|
||||
{
|
||||
Q_D(const QuantitySpinBox);
|
||||
if (isReadOnly() || !d->validInput)
|
||||
if (isReadOnly()/* || !d->validInput*/)
|
||||
return StepNone;
|
||||
if (wrapping())
|
||||
return StepEnabled(StepUpEnabled | StepDownEnabled);
|
||||
|
@ -331,6 +440,20 @@ void QuantitySpinBox::focusInEvent(QFocusEvent * event)
|
|||
}
|
||||
}
|
||||
|
||||
void QuantitySpinBox::focusOutEvent(QFocusEvent * event)
|
||||
{
|
||||
Q_D(QuantitySpinBox);
|
||||
|
||||
int pos;
|
||||
QString text = lineEdit()->text();
|
||||
QValidator::State state;
|
||||
d->validateAndInterpret(text, pos, state);
|
||||
if (state != QValidator::Acceptable) {
|
||||
lineEdit()->setText(d->validStr);
|
||||
}
|
||||
QAbstractSpinBox::focusOutEvent(event);
|
||||
}
|
||||
|
||||
void QuantitySpinBox::clear()
|
||||
{
|
||||
QAbstractSpinBox::clear();
|
||||
|
@ -377,10 +500,15 @@ Base::Quantity QuantitySpinBox::valueFromText(const QString &text) const
|
|||
Q_D(const QuantitySpinBox);
|
||||
|
||||
QString copy = text;
|
||||
fixup( copy );
|
||||
int pos = lineEdit()->cursorPosition();
|
||||
QValidator::State state = QValidator::Acceptable;
|
||||
return d->validateAndInterpret(copy, pos, state);
|
||||
Base::Quantity quant = d->validateAndInterpret(copy, pos, state);
|
||||
if (state != QValidator::Acceptable) {
|
||||
fixup(copy);
|
||||
quant = d->validateAndInterpret(copy, pos, state);
|
||||
}
|
||||
|
||||
return quant;
|
||||
}
|
||||
|
||||
QValidator::State QuantitySpinBox::validate(QString &text, int &pos) const
|
||||
|
@ -388,19 +516,13 @@ QValidator::State QuantitySpinBox::validate(QString &text, int &pos) const
|
|||
Q_D(const QuantitySpinBox);
|
||||
|
||||
QValidator::State state;
|
||||
QString copy = text;
|
||||
fixup(copy);
|
||||
d->validateAndInterpret(copy, pos, state);
|
||||
d->validateAndInterpret(text, pos, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
void QuantitySpinBox::fixup(QString &input) const
|
||||
{
|
||||
input.remove(locale().groupSeparator());
|
||||
if (locale().negativeSign() != QLatin1Char('-'))
|
||||
input.replace(locale().negativeSign(), QLatin1Char('-'));
|
||||
if (locale().positiveSign() != QLatin1Char('+'))
|
||||
input.replace(locale().positiveSign(), QLatin1Char('+'));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ protected:
|
|||
virtual StepEnabled stepEnabled() const;
|
||||
virtual void showEvent(QShowEvent * event);
|
||||
virtual void focusInEvent(QFocusEvent * event);
|
||||
virtual void focusOutEvent(QFocusEvent * event);
|
||||
|
||||
private:
|
||||
void updateText(const Base::Quantity&);
|
||||
|
@ -124,9 +125,6 @@ Q_SIGNALS:
|
|||
*/
|
||||
void valueChanged(double);
|
||||
|
||||
/// Signal for an invalid user input
|
||||
void parseError(const QString& errorText);
|
||||
|
||||
private:
|
||||
QScopedPointer<QuantitySpinBoxPrivate> d_ptr;
|
||||
Q_DISABLE_COPY(QuantitySpinBox)
|
||||
|
|
Loading…
Reference in New Issue
Block a user