Allow rules to have children

This commit is contained in:
Martin Dobias 2011-11-30 01:14:12 -03:00
parent 54c65ede0f
commit e55341658d
5 changed files with 490 additions and 341 deletions

View File

@ -390,6 +390,8 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2
public:
//typedef QList<QgsRuleBasedRendererV2::Rule*> RuleList;
/**
This class keeps data about a rules for rule-based renderer.
A rule consists of a symbol, filter expression and range of scales.
@ -403,10 +405,10 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2
public:
//! Constructor takes ownership of the symbol
Rule( QgsSymbolV2* symbol /Transfer/, int scaleMinDenom = 0, int scaleMaxDenom = 0, QString filterExp = QString() );
Rule( const QgsRuleBasedRendererV2::Rule& other );
//Rule( const QgsRuleBasedRendererV2::Rule& other );
~Rule();
QString dump() const;
QStringList needsFields() const;
//QStringList needsFields() const;
bool isFilterOK( QgsFeature& f ) const;
bool isScaleOK( double scale ) const;
@ -429,7 +431,7 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2
static QgsFeatureRendererV2* create( QDomElement& element ) /Factory/;
//! Constructor. Takes ownership of the defult symbol.
QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol /Transfer/ );
QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol /Transfer/ = NULL );
//! return symbol for current feature. Should not be used individually: there could be more symbols for a feature
virtual QgsSymbolV2* symbolForFeature( QgsFeature& feature );
@ -457,24 +459,24 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2
//! return the total number of rules
int ruleCount();
//! get reference to rule at index (valid indexes: 0...count-1)
QgsRuleBasedRendererV2::Rule& ruleAt( int index );
QgsRuleBasedRendererV2::Rule* ruleAt( int index );
//! add rule to the end of the list of rules
void addRule( const QgsRuleBasedRendererV2::Rule& rule );
void addRule( QgsRuleBasedRendererV2::Rule* rule );
//! insert rule to a specific position of the list of rules
void insertRule( int index, const QgsRuleBasedRendererV2::Rule& rule );
void insertRule( int index, QgsRuleBasedRendererV2::Rule* rule );
//! modify the rule at a specific position of the list of rules
void updateRuleAt( int index, const QgsRuleBasedRendererV2::Rule& rule );
void updateRuleAt( int index, QgsRuleBasedRendererV2::Rule* rule );
//! remove the rule at the specified index
void removeRuleAt( int index );
//////
//! take a rule and create a list of new rules based on the categories from categorized symbol renderer
static QList<QgsRuleBasedRendererV2::Rule> refineRuleCategories( QgsRuleBasedRendererV2::Rule& initialRule, QgsCategorizedSymbolRendererV2* r );
//static QgsRuleBasedRendererV2::RuleList refineRuleCategories( QgsRuleBasedRendererV2::Rule* initialRule, QgsCategorizedSymbolRendererV2* r );
//! take a rule and create a list of new rules based on the ranges from graduated symbol renderer
static QList<QgsRuleBasedRendererV2::Rule> refineRuleRanges( QgsRuleBasedRendererV2::Rule& initialRule, QgsGraduatedSymbolRendererV2* r );
//static QgsRuleBasedRendererV2::RuleList refineRuleRanges( QgsRuleBasedRendererV2::Rule* initialRule, QgsGraduatedSymbolRendererV2* r );
//! take a rule and create a list of new rules with intervals of scales given by the passed scale denominators
static QList<QgsRuleBasedRendererV2::Rule> refineRuleScales( QgsRuleBasedRendererV2::Rule& initialRule, QList<int> scales );
//static QgsRuleBasedRendererV2::RuleList refineRuleScales( QgsRuleBasedRendererV2::Rule* initialRule, QList<int> scales );
};

View File

@ -37,12 +37,6 @@ QgsRuleBasedRendererV2::Rule::Rule( QgsSymbolV2* symbol, int scaleMinDenom, int
initFilter();
}
QgsRuleBasedRendererV2::Rule::Rule( const QgsRuleBasedRendererV2::Rule& other )
: mSymbol( NULL ), mFilter( NULL )
{
*this = other;
}
QgsRuleBasedRendererV2::Rule::~Rule()
{
delete mSymbol;
@ -64,20 +58,67 @@ void QgsRuleBasedRendererV2::Rule::initFilter()
QString QgsRuleBasedRendererV2::Rule::dump() const
{
return QString( "RULE %1 - scale [%2,%3] - filter %4 - symbol %5\n" )
.arg( mLabel ).arg( mScaleMinDenom ).arg( mScaleMaxDenom )
.arg( mFilterExp ).arg( mSymbol->dump() );
QString symbolDump = ( mSymbol ? mSymbol->dump() : QString( "[]" ) );
QString msg = QString( "RULE %1 - scale [%2,%3] - filter %4 - symbol %5\n" )
.arg( mLabel ).arg( mScaleMinDenom ).arg( mScaleMaxDenom )
.arg( mFilterExp ).arg( symbolDump );
QStringList lst;
foreach( Rule* rule, mChildren )
{
lst.append( "- " + rule->dump() );
}
msg += lst.join( "\n" );
return msg;
}
QStringList QgsRuleBasedRendererV2::Rule::needsFields() const
QSet<QString> QgsRuleBasedRendererV2::Rule::usedAttributes()
{
if ( ! mFilter )
return QStringList();
// attributes needed by this rule
QSet<QString> attrs;
if ( mFilter )
attrs.unite( mFilter->referencedColumns().toSet() );
if ( mSymbol )
attrs.unite( mSymbol->usedAttributes() );
return mFilter->referencedColumns();
// attributes needed by child rules
for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
{
Rule* rule = *it;
attrs.unite( rule->usedAttributes() );
}
return attrs;
}
QgsSymbolV2List QgsRuleBasedRendererV2::Rule::symbols()
{
QgsSymbolV2List lst;
if ( mSymbol )
lst.append( mSymbol );
for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
{
Rule* rule = *it;
lst += rule->symbols();
}
return lst;
}
QgsLegendSymbolList QgsRuleBasedRendererV2::Rule::legendSymbolItems()
{
QgsLegendSymbolList lst;
if ( mSymbol )
lst << qMakePair( mLabel, mSymbol );
for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
{
Rule* rule = *it;
lst << rule->legendSymbolItems();
}
return lst;
}
bool QgsRuleBasedRendererV2::Rule::isFilterOK( QgsFeature& f ) const
{
if ( ! mFilter )
@ -98,30 +139,214 @@ bool QgsRuleBasedRendererV2::Rule::isScaleOK( double scale ) const
return true;
}
QgsRuleBasedRendererV2::Rule& QgsRuleBasedRendererV2::Rule::operator=( const QgsRuleBasedRendererV2::Rule & other )
QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::clone() const
{
if ( this != &other )
QgsSymbolV2* sym = mSymbol ? mSymbol->clone() : NULL;
Rule* newrule = new Rule( sym, mScaleMinDenom, mScaleMaxDenom, mFilterExp, mLabel, mDescription );
// clone children
foreach( Rule* rule, mChildren )
{
delete mSymbol;
mSymbol = other.mSymbol->clone();
mScaleMinDenom = other.mScaleMinDenom;
mScaleMaxDenom = other.mScaleMaxDenom;
mFilterExp = other.mFilterExp;
mLabel = other.mLabel;
mDescription = other.mDescription;
initFilter();
newrule->mChildren.append( rule->clone() );
}
return *this;
return newrule;
}
QDomElement QgsRuleBasedRendererV2::Rule::save( QDomDocument& doc, QgsSymbolV2Map& symbolMap )
{
QDomElement ruleElem = doc.createElement( "rule" );
if ( mSymbol )
{
int symbolIndex = symbolMap.size();
symbolMap[QString::number( symbolIndex )] = mSymbol;
ruleElem.setAttribute( "symbol", symbolIndex );
}
if ( !mFilterExp.isEmpty() )
ruleElem.setAttribute( "filter", mFilterExp );
if ( mScaleMinDenom != 0 )
ruleElem.setAttribute( "scalemindenom", mScaleMinDenom );
if ( mScaleMaxDenom != 0 )
ruleElem.setAttribute( "scalemaxdenom", mScaleMaxDenom );
if ( !mLabel.isEmpty() )
ruleElem.setAttribute( "label", mLabel );
if ( !mDescription.isEmpty() )
ruleElem.setAttribute( "description", mDescription );
for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
{
Rule* rule = *it;
ruleElem.appendChild( rule->save( doc, symbolMap ) );
}
return ruleElem;
}
bool QgsRuleBasedRendererV2::Rule::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
{
mActiveChildren.clear();
// filter out rules which are not compatible with this scale
if ( !isScaleOK( context.rendererScale() ) )
return false;
// init this rule
if ( mFilter )
mFilter->prepare( vlayer->pendingFields() );
if ( mSymbol )
mSymbol->startRender( context, vlayer );
// init children
// build temporary list of active rules (usable with this scale)
for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
{
Rule* rule = *it;
if ( rule->startRender( context, vlayer ) )
{
// only add those which are active with current scale
mActiveChildren.append( rule );
}
}
return true;
}
QSet<int> QgsRuleBasedRendererV2::Rule::collectZLevels()
{
QSet<int> symbolZLevelsSet;
// process this rule
if ( mSymbol )
{
// find out which Z-levels are used
for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
{
symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
}
}
// process children
QList<Rule*>::iterator it;
for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
{
Rule* rule = *it;
symbolZLevelsSet.unite( rule->collectZLevels() );
}
return symbolZLevelsSet;
}
void QgsRuleBasedRendererV2::Rule::setNormZLevels( const QMap<int, int>& zLevelsToNormLevels )
{
if ( mSymbol )
{
for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
{
int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
mSymbolNormZLevels.append( normLevel );
}
}
// prepare list of normalized levels for each rule
for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
{
Rule* rule = *it;
rule->setNormZLevels( zLevelsToNormLevels );
}
}
void QgsRuleBasedRendererV2::Rule::renderFeature( QgsFeature* featPtr, QgsRenderContext& context, QgsRuleBasedRendererV2::RenderQueue& renderQueue )
{
if ( isFilterOK( *featPtr ) )
{
// create job for this feature and this symbol, add to list of jobs
if ( mSymbol )
{
// add job to the queue: each symbol's zLevel must be added
foreach( int normZLevel, mSymbolNormZLevels )
{
//QgsDebugMsg(QString("add job at level %1").arg(normZLevel));
renderQueue[normZLevel].jobs.append( new RenderJob( featPtr, mSymbol ) );
}
}
// process children
for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
{
Rule* rule = *it;
rule->renderFeature( featPtr, context, renderQueue );
}
}
}
void QgsRuleBasedRendererV2::Rule::stopRender( QgsRenderContext& context )
{
if ( mSymbol )
mSymbol->stopRender( context );
for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
{
Rule* rule = *it;
rule->stopRender( context );
}
mActiveChildren.clear();
mSymbolNormZLevels.clear();
}
QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::create( QDomElement& ruleElem, QgsSymbolV2Map& symbolMap )
{
QString symbolIdx = ruleElem.attribute( "symbol" );
QgsSymbolV2* symbol = NULL;
if ( !symbolIdx.isEmpty() )
{
if ( symbolMap.contains( symbolIdx ) )
{
symbol = symbolMap.take( symbolIdx );
}
else
{
QgsDebugMsg( "symbol for rule " + symbolIdx + " not found!" );
}
}
QString filterExp = ruleElem.attribute( "filter" );
QString label = ruleElem.attribute( "label" );
QString description = ruleElem.attribute( "description" );
int scaleMinDenom = ruleElem.attribute( "scalemindenom", "0" ).toInt();
int scaleMaxDenom = ruleElem.attribute( "scalemaxdenom", "0" ).toInt();
Rule* rule = new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
QDomElement childRuleElem = ruleElem.firstChildElement( "rule" );
while ( !childRuleElem.isNull() )
{
Rule* childRule = create( childRuleElem, symbolMap );
if ( childRule )
rule->mChildren.append( childRule );
else
QgsDebugMsg( "failed to init a child rule!" );
childRuleElem = childRuleElem.nextSiblingElement( "rule" );
}
return rule;
}
/////////////////////
QgsRuleBasedRendererV2::QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol )
: QgsFeatureRendererV2( "RuleRenderer" ), mDefaultSymbol( defaultSymbol ), mCurrentSymbol( 0 )
: QgsFeatureRendererV2( "RuleRenderer" )
{
// add the default rule
mRules << Rule( defaultSymbol->clone() );
mRootRule = new Rule( NULL );
if ( defaultSymbol )
{
// add the default rule
mRootRule->children().append( new Rule( defaultSymbol ) );
}
}
QgsRuleBasedRendererV2::~QgsRuleBasedRendererV2()
{
delete mRootRule;
}
@ -140,100 +365,37 @@ void QgsRuleBasedRendererV2::renderFeature( QgsFeature& feature,
// TODO: selected features, vertex markers
// check each active rule
QgsFeature* featPtr = NULL;
for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
if ( !featPtr )
{
Rule* rule = *it;
// if matching: add rendering job to queue
if ( rule->isFilterOK( feature ) )
{
//QgsDebugMsg(QString("matching fid %1").arg(feature.id()));
// make a copy of the feature if not yet exists
if ( !featPtr )
{
featPtr = new QgsFeature( feature );
mCurrentFeatures.append( featPtr );
}
// create job for this feature and this symbol, add to list of jobs
//RenderJob* job = new RenderJob( featPtr, rule->symbol() );
//mRenderJobs.append( job );
// add job to the queue: each symbol's zLevel must be added
foreach( int normZLevel, rule->mSymbolNormZLevels )
{
//QgsDebugMsg(QString("add job at level %1").arg(normZLevel));
mRenderQueue.levels[normZLevel].jobs.append( new RenderJob( featPtr, rule->symbol() ) );
}
}
featPtr = new QgsFeature( feature );
mCurrentFeatures.append( featPtr );
}
// check each active rule
mRootRule->renderFeature( featPtr, context, mRenderQueue );
}
void QgsRuleBasedRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
{
double currentScale = context.rendererScale();
// filter out rules which are not compatible with this scale
// prepare active children
mRootRule->startRender( context, vlayer );
// build temporary list of active rules (usable with this scale)
mCurrentRules.clear();
for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it )
{
Rule& rule = *it;
if ( rule.isScaleOK( currentScale ) )
mCurrentRules.append( &rule );
}
QgsFieldMap pendingFields = vlayer->pendingFields();
QSet<int> symbolZLevelsSet;
QList<Rule*>::iterator it;
for ( it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
{
Rule* rule = *it;
QgsExpression* exp = rule->filter();
if ( exp )
exp->prepare( pendingFields );
// prepare symbol
QgsSymbolV2* s = rule->symbol();
s->startRender( context, vlayer );
QgsDebugMsg( "rule " + rule->dump() );
// find out which Z-levels are used
for ( int i = 0; i < s->symbolLayerCount(); i++ )
{
symbolZLevelsSet.insert( s->symbolLayer( i )->renderingPass() );
rule->mSymbolNormZLevels.clear();
}
}
QSet<int> symbolZLevelsSet = mRootRule->collectZLevels();
// create mapping from unnormalized levels [unlimited range] to normalized levels [0..N-1]
// and prepare rendering queue
QMap<int, int> zLevelsToNormLevels;
int maxNormLevel = -1;
mRenderQueue.levels.clear();
foreach( int zLevel, symbolZLevelsSet.toList() )
{
zLevelsToNormLevels[zLevel] = ++maxNormLevel;
mRenderQueue.levels.append( RenderLevel( zLevel ) );
mRenderQueue.append( RenderLevel( zLevel ) );
QgsDebugMsg( QString( "zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ) );
}
// prepare list of normalized levels for each rule
for ( it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
{
Rule* rule = *it;
QgsSymbolV2* s = rule->symbol();
for ( int i = 0; i < s->symbolLayerCount(); i++ )
{
int normLevel = zLevelsToNormLevels.value( s->symbolLayer( i )->renderingPass() );
rule->mSymbolNormZLevels.append( normLevel );
}
}
mRootRule->setNormZLevels( zLevelsToNormLevels );
}
void QgsRuleBasedRendererV2::stopRender( QgsRenderContext& context )
@ -247,7 +409,7 @@ void QgsRuleBasedRendererV2::stopRender( QgsRenderContext& context )
bool drawVertexMarker = false;
// go through all levels
foreach( const RenderLevel& level, mRenderQueue.levels )
foreach( const RenderLevel& level, mRenderQueue )
{
//QgsDebugMsg(QString("level %1").arg(level.zIndex));
// go through all jobs at the level
@ -270,59 +432,41 @@ void QgsRuleBasedRendererV2::stopRender( QgsRenderContext& context )
}
}
// TODO:
// clear render queue, render jobs
// clean current features
foreach( QgsFeature* f, mCurrentFeatures )
{
delete f;
}
mCurrentFeatures.clear();
for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
{
Rule* rule = *it;
rule->symbol()->stopRender( context );
}
// clean render queue
mRenderQueue.clear();
mCurrentRules.clear();
// clean up rules from temporary stuff
mRootRule->stopRender( context );
}
QList<QString> QgsRuleBasedRendererV2::usedAttributes()
{
QSet<QString> attrs;
for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it )
{
Rule& rule = *it;
attrs.unite( rule.needsFields().toSet() );
if ( rule.symbol() )
{
attrs.unite( rule.symbol()->usedAttributes() );
}
}
QSet<QString> attrs = mRootRule->usedAttributes();
return attrs.values();
}
QgsFeatureRendererV2* QgsRuleBasedRendererV2::clone()
{
QgsSymbolV2* s = mDefaultSymbol->clone();
QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( s );
r->mRules = mRules;
QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2();
delete r->mRootRule;
r->mRootRule = mRootRule->clone();
r->setUsingSymbolLevels( usingSymbolLevels() );
setUsingSymbolLevels( usingSymbolLevels() );
return r;
}
// TODO: ideally this function should be removed in favor of legendSymbol(ogy)Items
QgsSymbolV2List QgsRuleBasedRendererV2::symbols()
{
QgsSymbolV2List lst;
for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it )
{
Rule& rule = *it;
lst.append( rule.symbol() );
}
return lst;
return mRootRule->symbols();
}
QDomElement QgsRuleBasedRendererV2::save( QDomDocument& doc )
@ -331,25 +475,10 @@ QDomElement QgsRuleBasedRendererV2::save( QDomDocument& doc )
rendererElem.setAttribute( "type", "RuleRenderer" );
rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
QDomElement rulesElem = doc.createElement( "rules" );
QgsSymbolV2Map symbols;
symbols["default"] = mDefaultSymbol;
int i = 0;
for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++i, ++it )
{
Rule& rule = *it;
symbols[QString::number( i )] = rule.symbol();
QDomElement ruleElem = doc.createElement( "rule" );
ruleElem.setAttribute( "symbol", i );
ruleElem.setAttribute( "filter", rule.filterExpression() );
ruleElem.setAttribute( "scalemindenom", rule.scaleMinDenom() );
ruleElem.setAttribute( "scalemaxdenom", rule.scaleMaxDenom() );
ruleElem.setAttribute( "label", rule.label() );
ruleElem.setAttribute( "description", rule.description() );
rulesElem.appendChild( ruleElem );
}
QDomElement rulesElem = doc.createElement( "rules" );
rulesElem.appendChild( mRootRule->save( doc, symbols ) );
rendererElem.appendChild( rulesElem );
QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
@ -362,22 +491,19 @@ QDomElement QgsRuleBasedRendererV2::save( QDomDocument& doc )
QgsLegendSymbologyList QgsRuleBasedRendererV2::legendSymbologyItems( QSize iconSize )
{
QgsLegendSymbologyList lst;
for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it )
QgsLegendSymbolList items = legendSymbolItems();
for ( QgsLegendSymbolList::iterator it = items.begin(); it != items.end(); it++ )
{
QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( it->symbol(), iconSize );
lst << qMakePair( it->label(), pix );
QPair<QString, QgsSymbolV2*> pair = *it;
QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( pair.second, iconSize );
lst << qMakePair( pair.first, pix );
}
return lst;
}
QgsLegendSymbolList QgsRuleBasedRendererV2::legendSymbolItems()
{
QgsLegendSymbolList lst;
for ( QList<Rule>::iterator it = mRules.begin(); it != mRules.end(); ++it )
{
lst << qMakePair( it->label(), it->symbol() );
}
return lst;
return mRootRule->legendSymbolItems();
}
@ -390,35 +516,16 @@ QgsFeatureRendererV2* QgsRuleBasedRendererV2::create( QDomElement& element )
QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
if ( !symbolMap.contains( "default" ) )
{
QgsDebugMsg( "default symbol not found!" );
return NULL;
}
QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( symbolMap.take( "default" ) );
r->mRules.clear();
QDomElement rulesElem = element.firstChildElement( "rules" );
QDomElement ruleElem = rulesElem.firstChildElement( "rule" );
while ( !ruleElem.isNull() )
{
QString symbolIdx = ruleElem.attribute( "symbol" );
if ( symbolMap.contains( symbolIdx ) )
{
QString filterExp = ruleElem.attribute( "filter" );
QString label = ruleElem.attribute( "label" );
QString description = ruleElem.attribute( "description" );
int scaleMinDenom = ruleElem.attribute( "scalemindenom", "0" ).toInt();
int scaleMaxDenom = ruleElem.attribute( "scalemaxdenom", "0" ).toInt();
r->mRules.append( Rule( symbolMap.take( symbolIdx ), scaleMinDenom, scaleMaxDenom, filterExp, label, description ) );
}
else
{
QgsDebugMsg( "symbol for rule " + symbolIdx + " not found! (skipping)" );
}
ruleElem = ruleElem.nextSiblingElement( "rule" );
}
QDomElement rootRuleElem = rulesElem.firstChildElement( "rule" );
Rule* root = Rule::create( rootRuleElem, symbolMap );
if ( root == NULL )
return NULL;
QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2();
delete r->mRootRule;
r->mRootRule = root;
// delete symbols if there are any more
QgsSymbolLayerV2Utils::clearSymbolMap( symbolMap );
@ -429,105 +536,108 @@ QgsFeatureRendererV2* QgsRuleBasedRendererV2::create( QDomElement& element )
int QgsRuleBasedRendererV2::ruleCount()
{
return mRules.count();
return mRootRule->children().count();
}
QgsRuleBasedRendererV2::Rule& QgsRuleBasedRendererV2::ruleAt( int index )
QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::ruleAt( int index )
{
return mRules[index];
return mRootRule->children()[index];
}
void QgsRuleBasedRendererV2::addRule( const QgsRuleBasedRendererV2::Rule& rule )
void QgsRuleBasedRendererV2::addRule( QgsRuleBasedRendererV2::Rule* rule )
{
mRules.append( rule );
mRootRule->children().append( rule );
}
void QgsRuleBasedRendererV2::insertRule( int index, const QgsRuleBasedRendererV2::Rule& rule )
void QgsRuleBasedRendererV2::insertRule( int index, QgsRuleBasedRendererV2::Rule* rule )
{
mRules.insert( index, rule );
mRootRule->children().insert( index, rule );
}
void QgsRuleBasedRendererV2::updateRuleAt( int index, const QgsRuleBasedRendererV2::Rule& rule )
void QgsRuleBasedRendererV2::updateRuleAt( int index, QgsRuleBasedRendererV2::Rule* rule )
{
mRules[index] = rule;
RuleList& rules = mRootRule->children();
delete rules[index]; // delete previous
rules[index] = rule;
}
void QgsRuleBasedRendererV2::removeRuleAt( int index )
{
mRules.removeAt( index );
delete mRootRule->children().takeAt( index );
}
void QgsRuleBasedRendererV2::swapRules( int index1, int index2 )
{
mRules.swap( index1, index2 );
mRootRule->children().swap( index1, index2 );
}
#include "qgscategorizedsymbolrendererv2.h"
#include "qgsgraduatedsymbolrendererv2.h"
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2::refineRuleCategories( QgsRuleBasedRendererV2::Rule& initialRule, QgsCategorizedSymbolRendererV2* r )
QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2::refineRuleCategories( QgsRuleBasedRendererV2::Rule* initialRule, QgsCategorizedSymbolRendererV2* r )
{
QList<Rule> rules;
RuleList rules;
foreach( const QgsRendererCategoryV2& cat, r->categories() )
{
QString newfilter = QString( "%1 = '%2'" ).arg( r->classAttribute() ).arg( cat.value().toString() );
QString filter = initialRule.filterExpression();
QString label = initialRule.label();
QString description = initialRule.description();
QString filter = initialRule->filterExpression();
QString label = initialRule->label();
QString description = initialRule->description();
if ( filter.isEmpty() )
filter = newfilter;
else
filter = QString( "(%1) AND (%2)" ).arg( filter ).arg( newfilter );
rules.append( Rule( cat.symbol()->clone(), initialRule.scaleMinDenom(), initialRule.scaleMaxDenom(), filter, initialRule.label(), initialRule.description() ) );
rules.append( new Rule( cat.symbol()->clone(), initialRule->scaleMinDenom(), initialRule->scaleMaxDenom(), filter, label, description ) );
}
return rules;
}
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2::refineRuleRanges( QgsRuleBasedRendererV2::Rule& initialRule, QgsGraduatedSymbolRendererV2* r )
QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2::refineRuleRanges( QgsRuleBasedRendererV2::Rule* initialRule, QgsGraduatedSymbolRendererV2* r )
{
QList<Rule> rules;
RuleList rules;
foreach( const QgsRendererRangeV2& rng, r->ranges() )
{
QString newfilter = QString( "%1 >= '%2' AND %1 <= '%3'" ).arg( r->classAttribute() ).arg( rng.lowerValue() ).arg( rng.upperValue() );
QString filter = initialRule.filterExpression();
QString label = initialRule.label();
QString description = initialRule.description();
QString filter = initialRule->filterExpression();
QString label = initialRule->label();
QString description = initialRule->description();
if ( filter.isEmpty() )
filter = newfilter;
else
filter = QString( "(%1) AND (%2)" ).arg( filter ).arg( newfilter );
rules.append( Rule( rng.symbol()->clone(), initialRule.scaleMinDenom(), initialRule.scaleMaxDenom(), filter, initialRule.label(), initialRule.description() ) );
rules.append( new Rule( rng.symbol()->clone(), initialRule->scaleMinDenom(), initialRule->scaleMaxDenom(), filter, label, description ) );
}
return rules;
}
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2::refineRuleScales( QgsRuleBasedRendererV2::Rule& initialRule, QList<int> scales )
QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2::refineRuleScales( QgsRuleBasedRendererV2::Rule* initialRule, QList<int> scales )
{
qSort( scales ); // make sure the scales are in ascending order
QList<Rule> rules;
int oldScale = initialRule.scaleMinDenom();
int maxDenom = initialRule.scaleMaxDenom();
RuleList rules;
int oldScale = initialRule->scaleMinDenom();
int maxDenom = initialRule->scaleMaxDenom();
QString filter = initialRule->filterExpression();
QString label = initialRule->label();
QString description = initialRule->description();
QgsSymbolV2* symbol = initialRule->symbol();
foreach( int scale, scales )
{
if ( initialRule.scaleMinDenom() >= scale )
if ( initialRule->scaleMinDenom() >= scale )
continue; // jump over the first scales out of the interval
if ( maxDenom != 0 && maxDenom <= scale )
break; // ignore the latter scales out of the interval
rules.append( Rule( initialRule.symbol()->clone(), oldScale, scale, initialRule.filterExpression(), initialRule.label(), initialRule.description() ) );
rules.append( new Rule( symbol->clone(), oldScale, scale, filter, label, description ) );
oldScale = scale;
}
// last rule
rules.append( Rule( initialRule.symbol()->clone(), oldScale, maxDenom, initialRule.filterExpression(), initialRule.label(), initialRule.description() ) );
rules.append( new Rule( symbol->clone(), oldScale, maxDenom, filter, label, description ) );
return rules;
}
QString QgsRuleBasedRendererV2::dump()
{
QString msg( "Rule-based renderer:\n" );
foreach( const Rule& rule, mRules )
{
msg += rule.dump();
}
msg += mRootRule->dump();
return msg;
}

View File

@ -33,6 +33,34 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2
{
public:
// TODO: use QVarLengthArray instead of QList
// rendering job: a feature to be rendered with a particular symbol
// (both f, symbol are _not_ owned by this class)
struct RenderJob
{
RenderJob( QgsFeature* _f, QgsSymbolV2* _s ) : f( _f ), symbol( _s ) {}
QgsFeature* f;
QgsSymbolV2* symbol;
};
// render level: a list of jobs to be drawn at particular level
// (jobs are owned by this class)
struct RenderLevel
{
RenderLevel( int z ): zIndex( z ) {}
~RenderLevel() { foreach( RenderJob* j, jobs ) delete j; }
int zIndex;
QList<RenderJob*> jobs;
};
// rendering queue: a list of rendering levels
typedef QList<RenderLevel> RenderQueue;
class Rule;
typedef QList<Rule*> RuleList;
/**
This class keeps data about a rules for rule-based renderer.
A rule consists of a symbol, filter expression and range of scales.
@ -47,29 +75,50 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2
//! Constructor takes ownership of the symbol
Rule( QgsSymbolV2* symbol, int scaleMinDenom = 0, int scaleMaxDenom = 0, QString filterExp = QString(),
QString label = QString(), QString description = QString() );
Rule( const Rule& other );
//Rule( const Rule& other );
~Rule();
QString dump() const;
QStringList needsFields() const;
QSet<QString> usedAttributes();
QgsSymbolV2List symbols();
QgsLegendSymbolList legendSymbolItems();
bool isFilterOK( QgsFeature& f ) const;
bool isScaleOK( double scale ) const;
QgsSymbolV2* symbol() { return mSymbol; }
QString label() const { return mLabel; }
bool dependsOnScale() const { return mScaleMinDenom != 0 || mScaleMaxDenom != 0; }
int scaleMinDenom() const { return mScaleMinDenom; }
int scaleMaxDenom() const { return mScaleMaxDenom; }
QgsExpression* filter() const { return mFilter; }
QString filterExpression() const { return mFilterExp; }
QString label() const { return mLabel; }
QString description() const { return mDescription; }
void setLabel( QString label ) { mLabel = label; }
void setScaleMinDenom( int scaleMinDenom ) { mScaleMinDenom = scaleMinDenom; }
void setScaleMaxDenom( int scaleMaxDenom ) { mScaleMaxDenom = scaleMaxDenom; }
void setFilterExpression( QString filterExp ) { mFilterExp = filterExp; initFilter(); }
void setLabel( QString label ) { mLabel = label; }
void setDescription( QString description ) { mDescription = description; }
Rule& operator=( const Rule& other );
//Rule& operator=( const Rule& other );
//! clone this rule, return new instance
Rule* clone() const;
QDomElement save( QDomDocument& doc, QgsSymbolV2Map& symbolMap );
//! prepare the rule for rendering and its children (build active children array)
bool startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer );
//! get all used z-levels from this rule and children
QSet<int> collectZLevels();
//! assign normalized z-levels [0..N-1] for this rule's symbol for quick access during rendering
void setNormZLevels( const QMap<int, int>& zLevelsToNormLevels );
void renderFeature( QgsFeature* featPtr, QgsRenderContext& context, RenderQueue& renderQueue );
void stopRender( QgsRenderContext& context );
static Rule* create( QDomElement& ruleElem, QgsSymbolV2Map& symbolMap );
RuleList& children() { return mChildren; }
protected:
@ -78,43 +127,24 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2
QgsSymbolV2* mSymbol;
int mScaleMinDenom, mScaleMaxDenom;
QString mFilterExp, mLabel, mDescription;
bool mElseRule;
RuleList mChildren;
// temporary
QgsExpression* mFilter;
public: // TODO
QList<int> mSymbolNormZLevels; // normalized
};
// TODO: use QVarLengthArray instead of QList
// rendering job: a feature to be rendered with a particular symbol
struct RenderJob
{
RenderJob( QgsFeature* _f, QgsSymbolV2* _s ) : f( _f ), symbol( _s ) {}
QgsFeature* f;
QgsSymbolV2* symbol;
};
// render level: a list of jobs to be drawn at particular level
struct RenderLevel
{
RenderLevel( int z ): zIndex( z ) {}
int zIndex;
QList<RenderJob*> jobs;
};
// rendering queue: a list of rendering levels and jobs
struct RenderQueue
{
QList<RenderLevel> levels;
// temporary while rendering
QList<int> mSymbolNormZLevels;
RuleList mActiveChildren;
};
/////
static QgsFeatureRendererV2* create( QDomElement& element );
//! Constructor. Takes ownership of the default symbol.
QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol );
//! Constructor. Adds default rule if the symbol is not null (and takes ownership of it)
QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol = NULL );
~QgsRuleBasedRendererV2();
//! return symbol for current feature. Should not be used individually: there could be more symbols for a feature
virtual QgsSymbolV2* symbolForFeature( QgsFeature& feature );
@ -146,43 +176,41 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2
/////
Rule* rootRule() { return mRootRule; }
//! return the total number of rules
int ruleCount();
//! get reference to rule at index (valid indexes: 0...count-1)
Rule& ruleAt( int index );
//! add rule to the end of the list of rules
void addRule( const Rule& rule );
//! insert rule to a specific position of the list of rules
void insertRule( int index, const Rule& rule );
//! modify the rule at a specific position of the list of rules
void updateRuleAt( int index, const Rule& rule );
Rule* ruleAt( int index );
//! add rule to the end of the list of rules. takes ownership
void addRule( Rule* rule );
//! insert rule to a specific position of the list of rules. takes ownership
void insertRule( int index, Rule* rule );
//! modify the rule at a specific position of the list of rules. takes ownership
void updateRuleAt( int index, Rule* rule );
//! remove the rule at the specified index
void removeRuleAt( int index );
//! swap the two rules specified by the indices
void swapRules( int index1, int index2 );
//////
//! take a rule and create a list of new rules based on the categories from categorized symbol renderer
static QList<Rule> refineRuleCategories( Rule& initialRule, QgsCategorizedSymbolRendererV2* r );
static RuleList refineRuleCategories( Rule* initialRule, QgsCategorizedSymbolRendererV2* r );
//! take a rule and create a list of new rules based on the ranges from graduated symbol renderer
static QList<Rule> refineRuleRanges( Rule& initialRule, QgsGraduatedSymbolRendererV2* r );
static RuleList refineRuleRanges( Rule* initialRule, QgsGraduatedSymbolRendererV2* r );
//! take a rule and create a list of new rules with intervals of scales given by the passed scale denominators
static QList<Rule> refineRuleScales( Rule& initialRule, QList<int> scales );
static RuleList refineRuleScales( Rule* initialRule, QList<int> scales );
protected:
//! the list of rules
QList<Rule> mRules;
//! the default symbol, used for the first rule with no filter
QgsSymbolV2* mDefaultSymbol;
//! the root node with hierarchical list of rules
Rule* mRootRule;
// temporary
QList<Rule*> mCurrentRules;
QgsSymbolV2* mCurrentSymbol;
RenderQueue mRenderQueue;
QList<QgsFeature*> mCurrentFeatures;
//QList<RenderJob*> mCurrentRenderJobs;
};
#endif // QGSRULEBASEDRENDERERV2_H

View File

@ -110,16 +110,21 @@ void QgsRuleBasedRendererV2Widget::setGrouping()
void QgsRuleBasedRendererV2Widget::addRule()
{
QgsRuleBasedRendererV2::Rule newrule( QgsSymbolV2::defaultSymbol( mLayer->geometryType() ) );
QgsSymbolV2* s = QgsSymbolV2::defaultSymbol( mLayer->geometryType() );
QgsRuleBasedRendererV2::Rule* newrule = new QgsRuleBasedRendererV2::Rule( s );
QgsRendererRulePropsDialog dlg( newrule, mLayer, mStyle );
if ( dlg.exec() )
{
// add rule
dlg.updateRuleFromGui();
mRenderer->addRule( dlg.rule() );
mRenderer->addRule( newrule ); // takes ownership
treeRules->populateRules();
}
else
{
delete newrule;
}
}
@ -136,17 +141,21 @@ void QgsRuleBasedRendererV2Widget::editRule()
QMessageBox::information( this, tr( "Edit rule" ), tr( "Groups of rules cannot be edited." ) );
return;
}
QgsRuleBasedRendererV2::Rule& rule = mRenderer->ruleAt( rule_index );
QgsRuleBasedRendererV2::Rule* rule = mRenderer->ruleAt( rule_index )->clone();
QgsRendererRulePropsDialog dlg( rule, mLayer, mStyle );
if ( dlg.exec() )
{
// update rule
dlg.updateRuleFromGui();
mRenderer->updateRuleAt( rule_index, dlg.rule() );
mRenderer->updateRuleAt( rule_index, rule );
treeRules->populateRules();
}
else
{
delete rule;
}
}
void QgsRuleBasedRendererV2Widget::removeRule()
@ -245,10 +254,10 @@ void QgsRuleBasedRendererV2Widget::refineRule( int type )
if ( rule_index < 0 )
return;
QgsRuleBasedRendererV2::Rule& initialRule = mRenderer->ruleAt( rule_index );
QgsRuleBasedRendererV2::Rule* initialRule = mRenderer->ruleAt( rule_index );
QList<QgsRuleBasedRendererV2::Rule> refinedRules;
QgsRuleBasedRendererV2::RuleList refinedRules;
if ( type == 0 ) // categories
refinedRules = refineRuleCategoriesGui( initialRule );
else if ( type == 1 ) // ranges
@ -286,7 +295,7 @@ void QgsRuleBasedRendererV2Widget::refineRuleScales()
refineRule( 2 );
}
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2Widget::refineRuleCategoriesGui( QgsRuleBasedRendererV2::Rule& initialRule )
QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2Widget::refineRuleCategoriesGui( QgsRuleBasedRendererV2::Rule* initialRule )
{
QDialog dlg;
dlg.setWindowTitle( tr( "Refine a rule to categories" ) );
@ -300,7 +309,7 @@ QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2Widget::refineRuleCate
dlg.setLayout( l );
if ( !dlg.exec() )
return QList<QgsRuleBasedRendererV2::Rule>();
return QgsRuleBasedRendererV2::RuleList();
// create new rules
QgsCategorizedSymbolRendererV2* r = static_cast<QgsCategorizedSymbolRendererV2*>( w->renderer() );
@ -308,7 +317,7 @@ QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2Widget::refineRuleCate
}
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2Widget::refineRuleRangesGui( QgsRuleBasedRendererV2::Rule& initialRule )
QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2Widget::refineRuleRangesGui( QgsRuleBasedRendererV2::Rule* initialRule )
{
QDialog dlg;
dlg.setWindowTitle( tr( "Refine a rule to ranges" ) );
@ -322,20 +331,20 @@ QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2Widget::refineRuleRang
dlg.setLayout( l );
if ( !dlg.exec() )
return QList<QgsRuleBasedRendererV2::Rule>();
return QgsRuleBasedRendererV2::RuleList();
// create new rules
QgsGraduatedSymbolRendererV2* r = static_cast<QgsGraduatedSymbolRendererV2*>( w->renderer() );
return QgsRuleBasedRendererV2::refineRuleRanges( initialRule, r );
}
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2Widget::refineRuleScalesGui( QgsRuleBasedRendererV2::Rule& initialRule )
QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2Widget::refineRuleScalesGui( QgsRuleBasedRendererV2::Rule* initialRule )
{
QString txt = QInputDialog::getText( this,
tr( "Scale refinement" ),
tr( "Please enter scale denominators at which will split the rule, separate them by commas (e.g. 1000,5000):" ) );
if ( txt.isEmpty() )
return QList<QgsRuleBasedRendererV2::Rule>();
return QgsRuleBasedRendererV2::RuleList();
QList<int> scales;
bool ok;
@ -367,7 +376,7 @@ QList<QgsSymbolV2*> QgsRuleBasedRendererV2Widget::selectedSymbols()
int priority = ( *it )->data( 0, Qt::UserRole + 1 ).toInt();
if ( priority < mRenderer->ruleCount() )
{
symbolList.append( mRenderer->ruleAt( priority ).symbol() );
symbolList.append( mRenderer->ruleAt( priority )->symbol() );
}
}
@ -385,23 +394,23 @@ void QgsRuleBasedRendererV2Widget::refreshSymbolView()
///////////
QgsRendererRulePropsDialog::QgsRendererRulePropsDialog( const QgsRuleBasedRendererV2::Rule& rule, QgsVectorLayer* layer, QgsStyleV2* style )
QgsRendererRulePropsDialog::QgsRendererRulePropsDialog( QgsRuleBasedRendererV2::Rule* rule, QgsVectorLayer* layer, QgsStyleV2* style )
: mRule( rule ), mLayer( layer )
{
setupUi( this );
editFilter->setText( mRule.filterExpression() );
editLabel->setText( mRule.label() );
editDescription->setText( mRule.description() );
editFilter->setText( mRule->filterExpression() );
editLabel->setText( mRule->label() );
editDescription->setText( mRule->description() );
if ( mRule.dependsOnScale() )
if ( mRule->dependsOnScale() )
{
groupScale->setChecked( true );
spinMinScale->setValue( rule.scaleMinDenom() );
spinMaxScale->setValue( rule.scaleMaxDenom() );
spinMinScale->setValue( rule->scaleMinDenom() );
spinMaxScale->setValue( rule->scaleMaxDenom() );
}
QgsSymbolV2SelectorDialog* symbolSel = new QgsSymbolV2SelectorDialog( mRule.symbol(), style, mLayer, this, true );
QgsSymbolV2SelectorDialog* symbolSel = new QgsSymbolV2SelectorDialog( mRule->symbol(), style, mLayer, this, true );
QVBoxLayout* l = new QVBoxLayout;
l->addWidget( symbolSel );
groupSymbol->setLayout( l );
@ -458,11 +467,11 @@ void QgsRendererRulePropsDialog::testFilter()
void QgsRendererRulePropsDialog::updateRuleFromGui()
{
mRule.setFilterExpression( editFilter->text() );
mRule.setLabel( editLabel->text() );
mRule.setDescription( editDescription->text() );
mRule.setScaleMinDenom( groupScale->isChecked() ? spinMinScale->value() : 0 );
mRule.setScaleMaxDenom( groupScale->isChecked() ? spinMaxScale->value() : 0 );
mRule->setFilterExpression( editFilter->text() );
mRule->setLabel( editLabel->text() );
mRule->setDescription( editDescription->text() );
mRule->setScaleMinDenom( groupScale->isChecked() ? spinMinScale->value() : 0 );
mRule->setScaleMaxDenom( groupScale->isChecked() ? spinMaxScale->value() : 0 );
}
////////
@ -530,10 +539,10 @@ void QgsRendererRulesTreeWidget::populateRules()
// TODO: use a custom model and implement custom sorting
for ( int i = 0; i < mR->ruleCount(); ++i )
{
QgsRuleBasedRendererV2::Rule& rule = mR->ruleAt( i );
QgsRuleBasedRendererV2::Rule* rule = mR->ruleAt( i );
mLongestMinDenom = qMax( mLongestMinDenom, formatScale( rule.scaleMinDenom() ).size() );
mLongestMaxDenom = qMax( mLongestMaxDenom, formatScale( rule.scaleMaxDenom() ).size() );
mLongestMinDenom = qMax( mLongestMinDenom, formatScale( rule->scaleMinDenom() ).size() );
mLongestMaxDenom = qMax( mLongestMaxDenom, formatScale( rule->scaleMaxDenom() ).size() );
}
@ -554,24 +563,24 @@ void QgsRendererRulesTreeWidget::populateRulesNoGrouping()
for ( int i = 0; i < mR->ruleCount(); ++i )
{
QgsRuleBasedRendererV2::Rule& rule = mR->ruleAt( i );
QgsRuleBasedRendererV2::Rule* rule = mR->ruleAt( i );
QTreeWidgetItem* item = new QTreeWidgetItem;
QString txtLabel = rule.label();
QString txtLabel = rule->label();
item->setText( 0, txtLabel );
item->setData( 0, Qt::UserRole + 1, i );
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule.symbol(), QSize( 16, 16 ) ) );
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule->symbol(), QSize( 16, 16 ) ) );
QString txtRule = rule.filterExpression();
QString txtRule = rule->filterExpression();
if ( txtRule.isEmpty() )
txtRule = tr( "(no filter)" );
item->setText( 1, txtRule );
if ( rule.dependsOnScale() )
if ( rule->dependsOnScale() )
{
item->setText( 2, formatScale( rule.scaleMinDenom(), mLongestMinDenom ) );
item->setText( 3, formatScale( rule.scaleMaxDenom(), mLongestMaxDenom ) );
item->setText( 2, formatScale( rule->scaleMinDenom(), mLongestMinDenom ) );
item->setText( 3, formatScale( rule->scaleMaxDenom(), mLongestMaxDenom ) );
item->setTextAlignment( 2, Qt::AlignRight );
item->setTextAlignment( 3, Qt::AlignRight );
}
@ -598,14 +607,14 @@ void QgsRendererRulesTreeWidget::populateRulesGroupByScale()
for ( int i = 0; i < mR->ruleCount(); ++i )
{
QgsRuleBasedRendererV2::Rule& rule = mR->ruleAt( i );
QgsRuleBasedRendererV2::Rule* rule = mR->ruleAt( i );
QPair<int, int> scale = qMakePair( rule.scaleMinDenom(), rule.scaleMaxDenom() );
QPair<int, int> scale = qMakePair( rule->scaleMinDenom(), rule->scaleMaxDenom() );
if ( ! scale_items.contains( scale ) )
{
QString txt;
if ( rule.dependsOnScale() )
txt = tr( "scale " ) + formatScaleRange( rule.scaleMinDenom(), rule.scaleMaxDenom() );
if ( rule->dependsOnScale() )
txt = tr( "scale " ) + formatScaleRange( rule->scaleMinDenom(), rule->scaleMaxDenom() );
else
txt = tr( "any scale" );
@ -621,25 +630,25 @@ void QgsRendererRulesTreeWidget::populateRulesGroupByScale()
scale_item->setFirstColumnSpanned( true );
}
QString filter = rule.filterExpression();
QString filter = rule->filterExpression();
QTreeWidgetItem* item = new QTreeWidgetItem( scale_items[scale] );
QString txtLabel = rule.label();
QString txtLabel = rule->label();
item->setText( 0, txtLabel );
item->setData( 0, Qt::UserRole + 1, i );
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule.symbol(), QSize( 16, 16 ) ) );
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule->symbol(), QSize( 16, 16 ) ) );
QString txtRule = rule.filterExpression();
QString txtRule = rule->filterExpression();
if ( txtRule.isEmpty() )
txtRule = tr( "(no filter)" );
item->setText( 1, txtRule );
if ( rule.dependsOnScale() )
if ( rule->dependsOnScale() )
{
// Displaying scales is redundant here, but keeping them allows to keep constant the layout and width of all columns when switching to one of the two other views
item->setText( 2, formatScale( rule.scaleMinDenom(), mLongestMinDenom ) );
item->setText( 3, formatScale( rule.scaleMaxDenom(), mLongestMaxDenom ) );
item->setText( 2, formatScale( rule->scaleMinDenom(), mLongestMinDenom ) );
item->setText( 3, formatScale( rule->scaleMaxDenom(), mLongestMaxDenom ) );
item->setTextAlignment( 2, Qt::AlignRight );
item->setTextAlignment( 3, Qt::AlignRight );
}
@ -664,9 +673,9 @@ void QgsRendererRulesTreeWidget::populateRulesGroupByFilter()
for ( int i = 0; i < mR->ruleCount(); ++i )
{
QgsRuleBasedRendererV2::Rule& rule = mR->ruleAt( i );
QgsRuleBasedRendererV2::Rule* rule = mR->ruleAt( i );
QString filter = rule.filterExpression();
QString filter = rule->filterExpression();
if ( ! filter_items.contains( filter ) )
{
QTreeWidgetItem* filter_item = new QTreeWidgetItem;
@ -683,10 +692,10 @@ void QgsRendererRulesTreeWidget::populateRulesGroupByFilter()
QTreeWidgetItem* item = new QTreeWidgetItem( filter_items[filter] );
QString txtLabel = rule.label();
QString txtLabel = rule->label();
item->setText( 0, txtLabel );
item->setData( 0, Qt::UserRole + 1, i );
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule.symbol(), QSize( 16, 16 ) ) );
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule->symbol(), QSize( 16, 16 ) ) );
// Displaying filter is redundant here, but keeping it allows to keep constant the layout and width of all columns when switching to one of the two other views
item->setText( 1, filter );
@ -695,10 +704,10 @@ void QgsRendererRulesTreeWidget::populateRulesGroupByFilter()
//item->setBackground( 1, Qt::lightGray );
//item->setBackground( 3, Qt::lightGray );
if ( rule.dependsOnScale() )
if ( rule->dependsOnScale() )
{
item->setText( 2, formatScale( rule.scaleMinDenom(), mLongestMinDenom ) );
item->setText( 3, formatScale( rule.scaleMaxDenom(), mLongestMaxDenom ) );
item->setText( 2, formatScale( rule->scaleMinDenom(), mLongestMinDenom ) );
item->setText( 3, formatScale( rule->scaleMaxDenom(), mLongestMaxDenom ) );
item->setTextAlignment( 2, Qt::AlignRight );
item->setTextAlignment( 3, Qt::AlignRight );
}

View File

@ -90,9 +90,9 @@ class GUI_EXPORT QgsRuleBasedRendererV2Widget : public QgsRendererV2Widget, priv
protected:
void refineRule( int type );
QList<QgsRuleBasedRendererV2::Rule> refineRuleCategoriesGui( QgsRuleBasedRendererV2::Rule& initialRule );
QList<QgsRuleBasedRendererV2::Rule> refineRuleRangesGui( QgsRuleBasedRendererV2::Rule& initialRule );
QList<QgsRuleBasedRendererV2::Rule> refineRuleScalesGui( QgsRuleBasedRendererV2::Rule& initialRule );
QgsRuleBasedRendererV2::RuleList refineRuleCategoriesGui( QgsRuleBasedRendererV2::Rule* initialRule );
QgsRuleBasedRendererV2::RuleList refineRuleRangesGui( QgsRuleBasedRendererV2::Rule* initialRule );
QgsRuleBasedRendererV2::RuleList refineRuleScalesGui( QgsRuleBasedRendererV2::Rule* initialRule );
QList<QgsSymbolV2*> selectedSymbols();
void refreshSymbolView();
@ -113,17 +113,17 @@ class GUI_EXPORT QgsRendererRulePropsDialog : public QDialog, private Ui::QgsRen
Q_OBJECT
public:
QgsRendererRulePropsDialog( const QgsRuleBasedRendererV2::Rule& rule, QgsVectorLayer* layer, QgsStyleV2* style );
QgsRendererRulePropsDialog( QgsRuleBasedRendererV2::Rule* rule, QgsVectorLayer* layer, QgsStyleV2* style );
void updateRuleFromGui();
const QgsRuleBasedRendererV2::Rule& rule() { return mRule; }
QgsRuleBasedRendererV2::Rule* rule() { return mRule; }
public slots:
void testFilter();
void buildExpression();
protected:
QgsRuleBasedRendererV2::Rule mRule;
QgsRuleBasedRendererV2::Rule* mRule; // borrowed
QgsVectorLayer* mLayer;
QgsStyleV2* mStyle;
};