Resolved issue #606. Mac OS X. Can’t type in measurements due to digit count
limitation. --HG-- branch : develop
This commit is contained in:
parent
290f78651d
commit
da6cd92b22
|
@ -48,6 +48,7 @@
|
||||||
- [#582] Issue with standard path to shared data on Linux.
|
- [#582] Issue with standard path to shared data on Linux.
|
||||||
- [#595] GapWidth affecting to the margins.
|
- [#595] GapWidth affecting to the margins.
|
||||||
- [#589] Valentina lock up if not enough space for label.
|
- [#589] Valentina lock up if not enough space for label.
|
||||||
|
- [#606] Mac OS X. Can’t type in measurements due to digit count limitation.
|
||||||
|
|
||||||
# Version 0.4.6
|
# Version 0.4.6
|
||||||
- [#594] Broken export on Mac.
|
- [#594] Broken export on Mac.
|
||||||
|
|
275
src/libs/qmuparser/qmudef.cpp
Normal file
275
src/libs/qmuparser/qmudef.cpp
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 Roman Telezhynskyi <dismine(at)gmail.com>
|
||||||
|
**
|
||||||
|
** Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
** software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
** without restriction, including without limitation the rights to use, copy, modify,
|
||||||
|
** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
** permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
**
|
||||||
|
** The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
** substantial portions of the Software.
|
||||||
|
**
|
||||||
|
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||||
|
** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
**
|
||||||
|
******************************************************************************************************/
|
||||||
|
|
||||||
|
#include "qmudef.h"
|
||||||
|
|
||||||
|
#include <QLocale>
|
||||||
|
#include <QSet>
|
||||||
|
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
Init = 0,
|
||||||
|
Sign = 1,
|
||||||
|
Thousand = 2,
|
||||||
|
Mantissa = 3,
|
||||||
|
Dot = 4,
|
||||||
|
Abscissa = 5,
|
||||||
|
ExpMark = 6,
|
||||||
|
ExpSign = 7,
|
||||||
|
Exponent = 8,
|
||||||
|
Done = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
enum InputToken
|
||||||
|
{
|
||||||
|
InputSign = 1,
|
||||||
|
InputThousand = 2,
|
||||||
|
InputDigit = 3,
|
||||||
|
InputDot = 4,
|
||||||
|
InputExp = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
static const QChar QmuEOF = QChar(static_cast<ushort>(0xffff)); //guaranteed not to be a character.
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
static QChar GetChar(const QString &formula, int &index)
|
||||||
|
{
|
||||||
|
if (index >= formula.size())
|
||||||
|
{
|
||||||
|
return QmuEOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return formula.at(index++);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
static QChar EatWhiteSpace(const QString &formula, int &index)
|
||||||
|
{
|
||||||
|
QChar c;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
c = GetChar(formula, index);
|
||||||
|
}
|
||||||
|
while ( c != QmuEOF && c.isSpace() );
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
static int CheckChar(QChar &c, const QLocale &locale, const QChar &decimal, const QChar &thousand)
|
||||||
|
{
|
||||||
|
INIT_LOCALE_VARIABLES(locale);
|
||||||
|
|
||||||
|
if (c == positiveSign)
|
||||||
|
{
|
||||||
|
c = '+';
|
||||||
|
return InputToken::InputSign;
|
||||||
|
}
|
||||||
|
else if (c == negativeSign)
|
||||||
|
{
|
||||||
|
c = '-';
|
||||||
|
return InputToken::InputSign;
|
||||||
|
}
|
||||||
|
else if (c == sign0)
|
||||||
|
{
|
||||||
|
c = '0';
|
||||||
|
return InputToken::InputDigit;
|
||||||
|
}
|
||||||
|
else if (c == sign1)
|
||||||
|
{
|
||||||
|
c = '1';
|
||||||
|
return InputToken::InputDigit;
|
||||||
|
}
|
||||||
|
else if (c == sign2)
|
||||||
|
{
|
||||||
|
c = '2';
|
||||||
|
return InputToken::InputDigit;
|
||||||
|
}
|
||||||
|
else if (c == sign3)
|
||||||
|
{
|
||||||
|
c = '3';
|
||||||
|
return InputToken::InputDigit;
|
||||||
|
}
|
||||||
|
else if (c == sign4)
|
||||||
|
{
|
||||||
|
c = '4';
|
||||||
|
return InputToken::InputDigit;
|
||||||
|
}
|
||||||
|
else if (c == sign5)
|
||||||
|
{
|
||||||
|
c = '5';
|
||||||
|
return InputToken::InputDigit;
|
||||||
|
}
|
||||||
|
else if (c == sign6)
|
||||||
|
{
|
||||||
|
c = '6';
|
||||||
|
return InputToken::InputDigit;
|
||||||
|
}
|
||||||
|
else if (c == sign7)
|
||||||
|
{
|
||||||
|
c = '7';
|
||||||
|
return InputToken::InputDigit;
|
||||||
|
}
|
||||||
|
else if (c == sign8)
|
||||||
|
{
|
||||||
|
c = '8';
|
||||||
|
return InputToken::InputDigit;
|
||||||
|
}
|
||||||
|
else if (c == sign9)
|
||||||
|
{
|
||||||
|
c = '9';
|
||||||
|
return InputToken::InputDigit;
|
||||||
|
}
|
||||||
|
else if (c == decimal)
|
||||||
|
{
|
||||||
|
return InputToken::InputDot;
|
||||||
|
}
|
||||||
|
else if (c == thousand)
|
||||||
|
{
|
||||||
|
return InputToken::InputThousand;
|
||||||
|
}
|
||||||
|
else if (c == expLower)
|
||||||
|
{
|
||||||
|
c = 'e';
|
||||||
|
return InputToken::InputExp;
|
||||||
|
}
|
||||||
|
else if (c == expUpper)
|
||||||
|
{
|
||||||
|
c = 'E';
|
||||||
|
return InputToken::InputExp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
int ReadVal(const QString &formula, qreal &val, const QLocale &locale, const QChar &decimal, const QChar &thousand)
|
||||||
|
{
|
||||||
|
// Must not be equal
|
||||||
|
if (decimal == thousand || formula.isEmpty())
|
||||||
|
{
|
||||||
|
val = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT_LOCALE_VARIABLES(locale);
|
||||||
|
|
||||||
|
QSet<QChar> reserved;
|
||||||
|
reserved << positiveSign
|
||||||
|
<< negativeSign
|
||||||
|
<< sign0
|
||||||
|
<< sign1
|
||||||
|
<< sign2
|
||||||
|
<< sign3
|
||||||
|
<< sign4
|
||||||
|
<< sign5
|
||||||
|
<< sign6
|
||||||
|
<< sign7
|
||||||
|
<< sign8
|
||||||
|
<< sign9
|
||||||
|
<< expUpper
|
||||||
|
<< expLower;
|
||||||
|
|
||||||
|
if (reserved.contains(decimal) || reserved.contains(thousand))
|
||||||
|
{
|
||||||
|
val = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// row - current state, column - new state
|
||||||
|
static uchar table[9][6] =
|
||||||
|
{
|
||||||
|
/* None InputSign InputThousand InputDigit InputDot InputExp */
|
||||||
|
{ 0, State::Sign, 0, State::Mantissa, State::Dot, 0, }, // Init
|
||||||
|
{ 0, 0, 0, State::Mantissa, State::Dot, 0, }, // Sign
|
||||||
|
{ 0, 0, 0, State::Mantissa, 0, 0, }, // Thousand
|
||||||
|
{ State::Done, State::Done, State::Thousand, State::Mantissa, State::Dot, State::ExpMark,}, // Mantissa
|
||||||
|
{ 0, 0, 0, State::Abscissa, 0, 0, }, // Dot
|
||||||
|
{ State::Done, State::Done, 0, State::Abscissa, 0, State::ExpMark,}, // Abscissa
|
||||||
|
{ 0, State::ExpSign, 0, State::Exponent, 0, 0, }, // ExpMark
|
||||||
|
{ 0, 0, 0, State::Exponent, 0, 0, }, // ExpSign
|
||||||
|
{ State::Done, 0, 0, State::Exponent, 0, State::Done } // Exponent
|
||||||
|
};
|
||||||
|
|
||||||
|
int state = State::Init; // parse state
|
||||||
|
int input; // input token
|
||||||
|
QString buf;
|
||||||
|
|
||||||
|
int index = 0; // start position
|
||||||
|
QChar c = EatWhiteSpace(formula, index);
|
||||||
|
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
input = CheckChar(c, locale, decimal, thousand);
|
||||||
|
|
||||||
|
state = table[state][input];
|
||||||
|
|
||||||
|
if (state == 0)
|
||||||
|
{
|
||||||
|
val = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (state == Done)
|
||||||
|
{
|
||||||
|
// Convert to C locale
|
||||||
|
QLocale cLocale(QLocale::C);
|
||||||
|
const QChar cDecimal = cLocale.decimalPoint();
|
||||||
|
const QChar cThousand = cLocale.groupSeparator();
|
||||||
|
if (locale != cLocale && (cDecimal != decimal || cThousand != thousand))
|
||||||
|
{
|
||||||
|
if (decimal == cThousand)
|
||||||
|
{// Handle reverse to C locale case: thousand '.', decimal ','
|
||||||
|
const QChar tmpThousand = '@';
|
||||||
|
buf.replace(thousand, tmpThousand);
|
||||||
|
buf.replace(decimal, cDecimal);
|
||||||
|
buf.replace(tmpThousand, cThousand);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buf.replace(thousand, cThousand);
|
||||||
|
buf.replace(decimal, cDecimal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
const double d = cLocale.toDouble(buf, &ok);
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
val = d;
|
||||||
|
return buf.size();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
val = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.append(c);
|
||||||
|
c = GetChar(formula, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -90,6 +90,25 @@ QT_WARNING_DISABLE_GCC("-Wattributes")
|
||||||
#ifdef Q_CC_MSVC
|
#ifdef Q_CC_MSVC
|
||||||
#include <ciso646>
|
#include <ciso646>
|
||||||
#endif /* Q_CC_MSVC */
|
#endif /* Q_CC_MSVC */
|
||||||
|
|
||||||
|
class QLocale;
|
||||||
|
|
||||||
|
#define INIT_LOCALE_VARIABLES(locale) \
|
||||||
|
const QChar positiveSign = (locale).positiveSign(); \
|
||||||
|
const QChar negativeSign = (locale).negativeSign(); \
|
||||||
|
const QChar sign0 = (locale).toString(0).at(0); \
|
||||||
|
const QChar sign1 = (locale).toString(1).at(0); \
|
||||||
|
const QChar sign2 = (locale).toString(2).at(0); \
|
||||||
|
const QChar sign3 = (locale).toString(3).at(0); \
|
||||||
|
const QChar sign4 = (locale).toString(4).at(0); \
|
||||||
|
const QChar sign5 = (locale).toString(5).at(0); \
|
||||||
|
const QChar sign6 = (locale).toString(6).at(0); \
|
||||||
|
const QChar sign7 = (locale).toString(7).at(0); \
|
||||||
|
const QChar sign8 = (locale).toString(8).at(0); \
|
||||||
|
const QChar sign9 = (locale).toString(9).at(0); \
|
||||||
|
const QChar expUpper = (locale).exponential().toUpper(); \
|
||||||
|
const QChar expLower = (locale).exponential().toLower() \
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
inline QString NameRegExp()
|
inline QString NameRegExp()
|
||||||
{
|
{
|
||||||
|
@ -119,4 +138,6 @@ static inline bool QmuFuzzyComparePossibleNulls(double p1, double p2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ReadVal(const QString &formula, qreal &val, const QLocale &locale, const QChar &decimal, const QChar &thousand);
|
||||||
|
|
||||||
#endif // QMUDEF_H
|
#endif // QMUDEF_H
|
||||||
|
|
|
@ -46,13 +46,13 @@ QmuFormulaBase::~QmuFormulaBase()
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* @brief InitCharacterSets init character set for parser.
|
* @brief InitCharSets init character set for parser.
|
||||||
*
|
*
|
||||||
* QMuParser require setting character set for legal characters. Because we try make our expresion language independent
|
* QMuParser require setting character set for legal characters. Because we try make our expresion language independent
|
||||||
* we set all posible unique characters from all alphabets.
|
* we set all posible unique characters from all alphabets.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void QmuFormulaBase::InitCharacterSets()
|
void QmuFormulaBase::InitCharSets()
|
||||||
{
|
{
|
||||||
//String with all unique symbols for supported alphabets.
|
//String with all unique symbols for supported alphabets.
|
||||||
//See script alphabets.py for generation and more information.
|
//See script alphabets.py for generation and more information.
|
||||||
|
@ -68,9 +68,18 @@ void QmuFormulaBase::InitCharacterSets()
|
||||||
<< "ЪƯخγвŅԴŪضλкԼĴσтÅՄنъÍՌRӕՔZÝŜbåդﻩjíլļrӵմzýռپêЅքćچЍďӱҒЕůėژșΘØҚНğńءΠFҢХħΨҪ"
|
<< "ЪƯخγвŅԴŪضλкԼĴσтÅՄنъÍՌRӕՔZÝŜbåդﻩjíլļrӵմzýռپêЅքćچЍďӱҒЕůėژșΘØҚНğńءΠFҢХħΨҪ"
|
||||||
<< "ЭųįҶرҲеԷňعθҺнԿفπÂхՇψÊэšՏÒUəÚѝŻşҤӑâeէŐımկòuշÕúտŔ";
|
<< "ЭųįҶرҲеԷňعθҺнԿفπÂхՇψÊэšՏÒUəÚѝŻşҤӑâeէŐımկòuշÕúտŔ";
|
||||||
|
|
||||||
|
INIT_LOCALE_VARIABLES(m_locale);
|
||||||
|
|
||||||
// Defining identifier character sets
|
// Defining identifier character sets
|
||||||
DefineNameChars(QStringLiteral("0123456789_@#'") + symbols.join(""));
|
const QString nameChars = QString() + sign0 + sign1 + sign2 + sign3 + sign4 + sign5 + sign6 + sign7 + sign8 +
|
||||||
DefineOprtChars(symbols.join("") + QStringLiteral("+-*^/?<>=!$%&|~_"));
|
sign9 + QLatin1String("_@#'") + symbols.join("");
|
||||||
|
DefineNameChars(nameChars);
|
||||||
|
|
||||||
|
const QString oprtChars = symbols.join("") + positiveSign + negativeSign + QLatin1String("*^/?<>=!$%&|~'_");
|
||||||
|
DefineOprtChars(oprtChars);
|
||||||
|
|
||||||
|
const QString infixOprtChars = QString() + positiveSign + negativeSign + QLatin1String("*^/?<>=!$%&|~'_");
|
||||||
|
DefineInfixOprtChars(infixOprtChars);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
@ -94,12 +103,13 @@ void QmuFormulaBase::SetSepForTr(bool osSeparator, bool fromUser)
|
||||||
{
|
{
|
||||||
if (fromUser)
|
if (fromUser)
|
||||||
{
|
{
|
||||||
|
const QLocale loc = QLocale();
|
||||||
|
setLocale(loc);
|
||||||
|
SetArgSep(';');
|
||||||
if (osSeparator)
|
if (osSeparator)
|
||||||
{
|
{
|
||||||
const QLocale loc = QLocale::system();
|
setDecimalPoint(loc.decimalPoint());
|
||||||
SetDecSep(loc.decimalPoint().toLatin1());
|
setThousandsSeparator(loc.groupSeparator());
|
||||||
SetThousandsSep(loc.groupSeparator().toLatin1());
|
|
||||||
SetArgSep(';');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,8 +124,8 @@ void QmuFormulaBase::SetSepForTr(bool osSeparator, bool fromUser)
|
||||||
void QmuFormulaBase::SetSepForEval()
|
void QmuFormulaBase::SetSepForEval()
|
||||||
{
|
{
|
||||||
SetArgSep(';');
|
SetArgSep(';');
|
||||||
SetThousandsSep(',');
|
setThousandsSeparator(',');
|
||||||
SetDecSep('.');
|
setDecimalPoint('.');
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -41,14 +41,14 @@ public:
|
||||||
QmuFormulaBase();
|
QmuFormulaBase();
|
||||||
virtual ~QmuFormulaBase() Q_DECL_OVERRIDE;
|
virtual ~QmuFormulaBase() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
virtual void InitCharSets() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
static void RemoveAll(QMap<int, QString> &map, const QString &val);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void InitCharacterSets();
|
|
||||||
static qreal* AddVariable(const QString &a_szName, void *a_pUserData);
|
static qreal* AddVariable(const QString &a_szName, void *a_pUserData);
|
||||||
void SetSepForTr(bool osSeparator, bool fromUser);
|
void SetSepForTr(bool osSeparator, bool fromUser);
|
||||||
void SetSepForEval();
|
void SetSepForEval();
|
||||||
|
|
||||||
static void RemoveAll(QMap<int, QString> &map, const QString &val);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(QmuFormulaBase)
|
Q_DISABLE_COPY(QmuFormulaBase)
|
||||||
};
|
};
|
||||||
|
|
|
@ -225,23 +225,19 @@ qreal QmuParser::Max(const qreal *a_afArg, int a_iArgc)
|
||||||
* @param [out] a_fVal Pointer where the value should be stored in case one is found.
|
* @param [out] a_fVal Pointer where the value should be stored in case one is found.
|
||||||
* @return 1 if a value was found 0 otherwise.
|
* @return 1 if a value was found 0 otherwise.
|
||||||
*/
|
*/
|
||||||
int QmuParser::IsVal(const QString &a_szExpr, int *a_iPos, qreal *a_fVal, const std::locale &s_locale)
|
int QmuParser::IsVal(const QString &a_szExpr, int *a_iPos, qreal *a_fVal, const QLocale &locale, const QChar &decimal,
|
||||||
|
const QChar &thousand)
|
||||||
{
|
{
|
||||||
qreal fVal(0);
|
qreal fVal(0);
|
||||||
|
|
||||||
std::wstring a_szExprStd = a_szExpr.toStdWString();
|
const int pos = ReadVal(a_szExpr, fVal, locale, decimal, thousand);
|
||||||
stringstream_type stream(a_szExprStd);
|
|
||||||
stream.seekg(0); // todo: check if this really is necessary
|
|
||||||
stream.imbue(s_locale);
|
|
||||||
stream >> fVal;
|
|
||||||
stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading
|
|
||||||
|
|
||||||
if (iEnd==static_cast<stringstream_type::pos_type>(-1))
|
if (pos == -1)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*a_iPos += static_cast<int>(iEnd);
|
*a_iPos += pos;
|
||||||
*a_fVal = fVal;
|
*a_fVal = fVal;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -340,7 +336,7 @@ void QmuParser::InitConst()
|
||||||
*/
|
*/
|
||||||
void QmuParser::InitOprt()
|
void QmuParser::InitOprt()
|
||||||
{
|
{
|
||||||
DefineInfixOprt("-", UnaryMinus);
|
DefineInfixOprt(m_locale.negativeSign(), UnaryMinus);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
|
|
||||||
#include "../qmuparser/qmuparser_global.h"
|
|
||||||
#include "qmuparser_global.h"
|
#include "qmuparser_global.h"
|
||||||
#include "qmuparserbase.h"
|
#include "qmuparserbase.h"
|
||||||
|
|
||||||
|
@ -59,7 +58,8 @@ namespace qmu
|
||||||
virtual void OnDetectVar(const QString &pExpr, int &nStart, int &nEnd) Q_DECL_OVERRIDE;
|
virtual void OnDetectVar(const QString &pExpr, int &nStart, int &nEnd) Q_DECL_OVERRIDE;
|
||||||
qreal Diff(qreal *a_Var, qreal a_fPos, qreal a_fEpsilon = 0) const;
|
qreal Diff(qreal *a_Var, qreal a_fPos, qreal a_fEpsilon = 0) const;
|
||||||
protected:
|
protected:
|
||||||
static int IsVal(const QString &a_szExpr, int *a_iPos, qreal *a_fVal, const std::locale &s_locale);
|
static int IsVal(const QString &a_szExpr, int *a_iPos, qreal *a_fVal, const QLocale &locale,
|
||||||
|
const QChar &decimal, const QChar &thousand);
|
||||||
// hyperbolic functions
|
// hyperbolic functions
|
||||||
static qreal Sinh(qreal);
|
static qreal Sinh(qreal);
|
||||||
static qreal Cosh(qreal);
|
static qreal Cosh(qreal);
|
||||||
|
|
|
@ -11,7 +11,8 @@ SOURCES += \
|
||||||
$$PWD/qmuparsertest.cpp \
|
$$PWD/qmuparsertest.cpp \
|
||||||
$$PWD/qmutranslation.cpp \
|
$$PWD/qmutranslation.cpp \
|
||||||
$$PWD/qmuformulabase.cpp \
|
$$PWD/qmuformulabase.cpp \
|
||||||
$$PWD/qmutokenparser.cpp
|
$$PWD/qmutokenparser.cpp \
|
||||||
|
$$PWD/qmudef.cpp
|
||||||
|
|
||||||
win32-msvc*:SOURCES += $$PWD/stable.cpp
|
win32-msvc*:SOURCES += $$PWD/stable.cpp
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ OBJECTS_DIR = obj
|
||||||
|
|
||||||
include(qmuparser.pri)
|
include(qmuparser.pri)
|
||||||
|
|
||||||
VERSION = 2.4.1
|
VERSION = 2.5.0
|
||||||
|
|
||||||
# Allow MAC OS X to find library inside a bundle
|
# Allow MAC OS X to find library inside a bundle
|
||||||
macx:QMAKE_SONAME_PREFIX = @rpath
|
macx:QMAKE_SONAME_PREFIX = @rpath
|
||||||
|
|
|
@ -62,11 +62,31 @@ const QStringList QmuParserBase::c_DefaultOprt = QStringList()<< "<=" << ">=" <<
|
||||||
* @brief Constructor.
|
* @brief Constructor.
|
||||||
*/
|
*/
|
||||||
QmuParserBase::QmuParserBase()
|
QmuParserBase::QmuParserBase()
|
||||||
:s_locale(std::locale(std::locale::classic(), new change_dec_sep<char_type>('.'))),
|
: m_locale(QLocale::c()),
|
||||||
m_pParseFormula(&QmuParserBase::ParseString), m_vRPN(), m_vStringBuf(), m_vStringVarBuf(), m_pTokenReader(),
|
m_decimalPoint(QLocale::c().decimalPoint()),
|
||||||
m_FunDef(), m_PostOprtDef(), m_InfixOprtDef(), m_OprtDef(), m_ConstDef(), m_StrVarDef(), m_VarDef(),
|
m_thousandsSeparator(QLocale::c().groupSeparator()),
|
||||||
m_bBuiltInOp(true), m_sNameChars(), m_sOprtChars(), m_sInfixOprtChars(), m_nIfElseCounter(0), m_vStackBuffer(),
|
m_pParseFormula(&QmuParserBase::ParseString),
|
||||||
m_nFinalResultIdx(0), m_Tokens(QMap<int, QString>()), m_Numbers(QMap<int, QString>()), allowSubexpressions(true)
|
m_vRPN(),
|
||||||
|
m_vStringBuf(),
|
||||||
|
m_vStringVarBuf(),
|
||||||
|
m_pTokenReader(),
|
||||||
|
m_FunDef(),
|
||||||
|
m_PostOprtDef(),
|
||||||
|
m_InfixOprtDef(),
|
||||||
|
m_OprtDef(),
|
||||||
|
m_ConstDef(),
|
||||||
|
m_StrVarDef(),
|
||||||
|
m_VarDef(),
|
||||||
|
m_bBuiltInOp(true),
|
||||||
|
m_sNameChars(),
|
||||||
|
m_sOprtChars(),
|
||||||
|
m_sInfixOprtChars(),
|
||||||
|
m_nIfElseCounter(0),
|
||||||
|
m_vStackBuffer(),
|
||||||
|
m_nFinalResultIdx(0),
|
||||||
|
m_Tokens(QMap<int, QString>()),
|
||||||
|
m_Numbers(QMap<int, QString>()),
|
||||||
|
allowSubexpressions(true)
|
||||||
{
|
{
|
||||||
InitTokenReader();
|
InitTokenReader();
|
||||||
}
|
}
|
||||||
|
@ -78,11 +98,31 @@ QmuParserBase::QmuParserBase()
|
||||||
* Tha parser can be safely copy constructed but the bytecode is reset during copy construction.
|
* Tha parser can be safely copy constructed but the bytecode is reset during copy construction.
|
||||||
*/
|
*/
|
||||||
QmuParserBase::QmuParserBase(const QmuParserBase &a_Parser)
|
QmuParserBase::QmuParserBase(const QmuParserBase &a_Parser)
|
||||||
:s_locale(a_Parser.getLocale()), m_pParseFormula(&QmuParserBase::ParseString), m_vRPN(), m_vStringBuf(),
|
: m_locale(a_Parser.getLocale()),
|
||||||
m_vStringVarBuf(), m_pTokenReader(), m_FunDef(), m_PostOprtDef(), m_InfixOprtDef(), m_OprtDef(), m_ConstDef(),
|
m_decimalPoint(a_Parser.getDecimalPoint()),
|
||||||
m_StrVarDef(), m_VarDef(), m_bBuiltInOp(true), m_sNameChars(), m_sOprtChars(), m_sInfixOprtChars(),
|
m_thousandsSeparator(a_Parser.getThousandsSeparator()),
|
||||||
m_nIfElseCounter(0), m_vStackBuffer(), m_nFinalResultIdx(0), m_Tokens(QMap<int, QString>()),
|
m_pParseFormula(&QmuParserBase::ParseString),
|
||||||
m_Numbers(QMap<int, QString>()), allowSubexpressions(true)
|
m_vRPN(),
|
||||||
|
m_vStringBuf(),
|
||||||
|
m_vStringVarBuf(),
|
||||||
|
m_pTokenReader(),
|
||||||
|
m_FunDef(),
|
||||||
|
m_PostOprtDef(),
|
||||||
|
m_InfixOprtDef(),
|
||||||
|
m_OprtDef(),
|
||||||
|
m_ConstDef(),
|
||||||
|
m_StrVarDef(),
|
||||||
|
m_VarDef(),
|
||||||
|
m_bBuiltInOp(true),
|
||||||
|
m_sNameChars(),
|
||||||
|
m_sOprtChars(),
|
||||||
|
m_sInfixOprtChars(),
|
||||||
|
m_nIfElseCounter(0),
|
||||||
|
m_vStackBuffer(),
|
||||||
|
m_nFinalResultIdx(0),
|
||||||
|
m_Tokens(QMap<int, QString>()),
|
||||||
|
m_Numbers(QMap<int, QString>()),
|
||||||
|
allowSubexpressions(true)
|
||||||
{
|
{
|
||||||
m_pTokenReader.reset(new token_reader_type(this));
|
m_pTokenReader.reset(new token_reader_type(this));
|
||||||
Assign(a_Parser);
|
Assign(a_Parser);
|
||||||
|
@ -150,38 +190,6 @@ void QmuParserBase::Assign(const QmuParserBase &a_Parser)
|
||||||
m_sInfixOprtChars = a_Parser.m_sInfixOprtChars;
|
m_sInfixOprtChars = a_Parser.m_sInfixOprtChars;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* @brief Set the decimal separator.
|
|
||||||
* @param cDecSep Decimal separator as a character value.
|
|
||||||
* @sa SetThousandsSep
|
|
||||||
*
|
|
||||||
* By default muparser uses the "C" locale. The decimal separator of this
|
|
||||||
* locale is overwritten by the one provided here.
|
|
||||||
*/
|
|
||||||
// cppcheck-suppress unusedFunction
|
|
||||||
void QmuParserBase::SetDecSep(char_type cDecSep)
|
|
||||||
{
|
|
||||||
char_type cThousandsSep = std::use_facet< change_dec_sep<char_type> >(s_locale).thousands_sep();
|
|
||||||
s_locale = std::locale(std::locale("C"), new change_dec_sep<char_type>(cDecSep, cThousandsSep));
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* @brief Sets the thousands operator.
|
|
||||||
* @param cThousandsSep The thousands separator as a character
|
|
||||||
* @sa SetDecSep
|
|
||||||
*
|
|
||||||
* By default muparser uses the "C" locale. The thousands separator of this
|
|
||||||
* locale is overwritten by the one provided here.
|
|
||||||
*/
|
|
||||||
// cppcheck-suppress unusedFunction
|
|
||||||
void QmuParserBase::SetThousandsSep(char_type cThousandsSep)
|
|
||||||
{
|
|
||||||
char_type cDecSep = std::use_facet< change_dec_sep<char_type> >(s_locale).decimal_point();
|
|
||||||
s_locale = std::locale(std::locale("C"), new change_dec_sep<char_type>(cDecSep, cThousandsSep));
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* @brief Resets the locale.
|
* @brief Resets the locale.
|
||||||
|
@ -191,8 +199,10 @@ void QmuParserBase::SetThousandsSep(char_type cThousandsSep)
|
||||||
// cppcheck-suppress unusedFunction
|
// cppcheck-suppress unusedFunction
|
||||||
void QmuParserBase::ResetLocale()
|
void QmuParserBase::ResetLocale()
|
||||||
{
|
{
|
||||||
s_locale = std::locale(std::locale("C"), new change_dec_sep<char_type>('.'));
|
setLocale(QLocale::c());
|
||||||
SetArgSep(',');
|
m_decimalPoint = m_locale.decimalPoint();
|
||||||
|
m_thousandsSeparator = m_locale.groupSeparator();
|
||||||
|
SetArgSep(';');
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
@ -228,15 +238,41 @@ void QmuParserBase::setAllowSubexpressions(bool value)
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
std::locale QmuParserBase::getLocale() const
|
QLocale QmuParserBase::getLocale() const
|
||||||
{
|
{
|
||||||
return s_locale;
|
return m_locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
void QmuParserBase::setLocale(const std::locale &value)
|
void QmuParserBase::setLocale(const QLocale &value)
|
||||||
{
|
{
|
||||||
s_locale = value;
|
m_locale = value;
|
||||||
|
InitCharSets();
|
||||||
|
InitOprt();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
QChar QmuParserBase::getDecimalPoint() const
|
||||||
|
{
|
||||||
|
return m_decimalPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void QmuParserBase::setDecimalPoint(const QChar &c)
|
||||||
|
{
|
||||||
|
m_decimalPoint = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
QChar QmuParserBase::getThousandsSeparator() const
|
||||||
|
{
|
||||||
|
return m_thousandsSeparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void QmuParserBase::setThousandsSeparator(const QChar &c)
|
||||||
|
{
|
||||||
|
m_thousandsSeparator = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
@ -1319,7 +1355,7 @@ void QmuParserBase::CreateRPN() const
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
opt = m_pTokenReader->ReadNextToken(s_locale);
|
opt = m_pTokenReader->ReadNextToken(m_locale, m_decimalPoint, m_thousandsSeparator);
|
||||||
|
|
||||||
switch (opt.GetCode())
|
switch (opt.GetCode())
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,11 +31,10 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <locale>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <QLocale>
|
||||||
|
|
||||||
#include "../qmuparser/qmuparser_global.h"
|
|
||||||
#include "qmuparser_global.h"
|
#include "qmuparser_global.h"
|
||||||
#include "qmuparserbytecode.h"
|
#include "qmuparserbytecode.h"
|
||||||
#include "qmuparsercallback.h"
|
#include "qmuparsercallback.h"
|
||||||
|
@ -81,8 +80,6 @@ public:
|
||||||
int GetNumResults() const;
|
int GetNumResults() const;
|
||||||
void SetExpr(const QString &a_sExpr);
|
void SetExpr(const QString &a_sExpr);
|
||||||
void SetVarFactory(facfun_type a_pFactory, void *pUserData = nullptr);
|
void SetVarFactory(facfun_type a_pFactory, void *pUserData = nullptr);
|
||||||
void SetDecSep(char_type cDecSep);
|
|
||||||
void SetThousandsSep(char_type cThousandsSep = 0);
|
|
||||||
void ResetLocale();
|
void ResetLocale();
|
||||||
void EnableOptimizer(bool a_bIsOn=true);
|
void EnableOptimizer(bool a_bIsOn=true);
|
||||||
void EnableBuiltInOprt(bool a_bIsOn=true);
|
void EnableBuiltInOprt(bool a_bIsOn=true);
|
||||||
|
@ -128,12 +125,20 @@ public:
|
||||||
|
|
||||||
void setAllowSubexpressions(bool value);
|
void setAllowSubexpressions(bool value);
|
||||||
|
|
||||||
std::locale getLocale() const;
|
QLocale getLocale() const;
|
||||||
void setLocale(const std::locale &value);
|
void setLocale(const QLocale &value);
|
||||||
|
|
||||||
|
QChar getDecimalPoint() const;
|
||||||
|
void setDecimalPoint(const QChar &c);
|
||||||
|
|
||||||
|
QChar getThousandsSeparator() const;
|
||||||
|
void setThousandsSeparator(const QChar &c);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static const QStringList c_DefaultOprt;
|
static const QStringList c_DefaultOprt;
|
||||||
std::locale s_locale; ///< The locale used by the parser
|
QLocale m_locale;///< The locale used by the parser
|
||||||
|
QChar m_decimalPoint;
|
||||||
|
QChar m_thousandsSeparator;
|
||||||
static bool g_DbgDumpCmdCode;
|
static bool g_DbgDumpCmdCode;
|
||||||
static bool g_DbgDumpStack;
|
static bool g_DbgDumpStack;
|
||||||
void Init();
|
void Init();
|
||||||
|
|
|
@ -32,8 +32,8 @@
|
||||||
@brief This file contains standard definitions used by the parser.
|
@brief This file contains standard definitions used by the parser.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define QMUP_VERSION "2.2.4"
|
#define QMUP_VERSION "2.5.0"
|
||||||
#define QMUP_VERSION_DATE "20140504; GC"
|
#define QMUP_VERSION_DATE "20170101; GC"
|
||||||
|
|
||||||
#define QMUP_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
#define QMUP_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|
||||||
|
@ -64,6 +64,8 @@
|
||||||
/** @brief Definition of the basic parser string type. */
|
/** @brief Definition of the basic parser string type. */
|
||||||
#define QMUP_STRING_TYPE std::wstring
|
#define QMUP_STRING_TYPE std::wstring
|
||||||
|
|
||||||
|
class QLocale;
|
||||||
|
|
||||||
namespace qmu
|
namespace qmu
|
||||||
{
|
{
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -275,7 +277,8 @@ typedef qreal ( *strfun_type2 ) ( const QString &, qreal );
|
||||||
typedef qreal ( *strfun_type3 ) ( const QString &, qreal, qreal );
|
typedef qreal ( *strfun_type3 ) ( const QString &, qreal, qreal );
|
||||||
|
|
||||||
/** @brief Callback used for functions that identify values in a string. */
|
/** @brief Callback used for functions that identify values in a string. */
|
||||||
typedef int ( *identfun_type ) ( const QString &sExpr, int *nPos, qreal *fVal, const std::locale &s_locale );
|
typedef int ( *identfun_type ) ( const QString &sExpr, int *nPos, qreal *fVal, const QLocale &locale,
|
||||||
|
const QChar &decimal, const QChar &thousand );
|
||||||
|
|
||||||
/** @brief Callback used for variable creation factory functions. */
|
/** @brief Callback used for variable creation factory functions. */
|
||||||
typedef qreal* ( *facfun_type ) ( const QString &, void* );
|
typedef qreal* ( *facfun_type ) ( const QString &, void* );
|
||||||
|
|
|
@ -74,9 +74,12 @@ QmuParserTester::QmuParserTester(QObject *parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
int QmuParserTester::IsHexVal ( const QString &a_szExpr, int *a_iPos, qreal *a_fVal, const std::locale &s_locale )
|
int QmuParserTester::IsHexVal ( const QString &a_szExpr, int *a_iPos, qreal *a_fVal, const QLocale &locale,
|
||||||
|
const QChar &decimal, const QChar &thousand )
|
||||||
{
|
{
|
||||||
Q_UNUSED(s_locale)
|
Q_UNUSED(locale)
|
||||||
|
Q_UNUSED(decimal)
|
||||||
|
Q_UNUSED(thousand)
|
||||||
if ( a_szExpr.data()[1] == 0 || ( a_szExpr.data()[0] != '0' || a_szExpr.data()[1] != 'x' ) )
|
if ( a_szExpr.data()[1] == 0 || ( a_szExpr.data()[0] != '0' || a_szExpr.data()[1] != 'x' ) )
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -293,7 +293,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom value recognition
|
// Custom value recognition
|
||||||
static int IsHexVal (const QString &a_szExpr, int *a_iPos, qreal *a_fVal, const std::locale &s_locale);
|
static int IsHexVal (const QString &a_szExpr, int *a_iPos, qreal *a_fVal, const QLocale &locale,
|
||||||
|
const QChar &decimal, const QChar &thousand);
|
||||||
|
|
||||||
// cppcheck-suppress functionStatic
|
// cppcheck-suppress functionStatic
|
||||||
int TestNames();
|
int TestNames();
|
||||||
|
|
|
@ -213,7 +213,8 @@ void QmuParserTokenReader::ReInit()
|
||||||
/**
|
/**
|
||||||
* @brief Read the next token from the string.
|
* @brief Read the next token from the string.
|
||||||
*/
|
*/
|
||||||
QmuParserTokenReader::token_type QmuParserTokenReader::ReadNextToken(const std::locale &s_locale)
|
QmuParserTokenReader::token_type QmuParserTokenReader::ReadNextToken(const QLocale &locale, const QChar &decimal,
|
||||||
|
const QChar &thousand)
|
||||||
{
|
{
|
||||||
assert ( m_pParser );
|
assert ( m_pParser );
|
||||||
|
|
||||||
|
@ -245,7 +246,7 @@ QmuParserTokenReader::token_type QmuParserTokenReader::ReadNextToken(const std::
|
||||||
{
|
{
|
||||||
return SaveBeforeReturn ( tok ); // Check for function argument separators
|
return SaveBeforeReturn ( tok ); // Check for function argument separators
|
||||||
}
|
}
|
||||||
if ( IsValTok ( tok, s_locale ) )
|
if ( IsValTok ( tok, locale, decimal, thousand ) )
|
||||||
{
|
{
|
||||||
return SaveBeforeReturn ( tok ); // Check for values / constant tokens
|
return SaveBeforeReturn ( tok ); // Check for values / constant tokens
|
||||||
}
|
}
|
||||||
|
@ -779,7 +780,8 @@ bool QmuParserTokenReader::IsPostOpTok ( token_type &a_Tok )
|
||||||
* @param a_Tok [out] If a value token is found it will be placed here.
|
* @param a_Tok [out] If a value token is found it will be placed here.
|
||||||
* @return true if a value token has been found.
|
* @return true if a value token has been found.
|
||||||
*/
|
*/
|
||||||
bool QmuParserTokenReader::IsValTok ( token_type &a_Tok, const std::locale &s_locale )
|
bool QmuParserTokenReader::IsValTok ( token_type &a_Tok, const QLocale &locale, const QChar &decimal,
|
||||||
|
const QChar &thousand )
|
||||||
{
|
{
|
||||||
assert ( m_pConstDef );
|
assert ( m_pConstDef );
|
||||||
assert ( m_pParser );
|
assert ( m_pParser );
|
||||||
|
@ -815,7 +817,7 @@ bool QmuParserTokenReader::IsValTok ( token_type &a_Tok, const std::locale &s_lo
|
||||||
for ( item = m_vIdentFun.begin(); item != m_vIdentFun.end(); ++item )
|
for ( item = m_vIdentFun.begin(); item != m_vIdentFun.end(); ++item )
|
||||||
{
|
{
|
||||||
int iStart = m_iPos;
|
int iStart = m_iPos;
|
||||||
if ( ( *item ) ( m_strFormula.mid ( m_iPos ), &m_iPos, &fVal, s_locale ) == 1 )
|
if ( ( *item ) ( m_strFormula.mid ( m_iPos ), &m_iPos, &fVal, locale, decimal, thousand ) == 1 )
|
||||||
{
|
{
|
||||||
// 2013-11-27 Issue 2: https://code.google.com/p/muparser/issues/detail?id=2
|
// 2013-11-27 Issue 2: https://code.google.com/p/muparser/issues/detail?id=2
|
||||||
strTok = m_strFormula.mid ( iStart, m_iPos-iStart );
|
strTok = m_strFormula.mid ( iStart, m_iPos-iStart );
|
||||||
|
|
|
@ -66,7 +66,7 @@ public:
|
||||||
QChar GetArgSep() const;
|
QChar GetArgSep() const;
|
||||||
void IgnoreUndefVar(bool bIgnore);
|
void IgnoreUndefVar(bool bIgnore);
|
||||||
void ReInit();
|
void ReInit();
|
||||||
token_type ReadNextToken(const std::locale &s_locale);
|
token_type ReadNextToken(const QLocale &locale, const QChar &decimal, const QChar &thousand);
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -111,7 +111,7 @@ private:
|
||||||
bool IsFunTok(token_type &a_Tok);
|
bool IsFunTok(token_type &a_Tok);
|
||||||
bool IsPostOpTok(token_type &a_Tok);
|
bool IsPostOpTok(token_type &a_Tok);
|
||||||
bool IsOprt(token_type &a_Tok);
|
bool IsOprt(token_type &a_Tok);
|
||||||
bool IsValTok(token_type &a_Tok, const std::locale &s_locale);
|
bool IsValTok(token_type &a_Tok, const QLocale &locale, const QChar &decimal, const QChar &thousand);
|
||||||
bool IsVarTok(token_type &a_Tok);
|
bool IsVarTok(token_type &a_Tok);
|
||||||
bool IsStrVarTok(token_type &a_Tok);
|
bool IsStrVarTok(token_type &a_Tok);
|
||||||
bool IsUndefVarTok(token_type &a_Tok);
|
bool IsUndefVarTok(token_type &a_Tok);
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace qmu
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
QmuTokenParser::QmuTokenParser()
|
QmuTokenParser::QmuTokenParser()
|
||||||
{
|
{
|
||||||
InitCharacterSets();
|
InitCharSets();
|
||||||
setAllowSubexpressions(false);//Only one expression per time
|
setAllowSubexpressions(false);//Only one expression per time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ QmuTokenParser::QmuTokenParser()
|
||||||
QmuTokenParser::QmuTokenParser(const QString &formula, bool osSeparator, bool fromUser)
|
QmuTokenParser::QmuTokenParser(const QString &formula, bool osSeparator, bool fromUser)
|
||||||
:QmuFormulaBase()
|
:QmuFormulaBase()
|
||||||
{
|
{
|
||||||
InitCharacterSets();
|
InitCharSets();
|
||||||
setAllowSubexpressions(false);//Only one expression per time
|
setAllowSubexpressions(false);//Only one expression per time
|
||||||
SetVarFactory(AddVariable, this);
|
SetVarFactory(AddVariable, this);
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
Calculator::Calculator()
|
Calculator::Calculator()
|
||||||
:QmuFormulaBase()
|
:QmuFormulaBase()
|
||||||
{
|
{
|
||||||
InitCharacterSets();
|
InitCharSets();
|
||||||
setAllowSubexpressions(false);//Only one expression per time
|
setAllowSubexpressions(false);//Only one expression per time
|
||||||
|
|
||||||
SetSepForEval();
|
SetSepForEval();
|
||||||
|
|
|
@ -780,6 +780,11 @@ QString VTranslateVars::FormulaFromUser(const QString &formula, bool osSeparator
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tValues.at(i) == QLocale().negativeSign())
|
||||||
|
{// unary minus
|
||||||
|
newFormula.replace(tKeys.at(i), 1, '-');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QLocale loc = QLocale(); // User locale
|
QLocale loc = QLocale(); // User locale
|
||||||
|
@ -916,6 +921,11 @@ QString VTranslateVars::FormulaToUser(const QString &formula, bool osSeparator)
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tValues.at(i) == QChar('-'))
|
||||||
|
{// unary minus
|
||||||
|
newFormula.replace(tKeys.at(i), 1, QLocale().negativeSign());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QLocale loc = QLocale();// User locale
|
QLocale loc = QLocale();// User locale
|
||||||
|
@ -936,11 +946,6 @@ QString VTranslateVars::FormulaToUser(const QString &formula, bool osSeparator)
|
||||||
|
|
||||||
loc = QLocale();// To user locale
|
loc = QLocale();// To user locale
|
||||||
QString dStr = loc.toString(d);// Number string in user locale
|
QString dStr = loc.toString(d);// Number string in user locale
|
||||||
const QChar thSep = loc.groupSeparator();
|
|
||||||
if (thSep.isSpace())
|
|
||||||
{
|
|
||||||
dStr.remove(thSep);// Remove thousand separator
|
|
||||||
}
|
|
||||||
newFormula.replace(nKeys.at(i), nValues.at(i).length(), dStr);
|
newFormula.replace(nKeys.at(i), nValues.at(i).length(), dStr);
|
||||||
const int bias = nValues.at(i).length() - dStr.length();
|
const int bias = nValues.at(i).length() - dStr.length();
|
||||||
if (bias != 0)
|
if (bias != 0)
|
||||||
|
|
|
@ -53,7 +53,9 @@ SOURCES += \
|
||||||
tst_vcubicbezierpath.cpp \
|
tst_vcubicbezierpath.cpp \
|
||||||
tst_vgobject.cpp \
|
tst_vgobject.cpp \
|
||||||
tst_vsplinepath.cpp \
|
tst_vsplinepath.cpp \
|
||||||
tst_vpointf.cpp
|
tst_vpointf.cpp \
|
||||||
|
tst_readval.cpp \
|
||||||
|
tst_vtranslatevars.cpp
|
||||||
|
|
||||||
win32-msvc*:SOURCES += stable.cpp
|
win32-msvc*:SOURCES += stable.cpp
|
||||||
|
|
||||||
|
@ -77,7 +79,9 @@ HEADERS += \
|
||||||
tst_vcubicbezierpath.h \
|
tst_vcubicbezierpath.h \
|
||||||
tst_vgobject.h \
|
tst_vgobject.h \
|
||||||
tst_vsplinepath.h \
|
tst_vsplinepath.h \
|
||||||
tst_vpointf.h
|
tst_vpointf.h \
|
||||||
|
tst_readval.h \
|
||||||
|
tst_vtranslatevars.h
|
||||||
|
|
||||||
# Set using ccache. Function enable_ccache() defined in common.pri.
|
# Set using ccache. Function enable_ccache() defined in common.pri.
|
||||||
$$enable_ccache()
|
$$enable_ccache()
|
||||||
|
|
|
@ -47,8 +47,11 @@
|
||||||
#include "tst_vgobject.h"
|
#include "tst_vgobject.h"
|
||||||
#include "tst_vsplinepath.h"
|
#include "tst_vsplinepath.h"
|
||||||
#include "tst_vpointf.h"
|
#include "tst_vpointf.h"
|
||||||
|
#include "tst_readval.h"
|
||||||
|
#include "tst_vtranslatevars.h"
|
||||||
|
|
||||||
#include "../vmisc/def.h"
|
#include "../vmisc/def.h"
|
||||||
|
#include "../qmuparser/qmudef.h"
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
@ -82,6 +85,8 @@ int main(int argc, char** argv)
|
||||||
ASSERT_TEST(new TST_VCubicBezierPath());
|
ASSERT_TEST(new TST_VCubicBezierPath());
|
||||||
ASSERT_TEST(new TST_VGObject());
|
ASSERT_TEST(new TST_VGObject());
|
||||||
ASSERT_TEST(new TST_VPointF());
|
ASSERT_TEST(new TST_VPointF());
|
||||||
|
ASSERT_TEST(new TST_ReadVal());
|
||||||
|
ASSERT_TEST(new TST_VTranslateVars());
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,14 @@
|
||||||
|
|
||||||
#include "tst_qmutokenparser.h"
|
#include "tst_qmutokenparser.h"
|
||||||
#include "../qmuparser/qmutokenparser.h"
|
#include "../qmuparser/qmutokenparser.h"
|
||||||
|
#include "../vmisc/logging.h"
|
||||||
|
|
||||||
#include <QtTest>
|
#include <QtTest>
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
TST_QmuTokenParser::TST_QmuTokenParser(QObject *parent)
|
TST_QmuTokenParser::TST_QmuTokenParser(QObject *parent)
|
||||||
:QObject(parent)
|
: QObject(parent),
|
||||||
|
m_systemLocale(QLocale::system())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +58,7 @@ void TST_QmuTokenParser::IsSingle_data()
|
||||||
QTest::newRow("Correct C locale 15500") << "15500" << true;
|
QTest::newRow("Correct C locale 15500") << "15500" << true;
|
||||||
QTest::newRow("Correct C locale 15,500") << "15,500" << true;
|
QTest::newRow("Correct C locale 15,500") << "15,500" << true;
|
||||||
QTest::newRow("Correct C locale 15,500.1") << "15,500.1" << true;
|
QTest::newRow("Correct C locale 15,500.1") << "15,500.1" << true;
|
||||||
|
QTest::newRow("Correct C locale 15500.1") << "15500.1" << true;
|
||||||
QTest::newRow("Not C locale 15,5") << "15,5" << false;
|
QTest::newRow("Not C locale 15,5") << "15,5" << false;
|
||||||
QTest::newRow("Not C locale 15.500,1") << "15.500,1" << false;
|
QTest::newRow("Not C locale 15.500,1") << "15.500,1" << false;
|
||||||
}
|
}
|
||||||
|
@ -68,3 +71,95 @@ void TST_QmuTokenParser::IsSingle()
|
||||||
|
|
||||||
QCOMPARE(qmu::QmuTokenParser::IsSingle(formula), result);
|
QCOMPARE(qmu::QmuTokenParser::IsSingle(formula), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_QmuTokenParser::TokenFromUser_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>("formula");
|
||||||
|
QTest::addColumn<bool>("result");
|
||||||
|
QTest::addColumn<QLocale>("locale");
|
||||||
|
|
||||||
|
const QList<QLocale> allLocales =
|
||||||
|
QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
|
||||||
|
for(int i = 0; i < allLocales.size(); ++i)
|
||||||
|
{
|
||||||
|
const QLocale locale = allLocales.at(i);
|
||||||
|
PrepareVal(1000.5, locale);
|
||||||
|
PrepareVal(-1000.5, locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_QmuTokenParser::TokenFromUser()
|
||||||
|
{
|
||||||
|
QFETCH(QString, formula);
|
||||||
|
QFETCH(bool, result);
|
||||||
|
QFETCH(QLocale, locale);
|
||||||
|
|
||||||
|
QLocale::setDefault(locale);
|
||||||
|
|
||||||
|
QCOMPARE(IsSingleFromUser(formula), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_QmuTokenParser::cleanupTestCase()
|
||||||
|
{
|
||||||
|
QLocale::setDefault(m_systemLocale);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_QmuTokenParser::PrepareVal(qreal val, const QLocale &locale)
|
||||||
|
{
|
||||||
|
const QString formula = locale.toString(val);
|
||||||
|
QString string = formula;
|
||||||
|
QString tag = QString("%1. String '%2'").arg(locale.name()).arg(string);
|
||||||
|
QTest::newRow(qUtf8Printable(tag)) << string << true << locale;
|
||||||
|
|
||||||
|
string = formula+QLatin1String("+");
|
||||||
|
tag = QString("%1. String '%2'").arg(locale.name()).arg(string);
|
||||||
|
QTest::newRow(qUtf8Printable(tag)) << string << false << locale;
|
||||||
|
|
||||||
|
string = formula+QLatin1String("+")+formula;
|
||||||
|
tag = QString("%1. String '%2'").arg(locale.name()).arg(string);
|
||||||
|
QTest::newRow(qUtf8Printable(tag)) << string << false << locale;
|
||||||
|
|
||||||
|
string = formula+QString("+б");
|
||||||
|
tag = QString("%1. String '%2'").arg(locale.name()).arg(string);
|
||||||
|
QTest::newRow(qUtf8Printable(tag)) << string << false << locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
bool TST_QmuTokenParser::IsSingleFromUser(const QString &formula)
|
||||||
|
{
|
||||||
|
if (formula.isEmpty())
|
||||||
|
{
|
||||||
|
return false;// if don't know say no
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<int, QString> tokens;
|
||||||
|
QMap<int, QString> numbers;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QScopedPointer<qmu::QmuTokenParser> cal(new qmu::QmuTokenParser(formula, true, true));
|
||||||
|
tokens = cal->GetTokens();// Tokens (variables, measurements)
|
||||||
|
numbers = cal->GetNumbers();// All numbers in expression
|
||||||
|
}
|
||||||
|
catch (const qmu::QmuParserError &e)
|
||||||
|
{
|
||||||
|
Q_UNUSED(e)
|
||||||
|
return false;// something wrong with formula, say no
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove "-" from tokens list if exist. If don't do that unary minus operation will broken.
|
||||||
|
qmu::QmuFormulaBase::RemoveAll(tokens, QLocale().negativeSign());
|
||||||
|
|
||||||
|
if (tokens.isEmpty() && numbers.size() == 1)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,18 +29,26 @@
|
||||||
#ifndef TST_QMUTOKENPARSER_H
|
#ifndef TST_QMUTOKENPARSER_H
|
||||||
#define TST_QMUTOKENPARSER_H
|
#define TST_QMUTOKENPARSER_H
|
||||||
|
|
||||||
|
#include <QLocale>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
class TST_QmuTokenParser : public QObject
|
class TST_QmuTokenParser : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Q_DISABLE_COPY(TST_QmuTokenParser)
|
|
||||||
explicit TST_QmuTokenParser(QObject *parent = nullptr);
|
explicit TST_QmuTokenParser(QObject *parent = nullptr);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void IsSingle_data();
|
void IsSingle_data();
|
||||||
void IsSingle();
|
void IsSingle();
|
||||||
|
void TokenFromUser_data();
|
||||||
|
void TokenFromUser();
|
||||||
|
void cleanupTestCase();
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(TST_QmuTokenParser)
|
||||||
|
QLocale m_systemLocale;
|
||||||
|
|
||||||
|
void PrepareVal(qreal val, const QLocale &locale);
|
||||||
|
bool IsSingleFromUser(const QString &formula);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TST_QMUTOKENPARSER_H
|
#endif // TST_QMUTOKENPARSER_H
|
||||||
|
|
153
src/test/ValentinaTest/tst_readval.cpp
Normal file
153
src/test/ValentinaTest/tst_readval.cpp
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
/************************************************************************
|
||||||
|
**
|
||||||
|
** @file
|
||||||
|
** @author Roman Telezhynskyi <dismine(at)gmail.com>
|
||||||
|
** @date 30 12, 2016
|
||||||
|
**
|
||||||
|
** @brief
|
||||||
|
** @copyright
|
||||||
|
** This source code is part of the Valentine project, a pattern making
|
||||||
|
** program, whose allow create and modeling patterns of clothing.
|
||||||
|
** Copyright (C) 2016 Valentina project
|
||||||
|
** <https://bitbucket.org/dismine/valentina> All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Valentina is free software: you can redistribute it and/or modify
|
||||||
|
** it under the terms of the GNU General Public License as published by
|
||||||
|
** the Free Software Foundation, either version 3 of the License, or
|
||||||
|
** (at your option) any later version.
|
||||||
|
**
|
||||||
|
** Valentina is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
** GNU General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License
|
||||||
|
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
**
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#include "tst_readval.h"
|
||||||
|
#include "../qmuparser/qmudef.h"
|
||||||
|
#include "../vmisc/logging.h"
|
||||||
|
|
||||||
|
#include <QtTest>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
TST_ReadVal::TST_ReadVal(QObject *parent)
|
||||||
|
: QObject(parent),
|
||||||
|
m_systemLocale(QLocale::system())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_ReadVal::TestReadVal_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>("formula");
|
||||||
|
QTest::addColumn<int>("expCount");
|
||||||
|
QTest::addColumn<qreal>("expVal");
|
||||||
|
QTest::addColumn<QLocale>("locale");
|
||||||
|
|
||||||
|
const QList<QLocale> allLocales =
|
||||||
|
QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
|
||||||
|
for(int i = 0; i < allLocales.size(); ++i)
|
||||||
|
{
|
||||||
|
const QLocale locale = allLocales.at(i);
|
||||||
|
PrepareVal(1., locale);
|
||||||
|
PrepareVal(1.0, locale);
|
||||||
|
PrepareVal(-1.0, locale);
|
||||||
|
PrepareVal(1.5, locale);
|
||||||
|
PrepareVal(-1.5, locale);
|
||||||
|
PrepareVal(1000.0, locale);
|
||||||
|
PrepareVal(-1000.0, locale);
|
||||||
|
PrepareVal(1000.5, locale);
|
||||||
|
PrepareVal(-1000.5, locale);
|
||||||
|
PrepareVal(std::numeric_limits<double>::max(), locale);
|
||||||
|
PrepareVal(-std::numeric_limits<double>::max(), locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_ReadVal::TestReadVal()
|
||||||
|
{
|
||||||
|
TestVal();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_ReadVal::TestInvalidData_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>("formula");
|
||||||
|
QTest::addColumn<int>("expCount");
|
||||||
|
QTest::addColumn<qreal>("expVal");
|
||||||
|
QTest::addColumn<QLocale>("locale");
|
||||||
|
|
||||||
|
// Test invalid values
|
||||||
|
const QLocale locale = QLocale::c();
|
||||||
|
PrepareString(QString(), locale);
|
||||||
|
PrepareString(QString("-1.000.5"), locale);
|
||||||
|
PrepareString(QString("1.000.5"), locale);
|
||||||
|
PrepareString(QString("-1.000,5"), locale);
|
||||||
|
PrepareString(QString("1.000,5"), locale);
|
||||||
|
PrepareString(QString("-1.0.00,5"), locale);
|
||||||
|
PrepareString(QString("1.0.00,5"), locale);
|
||||||
|
PrepareString(QString("7,5"), locale);
|
||||||
|
PrepareString(QString("-7,5"), locale);
|
||||||
|
PrepareString(QString("- 7,5"), locale);
|
||||||
|
PrepareString(QString("- 7.5"), locale);
|
||||||
|
PrepareString(QString("1,0,00.5"), locale);
|
||||||
|
PrepareString(QString("1,,000.5"), locale);
|
||||||
|
PrepareString(QString(",5"), locale);
|
||||||
|
PrepareString(QString(","), locale);
|
||||||
|
PrepareString(QString("."), locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_ReadVal::TestInvalidData()
|
||||||
|
{
|
||||||
|
TestVal();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_ReadVal::cleanupTestCase()
|
||||||
|
{
|
||||||
|
QLocale::setDefault(m_systemLocale);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_ReadVal::PrepareVal(qreal val, const QLocale &locale)
|
||||||
|
{
|
||||||
|
const QString string = locale.toString(val);
|
||||||
|
bool ok = false;
|
||||||
|
const double d = locale.toDouble(string, &ok);
|
||||||
|
PrepareString(string, locale, d, string.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_ReadVal::PrepareString(const QString &str, const QLocale &locale, qreal val, int count)
|
||||||
|
{
|
||||||
|
const QString tag = QString("%1. String '%2'").arg(locale.name()).arg(str);
|
||||||
|
QTest::newRow(qUtf8Printable(tag)) << str << count << val << locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_ReadVal::TestVal()
|
||||||
|
{
|
||||||
|
QFETCH(QString, formula);
|
||||||
|
QFETCH(int, expCount);
|
||||||
|
QFETCH(qreal, expVal);
|
||||||
|
QFETCH(QLocale, locale);
|
||||||
|
|
||||||
|
qreal resVal = 0;
|
||||||
|
QLocale::setDefault(locale);
|
||||||
|
|
||||||
|
const int resCount = ReadVal(formula, resVal, locale, locale.decimalPoint(), locale.groupSeparator());
|
||||||
|
|
||||||
|
QString errorMsg = QString("Conversion failed. Locale: '%1'.").arg(locale.name());
|
||||||
|
QVERIFY2(resCount == expCount, qUtf8Printable(errorMsg));
|
||||||
|
|
||||||
|
if (resCount != -1)
|
||||||
|
{
|
||||||
|
QString errorMsg = QString("Unexpected result. Locale: '%1'.").arg(locale.name());
|
||||||
|
QVERIFY2(QmuFuzzyComparePossibleNulls(resVal, expVal), qUtf8Printable(errorMsg));
|
||||||
|
}
|
||||||
|
}
|
58
src/test/ValentinaTest/tst_readval.h
Normal file
58
src/test/ValentinaTest/tst_readval.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/************************************************************************
|
||||||
|
**
|
||||||
|
** @file
|
||||||
|
** @author Roman Telezhynskyi <dismine(at)gmail.com>
|
||||||
|
** @date 30 12, 2016
|
||||||
|
**
|
||||||
|
** @brief
|
||||||
|
** @copyright
|
||||||
|
** This source code is part of the Valentine project, a pattern making
|
||||||
|
** program, whose allow create and modeling patterns of clothing.
|
||||||
|
** Copyright (C) 2016 Valentina project
|
||||||
|
** <https://bitbucket.org/dismine/valentina> All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Valentina is free software: you can redistribute it and/or modify
|
||||||
|
** it under the terms of the GNU General Public License as published by
|
||||||
|
** the Free Software Foundation, either version 3 of the License, or
|
||||||
|
** (at your option) any later version.
|
||||||
|
**
|
||||||
|
** Valentina is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
** GNU General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License
|
||||||
|
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
**
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TST_READVAL_H
|
||||||
|
#define TST_READVAL_H
|
||||||
|
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QLocale>
|
||||||
|
|
||||||
|
class TST_ReadVal : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit TST_ReadVal(QObject *parent = nullptr);
|
||||||
|
private slots:
|
||||||
|
void TestReadVal_data();
|
||||||
|
void TestReadVal();
|
||||||
|
void TestInvalidData_data();
|
||||||
|
void TestInvalidData();
|
||||||
|
void cleanupTestCase();
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(TST_ReadVal)
|
||||||
|
QLocale m_systemLocale;
|
||||||
|
|
||||||
|
void PrepareVal(qreal val, const QLocale &locale);
|
||||||
|
void PrepareString(const QString &str, const QLocale &locale, qreal val=0, int count=-1);
|
||||||
|
|
||||||
|
void TestVal();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TST_READVAL_H
|
174
src/test/ValentinaTest/tst_vtranslatevars.cpp
Normal file
174
src/test/ValentinaTest/tst_vtranslatevars.cpp
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
/************************************************************************
|
||||||
|
**
|
||||||
|
** @file
|
||||||
|
** @author Roman Telezhynskyi <dismine(at)gmail.com>
|
||||||
|
** @date 2 1, 2017
|
||||||
|
**
|
||||||
|
** @brief
|
||||||
|
** @copyright
|
||||||
|
** This source code is part of the Valentine project, a pattern making
|
||||||
|
** program, whose allow create and modeling patterns of clothing.
|
||||||
|
** Copyright (C) 2017 Valentina project
|
||||||
|
** <https://bitbucket.org/dismine/valentina> All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Valentina is free software: you can redistribute it and/or modify
|
||||||
|
** it under the terms of the GNU General Public License as published by
|
||||||
|
** the Free Software Foundation, either version 3 of the License, or
|
||||||
|
** (at your option) any later version.
|
||||||
|
**
|
||||||
|
** Valentina is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
** GNU General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License
|
||||||
|
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
**
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#include "tst_vtranslatevars.h"
|
||||||
|
#include "../vmisc/logging.h"
|
||||||
|
#include "../vpatterndb/vtranslatevars.h"
|
||||||
|
#include "../qmuparser/qmuparsererror.h"
|
||||||
|
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
TST_VTranslateVars::TST_VTranslateVars(QObject *parent)
|
||||||
|
: QObject(parent),
|
||||||
|
m_trMs(nullptr),
|
||||||
|
m_systemLocale(QLocale::system())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_VTranslateVars::initTestCase()
|
||||||
|
{
|
||||||
|
m_trMs = new VTranslateVars();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_VTranslateVars::TestFormulaFromUser_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>("input");
|
||||||
|
QTest::addColumn<QString>("output");
|
||||||
|
QTest::addColumn<QLocale>("locale");
|
||||||
|
|
||||||
|
const QList<QLocale> allLocales =
|
||||||
|
QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
|
||||||
|
for(int i = 0; i < allLocales.size(); ++i)
|
||||||
|
{
|
||||||
|
PrepareValFromUser(1000.5, allLocales.at(i));
|
||||||
|
PrepareValFromUser(-1000.5, allLocales.at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_VTranslateVars::TestFormulaFromUser()
|
||||||
|
{
|
||||||
|
QFETCH(QString, input);
|
||||||
|
QFETCH(QString, output);
|
||||||
|
QFETCH(QLocale, locale);
|
||||||
|
|
||||||
|
QLocale::setDefault(locale);
|
||||||
|
|
||||||
|
QString result;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = m_trMs->FormulaFromUser(input, true);
|
||||||
|
}
|
||||||
|
catch (qmu::QmuParserError &e)// In case something bad will happen
|
||||||
|
{
|
||||||
|
Q_UNUSED(e)
|
||||||
|
result = input;
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(result, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_VTranslateVars::TestFormulaToUser_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>("input");
|
||||||
|
QTest::addColumn<QString>("output");
|
||||||
|
QTest::addColumn<QLocale>("locale");
|
||||||
|
|
||||||
|
const QList<QLocale> allLocales =
|
||||||
|
QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
|
||||||
|
for(int i = 0; i < allLocales.size(); ++i)
|
||||||
|
{
|
||||||
|
PrepareValToUser(1000.5, allLocales.at(i));
|
||||||
|
PrepareValToUser(-1000.5, allLocales.at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_VTranslateVars::TestFormulaToUser()
|
||||||
|
{
|
||||||
|
QFETCH(QString, input);
|
||||||
|
QFETCH(QString, output);
|
||||||
|
QFETCH(QLocale, locale);
|
||||||
|
|
||||||
|
QLocale::setDefault(locale);
|
||||||
|
|
||||||
|
QString result;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = m_trMs->FormulaToUser(input, true);
|
||||||
|
}
|
||||||
|
catch (qmu::QmuParserError &e)// In case something bad will happen
|
||||||
|
{
|
||||||
|
Q_UNUSED(e)
|
||||||
|
result = input;
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(result, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_VTranslateVars::cleanupTestCase()
|
||||||
|
{
|
||||||
|
delete m_trMs;
|
||||||
|
QLocale::setDefault(m_systemLocale);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_VTranslateVars::PrepareValFromUser(double d, const QLocale &locale)
|
||||||
|
{
|
||||||
|
const QString formulaToSystem = QLocale::c().toString(d);
|
||||||
|
const QString formulaFromUser = locale.toString(d);
|
||||||
|
|
||||||
|
PrepareVal(formulaFromUser, formulaToSystem, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_VTranslateVars::PrepareValToUser(double d, const QLocale &locale)
|
||||||
|
{
|
||||||
|
const QString formulaFromSystem = QLocale::c().toString(d);
|
||||||
|
const QString formulaToUser = locale.toString(d);
|
||||||
|
|
||||||
|
PrepareVal(formulaFromSystem, formulaToUser, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------
|
||||||
|
void TST_VTranslateVars::PrepareVal(const QString &inputFormula, const QString &outputFormula, const QLocale &locale)
|
||||||
|
{
|
||||||
|
QString inputString = inputFormula;
|
||||||
|
QString outputString = outputFormula;
|
||||||
|
|
||||||
|
auto PREPARE_CASE = [locale](const QString &inputString, const QString &outputString)
|
||||||
|
{
|
||||||
|
QString tag = QString("%1. String '%2'").arg(locale.name()).arg(inputString);
|
||||||
|
QTest::newRow(qUtf8Printable(tag)) << inputString << outputString << locale;
|
||||||
|
};
|
||||||
|
|
||||||
|
PREPARE_CASE(inputString, outputString);
|
||||||
|
|
||||||
|
inputString = inputFormula+QLatin1String("+")+inputFormula;
|
||||||
|
outputString = outputFormula+QLatin1String("+")+outputFormula;
|
||||||
|
PREPARE_CASE(inputString, outputString);
|
||||||
|
|
||||||
|
inputString = inputFormula+QString("+a");
|
||||||
|
outputString = outputFormula+QString("+a");
|
||||||
|
PREPARE_CASE(inputString, outputString);
|
||||||
|
}
|
60
src/test/ValentinaTest/tst_vtranslatevars.h
Normal file
60
src/test/ValentinaTest/tst_vtranslatevars.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/************************************************************************
|
||||||
|
**
|
||||||
|
** @file
|
||||||
|
** @author Roman Telezhynskyi <dismine(at)gmail.com>
|
||||||
|
** @date 2 1, 2017
|
||||||
|
**
|
||||||
|
** @brief
|
||||||
|
** @copyright
|
||||||
|
** This source code is part of the Valentine project, a pattern making
|
||||||
|
** program, whose allow create and modeling patterns of clothing.
|
||||||
|
** Copyright (C) 2017 Valentina project
|
||||||
|
** <https://bitbucket.org/dismine/valentina> All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Valentina is free software: you can redistribute it and/or modify
|
||||||
|
** it under the terms of the GNU General Public License as published by
|
||||||
|
** the Free Software Foundation, either version 3 of the License, or
|
||||||
|
** (at your option) any later version.
|
||||||
|
**
|
||||||
|
** Valentina is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
** GNU General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License
|
||||||
|
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
**
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TST_VTRANSLATEVARS_H
|
||||||
|
#define TST_VTRANSLATEVARS_H
|
||||||
|
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
#include <QLocale>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class VTranslateVars;
|
||||||
|
|
||||||
|
class TST_VTranslateVars : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit TST_VTranslateVars(QObject *parent = nullptr);
|
||||||
|
private slots:
|
||||||
|
void initTestCase();
|
||||||
|
void TestFormulaFromUser_data();
|
||||||
|
void TestFormulaFromUser();
|
||||||
|
void TestFormulaToUser_data();
|
||||||
|
void TestFormulaToUser();
|
||||||
|
void cleanupTestCase();
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(TST_VTranslateVars)
|
||||||
|
VTranslateVars *m_trMs;
|
||||||
|
QLocale m_systemLocale;
|
||||||
|
|
||||||
|
void PrepareValFromUser(double d, const QLocale &locale);
|
||||||
|
void PrepareValToUser(double d, const QLocale &locale);
|
||||||
|
void PrepareVal(const QString &inputFormula, const QString &outputFormula, const QLocale &locale);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TST_VTRANSLATEVARS_H
|
Loading…
Reference in New Issue
Block a user