Merge pull request #6246 from elpaso/rangeformatter

[bugfix] Range formatter for doubles and ints
This commit is contained in:
Alessandro Pasotti 2018-02-02 14:25:28 +01:00 committed by GitHub
commit 5c5ef3b6de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 274 additions and 2 deletions

View File

@ -287,6 +287,7 @@
%Include geometry/qgswkbtypes.sip
%Include ./3d/qgs3drendererregistry.sip
%Include ./3d/qgsabstract3drenderer.sip
%Include fieldformatter/qgsrangefieldformatter.sip
%Include fieldformatter/qgsdatetimefieldformatter.sip
%Include fieldformatter/qgsfallbackfieldformatter.sip
%Include fieldformatter/qgskeyvaluefieldformatter.sip

View File

@ -0,0 +1,42 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/fieldformatter/qgsrangefieldformatter.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsRangeFieldFormatter : QgsFieldFormatter
{
%Docstring
Field formatter for a range (double) field with precision and locale
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsrangefieldformatter.h"
%End
public:
QgsRangeFieldFormatter();
%Docstring
Default constructor of field formatter for a range (double)field.
%End
virtual QString id() const;
virtual QString representValue( QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value ) const;
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/fieldformatter/qgsrangefieldformatter.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -117,6 +117,13 @@ Defines if the clear value should be the minimum or maximum values of the widget
Returns the value used when clear() is called.
.. seealso:: :py:func:`setClearValue`
%End
void setLineEditAlignment( Qt::Alignment alignment );
%Docstring
Set alignment in the embedded line edit widget
:param alignment:
%End
virtual double valueFromText( const QString &text ) const;

View File

@ -117,6 +117,13 @@ Defines if the clear value should be the minimum or maximum values of the widget
Returns the value used when clear() is called.
.. seealso:: :py:func:`setClearValue`
%End
void setLineEditAlignment( Qt::Alignment alignment );
%Docstring
Set alignment in the embedded line edit widget
:param alignment:
%End
virtual int valueFromText( const QString &text ) const;

View File

@ -473,6 +473,7 @@ SET(QGIS_CORE_SRCS
3d/qgs3drendererregistry.cpp
3d/qgsabstract3drenderer.cpp
fieldformatter/qgsrangefieldformatter.cpp
fieldformatter/qgsdatetimefieldformatter.cpp
fieldformatter/qgsfallbackfieldformatter.cpp
fieldformatter/qgskeyvaluefieldformatter.cpp
@ -1110,6 +1111,7 @@ SET(QGIS_CORE_HDRS
3d/qgs3drendererregistry.h
3d/qgsabstract3drenderer.h
fieldformatter/qgsrangefieldformatter.h
fieldformatter/qgsdatetimefieldformatter.h
fieldformatter/qgsfallbackfieldformatter.h
fieldformatter/qgskeyvaluefieldformatter.h

View File

@ -0,0 +1,86 @@
/***************************************************************************
qgsrangefieldformatter.cpp - QgsRangeFieldFormatter
---------------------
begin : 01/02/2018
copyright : (C) 2018 by Alessandro Pasotti
email : elpaso at itopen dot it
***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <QLocale>
#include "qgsrangefieldformatter.h"
#include "qgssettings.h"
#include "qgsfield.h"
#include "qgsvectorlayer.h"
QString QgsRangeFieldFormatter::id() const
{
return QStringLiteral( "Range" );
}
QString QgsRangeFieldFormatter::representValue( QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value ) const
{
Q_UNUSED( cache )
Q_UNUSED( config )
if ( value.isNull() )
{
return QgsApplication::nullRepresentation();
}
QString result;
// Prepare locale
std::function<QLocale()> f_locale = [ ]
{
QLocale locale( QgsApplication::instance()->locale() );
QLocale::NumberOptions options( locale.numberOptions() );
options |= QLocale::NumberOption::OmitGroupSeparator;
locale.setNumberOptions( options );
return locale;
};
const QgsField field = layer->fields().at( fieldIndex );
if ( field.type() == QVariant::Double &&
config.contains( QStringLiteral( "Precision" ) ) &&
value.isValid( ) )
{
bool ok;
double val( value.toDouble( &ok ) );
if ( ok )
{
int precision( config[ QStringLiteral( "Precision" ) ].toInt( &ok ) );
if ( ok )
{
// TODO: make the format configurable!
result = f_locale().toString( val, 'f', precision );
}
}
}
else if ( field.type() == QVariant::Int &&
value.isValid( ) )
{
bool ok;
double val( value.toInt( &ok ) );
if ( ok )
{
result = f_locale().toString( val );
}
}
else
{
result = value.toString();
}
return result;
}

View File

@ -0,0 +1,43 @@
/***************************************************************************
qgsrangefieldformatter.h - QgsRangeFieldFormatter
---------------------
begin : 01/02/2018
copyright : (C) 2018 by Alessandro Pasotti
email : elpaso at itopen dot it
***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSRANGEFIELDFORMATTER_H
#define QGSRANGEFIELDFORMATTER_H
#include "qgis_core.h"
#include "qgsfieldformatter.h"
/**
* \ingroup core
* Field formatter for a range (double) field with precision and locale
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsRangeFieldFormatter : public QgsFieldFormatter
{
public:
/**
* Default constructor of field formatter for a range (double)field.
*/
QgsRangeFieldFormatter() = default;
QString id() const override;
QString representValue( QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value ) const override;
};
#endif // QGSRANGEFIELDFORMATTER_H

View File

@ -22,6 +22,7 @@
#include "qgsrelationreferencefieldformatter.h"
#include "qgskeyvaluefieldformatter.h"
#include "qgslistfieldformatter.h"
#include "qgsrangefieldformatter.h"
#include "qgsfallbackfieldformatter.h"
@ -34,6 +35,7 @@ QgsFieldFormatterRegistry::QgsFieldFormatterRegistry( QObject *parent )
addFieldFormatter( new QgsKeyValueFieldFormatter() );
addFieldFormatter( new QgsListFieldFormatter() );
addFieldFormatter( new QgsDateTimeFieldFormatter() );
addFieldFormatter( new QgsRangeFieldFormatter() );
mFallbackFieldFormatter = new QgsFallbackFieldFormatter();
}

View File

@ -31,6 +31,8 @@ QgsDoubleSpinBox::QgsDoubleSpinBox( QWidget *parent )
{
mLineEdit = new QgsSpinBoxLineEdit();
// By default, group separator is off
setLocale( QLocale( QgsApplication::locale( ) ) );
setLineEdit( mLineEdit );
QSize msz = minimumSizeHint();
@ -134,6 +136,11 @@ double QgsDoubleSpinBox::clearValue() const
return mCustomClearValue;
}
void QgsDoubleSpinBox::setLineEditAlignment( Qt::Alignment alignment )
{
mLineEdit->setAlignment( alignment );
}
QString QgsDoubleSpinBox::stripped( const QString &originalText ) const
{
//adapted from QAbstractSpinBoxPrivate::stripped

View File

@ -126,6 +126,12 @@ class GUI_EXPORT QgsDoubleSpinBox : public QDoubleSpinBox
*/
double clearValue() const;
/**
* Set alignment in the embedded line edit widget
* \param alignment
*/
void setLineEditAlignment( Qt::Alignment alignment );
double valueFromText( const QString &text ) const override;
QValidator::State validate( QString &input, int &pos ) const override;
void paintEvent( QPaintEvent *e ) override;

View File

@ -47,12 +47,14 @@ QWidget *QgsRangeWidgetWrapper::createWidget( QWidget *parent )
case QVariant::Double:
{
editor = new QgsDoubleSpinBox( parent );
static_cast<QgsDoubleSpinBox *>( editor )->setLineEditAlignment( Qt::AlignRight );
break;
}
case QVariant::Int:
case QVariant::LongLong:
default:
editor = new QgsSpinBox( parent );
static_cast<QgsSpinBox *>( editor )->setLineEditAlignment( Qt::AlignRight );
break;
}
}

