Skip to content

Commit

Permalink
Introduce support for active/inactive rules, else rules, scale-based …
Browse files Browse the repository at this point in the history
…rules

This code has been funded by Tuscany Region (Italy) - SITA (CIG: 63526840AE) and commissioned to Gis3W s.a.s.
  • Loading branch information
wonder-sk committed Sep 24, 2015
1 parent 7bb70aa commit b088220
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 21 deletions.
10 changes: 4 additions & 6 deletions src/app/qgsrulebasedlabelingwidget.cpp
Expand Up @@ -255,13 +255,12 @@ QVariant QgsRuleBasedLabelingModel::data( const QModelIndex& index, int role ) c
default: return QVariant();
}
}
/* TODO
else if ( role == Qt::CheckStateRole )
{
if ( index.column() != 0 )
return QVariant();
return rule->checkState() ? Qt::Checked : Qt::Unchecked;
}*/
return rule->active() ? Qt::Checked : Qt::Unchecked;
}
else
return QVariant();
}
Expand Down Expand Up @@ -339,13 +338,12 @@ bool QgsRuleBasedLabelingModel::setData( const QModelIndex& index, const QVarian

QgsRuleBasedLabeling::Rule* rule = ruleForIndex( index );

/* TODO
if ( role == Qt::CheckStateRole )
{
rule->setCheckState( value.toInt() == Qt::Checked );
rule->setActive( value.toInt() == Qt::Checked );
emit dataChanged( index, index );
return true;
}*/
}

if ( role != Qt::EditRole )
return false;
Expand Down
80 changes: 66 additions & 14 deletions src/core/qgsrulebasedlabeling.cpp
Expand Up @@ -47,7 +47,7 @@ QgsRuleBasedLabeling::Rule::Rule( QgsPalLayerSettings* settings, int scaleMinDen
, mScaleMinDenom( scaleMinDenom ), mScaleMaxDenom( scaleMaxDenom )
, mFilterExp( filterExp ), mLabel( label ), mDescription( description )
, mElseRule( elseRule )
//, mIsActive( true )
, mIsActive( true )
, mFilter( 0 )
{
initFilter();
Expand Down Expand Up @@ -88,34 +88,44 @@ void QgsRuleBasedLabeling::Rule::initFilter()
}
}

void QgsRuleBasedLabeling::Rule::updateElseRules()
{
mElseRules.clear();
Q_FOREACH ( Rule* rule, mChildren )
{
if ( rule->isElse() )
mElseRules << rule;
}
}


void QgsRuleBasedLabeling::Rule::appendChild( QgsRuleBasedLabeling::Rule* rule )
{
mChildren.append( rule );
rule->mParent = this;
// TODO updateElseRules();
updateElseRules();
}

void QgsRuleBasedLabeling::Rule::insertChild( int i, QgsRuleBasedLabeling::Rule* rule )
{
mChildren.insert( i, rule );
rule->mParent = this;
// TODO updateElseRules();
updateElseRules();
}

void QgsRuleBasedLabeling::Rule::removeChildAt( int i )
{
Rule* rule = mChildren[i];
mChildren.removeAt( i );
delete rule;
// TODO updateElseRules();
updateElseRules();
}

