From fb7901c9d94d3af0222cb2e54ba7352527e1f9c1 Mon Sep 17 00:00:00 2001 From: Martin Dobias Date: Wed, 6 Aug 2014 16:19:15 +0700 Subject: [PATCH] Added support for check states to rule-based renderer --- .../symbology-ng/qgsrulebasedrendererv2.cpp | 68 ++++++++++++++++++- .../symbology-ng/qgsrulebasedrendererv2.h | 34 ++++++++++ .../qgsrulebasedrendererv2widget.cpp | 22 +++++- 3 files changed, 120 insertions(+), 4 deletions(-) diff --git a/src/core/symbology-ng/qgsrulebasedrendererv2.cpp b/src/core/symbology-ng/qgsrulebasedrendererv2.cpp index 59eb6914ee07..0fc9cf7c263f 100644 --- a/src/core/symbology-ng/qgsrulebasedrendererv2.cpp +++ b/src/core/symbology-ng/qgsrulebasedrendererv2.cpp @@ -26,15 +26,18 @@ #include #include - +#include QgsRuleBasedRendererV2::Rule::Rule( QgsSymbolV2* symbol, int scaleMinDenom, int scaleMaxDenom, QString filterExp, QString label, QString description , bool elseRule ) : mParent( NULL ), mSymbol( symbol ) , mScaleMinDenom( scaleMinDenom ), mScaleMaxDenom( scaleMaxDenom ) , mFilterExp( filterExp ), mLabel( label ), mDescription( description ) - , mElseRule( elseRule ), mFilter( NULL ) + , mElseRule( elseRule ) + , mCheckState( true ) + , mFilter( NULL ) { + mRuleKey = QUuid::createUuid().toString(); initFilter(); } @@ -108,6 +111,22 @@ QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::takeChildAt( int i ) // updateElseRules(); } +QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::findRuleByKey( QString key ) +{ + // we could use a hash / map for search if this will be slow... + + if ( key == mRuleKey ) + return this; + + foreach ( Rule* rule, mChildren ) + { + Rule* r = rule->findRuleByKey( key ); + if ( r ) + return r; + } + return 0; +} + void QgsRuleBasedRendererV2::Rule::updateElseRules() { mElseRules.clear(); @@ -192,6 +211,24 @@ QgsLegendSymbolList QgsRuleBasedRendererV2::Rule::legendSymbolItems( double scal return lst; } +QgsLegendSymbolListV2 QgsRuleBasedRendererV2::Rule::legendSymbolItemsV2() const +{ + QgsLegendSymbolListV2 lst; + if ( mSymbol ) + { + lst << QgsLegendSymbolItemV2( mSymbol->clone(), mLabel, mRuleKey ); + lst.last().scaleDenomMin = mScaleMinDenom; + lst.last().scaleDenomMax = mScaleMaxDenom; + } + + for ( RuleList::const_iterator it = mChildren.constBegin(); it != mChildren.constEnd(); ++it ) + { + Rule* rule = *it; + lst << rule->legendSymbolItemsV2(); + } + return lst; +} + bool QgsRuleBasedRendererV2::Rule::isFilterOK( QgsFeature& f ) const { @@ -219,6 +256,7 @@ QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::clone() const { QgsSymbolV2* sym = mSymbol ? mSymbol->clone() : NULL; Rule* newrule = new Rule( sym, mScaleMinDenom, mScaleMaxDenom, mFilterExp, mLabel, mDescription ); + newrule->setCheckState( mCheckState ); // clone children foreach ( Rule* rule, mChildren ) newrule->appendChild( rule->clone() ); @@ -349,6 +387,9 @@ bool QgsRuleBasedRendererV2::Rule::startRender( QgsRenderContext& context, const { mActiveChildren.clear(); + if ( ! mCheckState ) + return false; + // filter out rules which are not compatible with this scale if ( !isScaleOK( context.rendererScale() ) ) return false; @@ -847,11 +888,34 @@ QgsLegendSymbologyList QgsRuleBasedRendererV2::legendSymbologyItems( QSize iconS return lst; } +bool QgsRuleBasedRendererV2::legendSymbolItemsCheckable() const +{ + return true; +} + +bool QgsRuleBasedRendererV2::legendSymbolItemChecked( QString key ) +{ + Rule* rule = mRootRule->findRuleByKey( key ); + return rule ? rule->checkState() : true; +} + +void QgsRuleBasedRendererV2::checkLegendSymbolItem( QString key, bool state ) +{ + Rule* rule = mRootRule->findRuleByKey( key ); + if ( rule ) + rule->setCheckState( state ); +} + QgsLegendSymbolList QgsRuleBasedRendererV2::legendSymbolItems( double scaleDenominator, QString rule ) { return mRootRule->legendSymbolItems( scaleDenominator, rule ); } +QgsLegendSymbolListV2 QgsRuleBasedRendererV2::legendSymbolItemsV2() const +{ + return mRootRule->legendSymbolItemsV2(); +} + QgsFeatureRendererV2* QgsRuleBasedRendererV2::create( QDomElement& element ) { diff --git a/src/core/symbology-ng/qgsrulebasedrendererv2.h b/src/core/symbology-ng/qgsrulebasedrendererv2.h index 2c6b892b092b..a587a9acaaa2 100644 --- a/src/core/symbology-ng/qgsrulebasedrendererv2.h +++ b/src/core/symbology-ng/qgsrulebasedrendererv2.h @@ -94,6 +94,8 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2 QgsSymbolV2List symbols(); //! @note not available in python bindings QgsLegendSymbolList legendSymbolItems( double scaleDenominator = -1, QString rule = "" ); + //! @note added in 2.6 + QgsLegendSymbolListV2 legendSymbolItemsV2() const; bool isFilterOK( QgsFeature& f ) const; bool isScaleOK( double scale ) const; @@ -105,6 +107,12 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2 QgsExpression* filter() const { return mFilter; } QString filterExpression() const { return mFilterExp; } QString description() const { return mDescription; } + //! @note added in 2.6 + bool checkState() const { return mCheckState; } + + //! Unique rule identifier (for identification of rule within renderer) + //! @note added in 2.6 + QString ruleKey() const { return mRuleKey; } //! set a new symbol (or NULL). Deletes old symbol. void setSymbol( QgsSymbolV2* sym ); @@ -113,6 +121,8 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2 void setScaleMaxDenom( int scaleMaxDenom ) { mScaleMaxDenom = scaleMaxDenom; } void setFilterExpression( QString filterExp ) { mFilterExp = filterExp; initFilter(); } void setDescription( QString description ) { mDescription = description; } + //! @note added in 2.6 + void setCheckState( bool state ) { mCheckState = state; } //! clone this rule, return new instance Rule* clone() const; @@ -164,6 +174,10 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2 //! take child rule out, set parent as null Rule* takeChildAt( int i ); + //! Try to find a rule given its unique key + //! @note added in 2.6 + Rule* findRuleByKey( QString key ); + void updateElseRules(); void setIsElse( bool iselse ) { mElseRule = iselse; } @@ -179,6 +193,9 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2 bool mElseRule; RuleList mChildren; RuleList mElseRules; + bool mCheckState; // whether it is enabled or not + + QString mRuleKey; // string used for unique identification of rule within renderer // temporary QgsExpression* mFilter; @@ -223,11 +240,28 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2 //! return a list of symbology items for the legend virtual QgsLegendSymbologyList legendSymbologyItems( QSize iconSize ); + //! items of symbology items in legend should be checkable + //! @note added in 2.5 + virtual bool legendSymbolItemsCheckable() const; + + //! items of symbology items in legend is checked + //! @note added in 2.5 + virtual bool legendSymbolItemChecked( QString key ); + + //! item in symbology was checked + //! @note added in 2.5 + virtual void checkLegendSymbolItem( QString key, bool state = true ); + //! return a list of item text / symbol //! @note: this method was added in version 1.5 //! @note not available in python bindings virtual QgsLegendSymbolList legendSymbolItems( double scaleDenominator = -1, QString rule = "" ); + //! Return a list of symbology items for the legend. Better choice than legendSymbolItems(). + //! Default fallback implementation just uses legendSymbolItems() implementation + //! @node added in 2.6 + virtual QgsLegendSymbolListV2 legendSymbolItemsV2() const; + //! for debugging virtual QString dump() const; diff --git a/src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp b/src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp index 3d7ee2186c01..04d3f4834deb 100644 --- a/src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp +++ b/src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp @@ -704,8 +704,10 @@ Qt::ItemFlags QgsRuleBasedRendererV2Model::flags( const QModelIndex &index ) con // allow drop only at first column Qt::ItemFlag drop = ( index.column() == 0 ? Qt::ItemIsDropEnabled : Qt::NoItemFlags ); + Qt::ItemFlag checkable = ( index.column() == 0 ? Qt::ItemIsUserCheckable : Qt::NoItemFlags ); + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | - Qt::ItemIsEditable | + Qt::ItemIsEditable | checkable | Qt::ItemIsDragEnabled | drop; } @@ -797,6 +799,12 @@ QVariant QgsRuleBasedRendererV2Model::data( const QModelIndex &index, int role ) default: return QVariant(); } } + else if ( role == Qt::CheckStateRole ) + { + if ( index.column() != 0 ) + return QVariant(); + return rule->checkState() ? Qt::Checked : Qt::Unchecked; + } else return QVariant(); } @@ -868,11 +876,21 @@ QModelIndex QgsRuleBasedRendererV2Model::parent( const QModelIndex &index ) cons bool QgsRuleBasedRendererV2Model::setData( const QModelIndex & index, const QVariant & value, int role ) { - if ( !index.isValid() || role != Qt::EditRole ) + if ( !index.isValid() ) return false; QgsRuleBasedRendererV2::Rule* rule = ruleForIndex( index ); + if ( role == Qt::CheckStateRole ) + { + rule->setCheckState( value.toInt() == Qt::Checked ); + emit dataChanged( index, index ); + return true; + } + + if ( role != Qt::EditRole ) + return false; + switch ( index.column() ) { case 0: // label