Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Some improvements to QgsDataDefined and QgsDataDefinedButton:
- enhanced methods for storing/retrieving QgsDataDefined in a
  string map
- add method to QgsDataDefinedButton to update parameters for a
  QgsDataDefined
- deprecate an unused method
- const correctness
  • Loading branch information
nyalldawson committed May 6, 2015
1 parent 254af20 commit 6ad2f9f
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 20 deletions.
29 changes: 26 additions & 3 deletions python/core/qgsdatadefined.sip
Expand Up @@ -43,6 +43,15 @@ class QgsDataDefined
*/
QgsDataDefined( const QgsDataDefined& other );

/** Creates a QgsDataDefined from a decoded QgsStringMap.
* @param map string map encoding of QgsDataDefined
* @param baseName base name for values in the string map
* @returns new QgsDataDefined if string map was successfully interpreted
* @see toMap
* @note added in QGIS 2.9
*/
static QgsDataDefined* fromMap( const QgsStringMap& map, const QString& baseName = QString() );

virtual ~QgsDataDefined();

/**Returns whether the data defined container is set to all the default
Expand Down Expand Up @@ -78,21 +87,35 @@ class QgsDataDefined
* @returns true if expression was successfully prepared
* @note added in QGIS 2.9
*/
bool prepareExpression( const QgsFields &fields );
bool prepareExpression( const QgsFields &fields = QgsFields() );

/** Returns whether the data defined object's expression is prepared
* @returns true if expression is prepared
*/
bool expressionIsPrepared() const;

QgsExpression* expression();

/** Returns the columns referenced by the QgsDataDefined
* @param layer vector layer, used for preparing the expression if required
*/
QStringList referencedColumns( QgsVectorLayer* layer );

/** Returns the columns referenced by the QgsDataDefined
* @param fields vector layer, used for preparing the expression if required
* @note added in QGIS 2.9
*/
QStringList referencedColumns( const QgsFields& fields = QgsFields() );

QString field() const;
void setField( const QString& field );

// @note not available in python bindings
//QMap< QString, QString > toMap();
/** Encodes the QgsDataDefined into a string map.
* @param baseName optional base name for values in the string map. Can be used
* to differentiate multiple QgsDataDefineds encoded in the same string map.
* @see fromMap
*/
QMap< QString, QString > toMap( const QString& baseName = QString() );

/**Returns a DOM element containing the properties of the data defined container.
* @param document DOM document
Expand Down
10 changes: 8 additions & 2 deletions python/gui/qgsdatadefinedbutton.sip
Expand Up @@ -64,15 +64,21 @@ class QgsDataDefinedButton : QToolButton

QMap< QString, QString > definedProperty() const;

/** Updates a QgsDataDefined with the current settings from the button
* @param dd QgsDataDefined to update
* @note added in QGIS 2.9
*/
void updateDataDefined( QgsDataDefined* dd ) const;

/**
* Whether the current data definition or expression is to be used
*/
bool isActive();
bool isActive() const;

/**
* Whether the current expression is to be used instead of field mapping
*/
bool useExpression();
bool useExpression() const;

/**
* The current defined expression
Expand Down
3 changes: 2 additions & 1 deletion python/gui/symbology-ng/qgssymbollayerv2widget.sip
Expand Up @@ -18,8 +18,9 @@ class QgsSymbolLayerV2Widget : QWidget
/** Get label for data defined entry.
* Implemented only for 'size' of marker symbols
* @note added in 2.1
* @deprecated no longer used
*/
virtual QString dataDefinedPropertyLabel( const QString &entryName );
virtual QString dataDefinedPropertyLabel( const QString &entryName ) /Deprecated/;

signals:
void changed();
Expand Down
54 changes: 47 additions & 7 deletions src/core/qgsdatadefined.cpp
Expand Up @@ -55,6 +55,28 @@ QgsDataDefined::QgsDataDefined( const QgsDataDefined &other )

}

QgsDataDefined* QgsDataDefined::fromMap( const QgsStringMap &map, const QString &baseName )
{
QString prefix;
if ( !baseName.isEmpty() )
{
prefix.append( QString( "%1_dd_" ).arg( baseName ) );
}

if ( !map.contains( QString( "%1expression" ).arg( prefix ) ) )
{
//requires at least the expression value
return 0;
}

bool active = ( map.value( QString( "%1active" ).arg( prefix ), "1" ) != QString( "0" ) );
QString expression = map.value( QString( "%1expression" ).arg( prefix ) );
bool useExpression = ( map.value( QString( "%1useexpr" ).arg( prefix ), "1" ) != QString( "0" ) );
QString field = map.value( QString( "%1field" ).arg( prefix ), QString() );

return new QgsDataDefined( active, useExpression, expression, field );
}