View File

@ -30,7 +30,6 @@ QgsSpinBox::QgsSpinBox( QWidget *parent )
: QSpinBox( parent )
{
mLineEdit = new QgsSpinBoxLineEdit();
setLineEdit( mLineEdit );
QSize msz = minimumSizeHint();
@ -133,6 +132,11 @@ int QgsSpinBox::clearValue() const
return mCustomClearValue;
}
void QgsSpinBox::setLineEditAlignment( Qt::Alignment alignment )
{
mLineEdit->setAlignment( alignment );
}
int QgsSpinBox::valueFromText( const QString &text ) const
{
if ( !mExpressionsEnabled )

View File

@ -126,6 +126,12 @@ class GUI_EXPORT QgsSpinBox : public QSpinBox
*/
int clearValue() const;
/**
* Set alignment in the embedded line edit widget
* \param alignment
*/
void setLineEditAlignment( Qt::Alignment alignment );
int valueFromText( const QString &text ) const override;
QValidator::State validate( QString &input, int &pos ) const override;

View File

@ -16,7 +16,7 @@ import qgis # NOQA
from qgis.core import (QgsFeature, QgsProject, QgsRelation, QgsVectorLayer,
QgsValueMapFieldFormatter, QgsValueRelationFieldFormatter,
QgsRelationReferenceFieldFormatter, QgsSettings)
QgsRelationReferenceFieldFormatter, QgsRangeFieldFormatter, QgsSettings)
from qgis.testing import start_app, unittest
@ -197,5 +197,62 @@ class TestQgsRelationReferenceFieldFormatter(unittest.TestCase):
QgsProject.instance().removeAllMapLayers()
class TestQgsRangeFieldFormatter(unittest.TestCase):
def test_representValue(self):
layer = QgsVectorLayer("point?field=int:integer&field=double:double",
"layer", "memory")
self.assertTrue(layer.isValid())
QgsProject.instance().addMapLayers([layer])
fieldFormatter = QgsRangeFieldFormatter()
# Precision is ignored for integers
self.assertEqual(fieldFormatter.representValue(layer, 0, {'Precision': 1}, None, '123'), '123')
self.assertEqual(fieldFormatter.representValue(layer, 0, {'Precision': 1}, None, '123000'), '123000')
self.assertEqual(fieldFormatter.representValue(layer, 0, {'Precision': 1}, None, None), 'NULL')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 1}, None, None), 'NULL')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 1}, None, '123'), '123.0')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, None), 'NULL')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '123000'), '123000.00')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '0'), '0.00')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '123'), '123.00')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '0.123'), '0.12')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '0.127'), '0.13')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '0'), '0.000')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '0.127'), '0.127')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '1.27e-1'), '0.127')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '-123'), '-123.00')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '-0.123'), '-0.12')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '-0.127'), '-0.13')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '-0.127'), '-0.127')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '-1.27e-1'), '-0.127')
QgsSettings().setValue("locale/overrideFlag", True)
QgsSettings().setValue("locale/userLocale", 'it')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, None), 'NULL')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '123000'), '123000,00')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '0'), '0,00')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '123'), '123,00')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '0.123'), '0,12')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '0.127'), '0,13')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '0'), '0,000')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '0.127'), '0,127')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '1.27e-1'), '0,127')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '-123'), '-123,00')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '-0.123'), '-0,12')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 2}, None, '-0.127'), '-0,13')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '-0.127'), '-0,127')
self.assertEqual(fieldFormatter.representValue(layer, 1, {'Precision': 3}, None, '-1.27e-1'), '-0,127')
QgsProject.instance().removeAllMapLayers()
if __name__ == '__main__':
unittest.main()