QgsRuleBasedLabeling::Rule*QgsRuleBasedLabeling::Rule::clone() const
{
QgsPalLayerSettings* s = mSettings ? new QgsPalLayerSettings( *mSettings ) : 0;
Rule* newrule = new Rule( s, mScaleMinDenom, mScaleMaxDenom, mFilterExp, mLabel, mDescription );
// TODO newrule->setCheckState( mIsActive );
newrule->setActive( mIsActive );
// clone children
Q_FOREACH ( Rule* rule, mChildren )
newrule->appendChild( rule->clone() );
Expand Down Expand Up @@ -143,7 +153,7 @@ QgsRuleBasedLabeling::Rule*QgsRuleBasedLabeling::Rule::create( const QDomElement
//if ( !ruleKey.isEmpty() )
// rule->mRuleKey = ruleKey;

//rule->setCheckState( ruleElem.attribute( "checkstate", "1" ).toInt() );
rule->setActive( ruleElem.attribute( "active", "1" ).toInt() );

QDomElement childRuleElem = ruleElem.firstChildElement( "rule" );
while ( !childRuleElem.isNull() )
Expand Down Expand Up @@ -181,8 +191,8 @@ QDomElement QgsRuleBasedLabeling::Rule::save( QDomDocument& doc ) const
ruleElem.setAttribute( "label", mLabel );
if ( !mDescription.isEmpty() )
ruleElem.setAttribute( "description", mDescription );
//if ( !mIsActive )
// ruleElem.setAttribute( "checkstate", 0 );
if ( !mIsActive )
ruleElem.setAttribute( "active", 0 );
//ruleElem.setAttribute( "key", mRuleKey );

for ( RuleList::const_iterator it = mChildren.constBegin(); it != mChildren.constEnd(); ++it )
Expand Down Expand Up @@ -231,22 +241,51 @@ void QgsRuleBasedLabeling::Rule::prepare( const QgsRenderContext& context, QStri
}
}

void QgsRuleBasedLabeling::Rule::registerFeature( QgsFeature& feature, const QgsRenderContext& context, QgsRuleBasedLabeling::RuleToProviderMap& subProviders )
QgsRuleBasedLabeling::Rule::RegisterResult QgsRuleBasedLabeling::Rule::registerFeature( QgsFeature& feature, const QgsRenderContext& context, QgsRuleBasedLabeling::RuleToProviderMap& subProviders )
{
bool isOK = isFilterOK( feature, const_cast<QgsRenderContext&>( context ) ); // TODO: remove const_cast
if ( !isFilterOK( feature, const_cast<QgsRenderContext&>( context ) )
|| !isScaleOK( context.rendererScale() ) )
return Filtered;

if ( !isOK )
return;
bool registered = false;

// do we have active subprovider for the rule?
if ( subProviders.contains( this ) )
if ( subProviders.contains( this ) && mIsActive )
{
subProviders[this]->registerFeature( feature, context );
registered = true;
}

bool willRegisterSomething = false;

// call recursively
Q_FOREACH ( Rule* rule, mChildren )
{
rule->registerFeature( feature, context, subProviders );
// Don't process else rules yet
if ( !rule->isElse() )
{
RegisterResult res = rule->registerFeature( feature, context, subProviders );
// consider inactive items as "registered" so the else rule will ignore them
willRegisterSomething |= ( res == Registered || res == Inactive );
registered |= willRegisterSomething;
}
}

// If none of the rules passed then we jump into the else rules and process them.
if ( !willRegisterSomething )
{
Q_FOREACH ( Rule* rule, mElseRules )
{
registered |= rule->registerFeature( feature, context, subProviders ) != Filtered;
}
}

if ( !mIsActive )
return Inactive;
else if ( registered )
return Registered;
else
return Filtered;
}

bool QgsRuleBasedLabeling::Rule::isFilterOK( QgsFeature& f, QgsRenderContext& context ) const
Expand All @@ -259,6 +298,19 @@ bool QgsRuleBasedLabeling::Rule::isFilterOK( QgsFeature& f, QgsRenderContext& co
return res.toInt() != 0;
}

bool QgsRuleBasedLabeling::Rule::isScaleOK( double scale ) const
{
if ( scale == 0 ) // so that we can count features in classes without scale context
return true;
if ( mScaleMinDenom == 0 && mScaleMaxDenom == 0 )
return true;
if ( mScaleMinDenom != 0 && mScaleMinDenom > scale )
return false;
if ( mScaleMaxDenom != 0 && mScaleMaxDenom < scale )
return false;
return true;
}

////////////////////

QgsRuleBasedLabeling::QgsRuleBasedLabeling( QgsRuleBasedLabeling::Rule* root )
Expand Down
35 changes: 34 additions & 1 deletion src/core/qgsrulebasedlabeling.h
Expand Up @@ -28,6 +28,14 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
Rule( QgsPalLayerSettings* settings, int scaleMinDenom = 0, int scaleMaxDenom = 0, const QString& filterExp = QString(), const QString& label = QString(), const QString& description = QString(), bool elseRule = false );
~Rule();

//! The result of registering a rule
enum RegisterResult
{
Filtered = 0, //!< The rule does not apply
Inactive, //!< The rule is inactive
Registered //!< Something was registered
};

QgsPalLayerSettings* settings() const { return mSettings; }
QString label() const { return mLabel; }
bool dependsOnScale() const { return mScaleMinDenom != 0 || mScaleMaxDenom != 0; }
Expand All @@ -44,6 +52,12 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
* @return Description
*/
QString description() const { return mDescription; }
/**
* Returns if this rule is active
*
* @return True if the rule is active
*/
bool active() const { return mIsActive; }
/**
* Check if this rule is an ELSE rule
*
Expand Down Expand Up @@ -81,6 +95,11 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
* @param description Description
*/
void setDescription( QString description ) { mDescription = description; }
/**
* Sets if this rule is active
* @param state Determines if the rule should be activated or deactivated
*/
void setActive( bool state ) { mIsActive = state; }
/**
* Sets if this rule is an ELSE rule
*
Expand Down Expand Up @@ -149,7 +168,7 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
void prepare( const QgsRenderContext& context, QStringList& attributeNames, RuleToProviderMap& subProviders );

//! register individual features
void registerFeature( QgsFeature& feature, const QgsRenderContext& context, RuleToProviderMap& subProviders );
RegisterResult registerFeature( QgsFeature& feature, const QgsRenderContext& context, RuleToProviderMap& subProviders );

protected:
/**
Expand All @@ -160,16 +179,30 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
* @return True if the feature shall be rendered
*/
bool isFilterOK( QgsFeature& f, QgsRenderContext& context ) const;
/**
* Check if this rule applies for a given scale
* @param scale The scale to check. If set to 0, it will always return true.
*
* @return If the rule will be evaluated at this scale
*/
bool isScaleOK( double scale ) const;

void initFilter();

/**
* Check which child rules are else rules and update the internal list of else rules
*/
void updateElseRules();

protected:
Rule* mParent; // parent rule (NULL only for root rule)
QgsPalLayerSettings* mSettings;
int mScaleMinDenom, mScaleMaxDenom;
QString mFilterExp, mLabel, mDescription;
bool mElseRule;
RuleList mChildren;
RuleList mElseRules;
bool mIsActive; // whether it is enabled or not

// temporary
QgsExpression* mFilter;
Expand Down

0 comments on commit b088220

Please sign in to comment.