QgsDataDefined::QgsDataDefined( const QString & string )
{
QgsExpression expression( string );
Expand Down Expand Up @@ -137,6 +159,18 @@ bool QgsDataDefined::prepareExpression( const QgsFields &fields )
}

QStringList QgsDataDefined::referencedColumns( QgsVectorLayer* layer )
{
if ( layer )
{
return referencedColumns( layer->pendingFields() );
}
else
{
return referencedColumns( );
}
}

QStringList QgsDataDefined::referencedColumns( const QgsFields &fields )
{
if ( !mExprRefColumns.isEmpty() )
{
Expand All @@ -147,7 +181,7 @@ QStringList QgsDataDefined::referencedColumns( QgsVectorLayer* layer )
{
if ( !mExpression || !mExpressionPrepared )
{
prepareExpression( layer );
prepareExpression( fields );
}
}
else if ( !mField.isEmpty() )
Expand All @@ -163,13 +197,19 @@ void QgsDataDefined::insertExpressionParam( QString key, QVariant param )
mExpressionParams.insert( key, param );
}

QMap< QString, QString > QgsDataDefined::toMap()
QgsStringMap QgsDataDefined::toMap( const QString &baseName )
{
QMap< QString, QString > map;
map.insert( "active", ( mActive ? "1" : "0" ) );
map.insert( "useexpr", ( mUseExpression ? "1" : "0" ) );
map.insert( "expression", mExpressionString );
map.insert( "field", mField );
QgsStringMap map;
QString prefix;
if ( !baseName.isEmpty() )
{
prefix.append( QString( "%1_dd_" ).arg( baseName ) );
}

map.insert( QString( "%1active" ).arg( prefix ), ( mActive ? "1" : "0" ) );
map.insert( QString( "%1useexpr" ).arg( prefix ), ( mUseExpression ? "1" : "0" ) );
map.insert( QString( "%1expression" ).arg( prefix ), mExpressionString );
map.insert( QString( "%1field" ).arg( prefix ), mField );

return map;
}
Expand Down
32 changes: 28 additions & 4 deletions src/core/qgsdatadefined.h
Expand Up @@ -18,10 +18,11 @@
#include <QStringList>
#include <QDomElement>
#include <QMap>
#include "qgis.h"
#include "qgsfield.h"

class QgsExpression;
class QgsVectorLayer;
class QgsFields;

/** \ingroup core
* \class QgsDataDefined
Expand Down Expand Up @@ -65,6 +66,15 @@ class CORE_EXPORT QgsDataDefined
*/
QgsDataDefined( const QgsDataDefined& other );

/** Creates a QgsDataDefined from a decoded QgsStringMap.
* @param map string map encoding of QgsDataDefined
* @param baseName base name for values in the string map
* @returns new QgsDataDefined if string map was successfully interpreted
* @see toMap
* @note added in QGIS 2.9
*/
static QgsDataDefined* fromMap( const QgsStringMap& map, const QString& baseName = QString() );

virtual ~QgsDataDefined();

/**Returns whether the data defined container is set to all the default
Expand Down Expand Up @@ -100,21 +110,35 @@ class CORE_EXPORT QgsDataDefined
* @returns true if expression was successfully prepared
* @note added in QGIS 2.9
*/
bool prepareExpression( const QgsFields &fields );
bool prepareExpression( const QgsFields &fields = QgsFields() );

/** Returns whether the data defined object's expression is prepared
* @returns true if expression is prepared
*/
bool expressionIsPrepared() const { return mExpressionPrepared; }

QgsExpression* expression() { return mExpression; }

/** Returns the columns referenced by the QgsDataDefined
* @param layer vector layer, used for preparing the expression if required
*/
QStringList referencedColumns( QgsVectorLayer* layer );

/** Returns the columns referenced by the QgsDataDefined
* @param fields vector layer, used for preparing the expression if required
* @note added in QGIS 2.9
*/
QStringList referencedColumns( const QgsFields& fields = QgsFields() );

QString field() const { return mField; }
void setField( const QString& field ) { mField = field; }

// @note not available in python bindings
QMap< QString, QString > toMap();
/** Encodes the QgsDataDefined into a string map.
* @param baseName optional base name for values in the string map. Can be used
* to differentiate multiple QgsDataDefineds encoded in the same string map.
* @see fromMap
*/
QgsStringMap toMap( const QString& baseName = QString() );

/**Returns a DOM element containing the properties of the data defined container.
* @param document DOM document
Expand Down
11 changes: 11 additions & 0 deletions src/gui/qgsdatadefinedbutton.cpp
Expand Up @@ -193,6 +193,17 @@ void QgsDataDefinedButton::init( const QgsVectorLayer* vl,
updateGui();
}

void QgsDataDefinedButton::updateDataDefined( QgsDataDefined *dd ) const
{
if ( !dd )
return;

dd->setActive( isActive() );
dd->setUseExpression( useExpression() );
dd->setExpressionString( getExpression() );
dd->setField( getField() );
}

void QgsDataDefinedButton::mouseReleaseEvent( QMouseEvent *event )
{
// Ctrl-click to toggle activated state
Expand Down
10 changes: 8 additions & 2 deletions src/gui/qgsdatadefinedbutton.h
Expand Up @@ -89,15 +89,21 @@ class GUI_EXPORT QgsDataDefinedButton: public QToolButton

QMap< QString, QString > definedProperty() const { return mProperty; }

/** Updates a QgsDataDefined with the current settings from the button
* @param dd QgsDataDefined to update
* @note added in QGIS 2.9
*/
void updateDataDefined( QgsDataDefined* dd ) const;

/**
* Whether the current data definition or expression is to be used
*/
bool isActive() { return mProperty.value( "active" ).toInt(); }
bool isActive() const { return mProperty.value( "active" ).toInt(); }

/**
* Whether the current expression is to be used instead of field mapping
*/
bool useExpression() { return mProperty.value( "useexpr" ).toInt(); }
bool useExpression() const { return mProperty.value( "useexpr" ).toInt(); }

/**
* The current defined expression
Expand Down
3 changes: 2 additions & 1 deletion src/gui/symbology-ng/qgssymbollayerv2widget.h
Expand Up @@ -43,8 +43,9 @@ class GUI_EXPORT QgsSymbolLayerV2Widget : public QWidget
/** Get label for data defined entry.
* Implemented only for 'size' of marker symbols
* @note added in 2.1
* @deprecated no longer used
*/
virtual QString dataDefinedPropertyLabel( const QString &entryName );
Q_DECL_DEPRECATED virtual QString dataDefinedPropertyLabel( const QString &entryName );

signals:
void changed();
Expand Down
49 changes: 49 additions & 0 deletions tests/src/core/testqgsdatadefined.cpp
Expand Up @@ -39,6 +39,7 @@ class TestQgsDataDefined: public QObject
void defaultValues(); //test hasDefaultValues method
void equality(); //test equality operators
void xmlMethods(); //test saving and reading from xml
void mapMethods(); //test saving and reading from a string map

private:
};
Expand Down Expand Up @@ -200,5 +201,53 @@ void TestQgsDataDefined::xmlMethods()
QVERIFY( !dd2.setFromXmlElement( badElem ) );
}

void TestQgsDataDefined::mapMethods()
{
//test reading empty map
QgsStringMap empty;
QgsDataDefined* fromEmpty = QgsDataDefined::fromMap( empty );
QVERIFY( !fromEmpty );

//no base name
QgsDataDefined dd1;
dd1.setActive( true );
dd1.setField( QString( "field" ) );
dd1.setExpressionString( QString( "expression" ) );
dd1.setUseExpression( true );
QgsStringMap map1 = dd1.toMap();

QgsDataDefined* dd2 = QgsDataDefined::fromMap( map1 );
QCOMPARE( *dd2, dd1 );
delete dd2;

//base name
QgsDataDefined dd3;
dd3.setActive( false );
dd3.setField( QString( "field2" ) );
dd3.setExpressionString( QString( "expression2" ) );
dd3.setUseExpression( false );
QgsStringMap map2 = dd3.toMap( QString( "basename" ) );

QgsDataDefined* dd4 = QgsDataDefined::fromMap( map2, QString( "basename" ) );
QCOMPARE( *dd4, dd3 );
delete dd4;

// read with invalid basename
dd4 = QgsDataDefined::fromMap( map2, QString( "xx" ) );
QVERIFY( !dd4 );

//test read map with only an expression
QgsStringMap expMapOnly;
expMapOnly.insert( QString( "expression" ), QString( "test_exp" ) );

dd4 = QgsDataDefined::fromMap( expMapOnly );
QVERIFY( dd4 );
QCOMPARE( dd4->expressionString(), QString( "test_exp" ) );
QVERIFY( dd4->isActive() );
QVERIFY( dd4->useExpression() );

delete dd4;
}

QTEST_MAIN( TestQgsDataDefined )
#include "testqgsdatadefined.moc"

0 comments on commit 6ad2f9f

Please sign in to comment.