diff --git a/python/core/symbology-ng-core.sip b/python/core/symbology-ng-core.sip index 2a909271abc..292ee147a5f 100644 --- a/python/core/symbology-ng-core.sip +++ b/python/core/symbology-ng-core.sip @@ -390,6 +390,8 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2 public: + //typedef QList 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 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 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 refineRuleScales( QgsRuleBasedRendererV2::Rule& initialRule, QList scales ); + //static QgsRuleBasedRendererV2::RuleList refineRuleScales( QgsRuleBasedRendererV2::Rule* initialRule, QList scales ); }; diff --git a/src/core/symbology-ng/qgsrulebasedrendererv2.cpp b/src/core/symbology-ng/qgsrulebasedrendererv2.cpp index f0bc552bef3..2106b26fd2d 100644 --- a/src/core/symbology-ng/qgsrulebasedrendererv2.cpp +++ b/src/core/symbology-ng/qgsrulebasedrendererv2.cpp @@ -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 QgsRuleBasedRendererV2::Rule::usedAttributes() { - if ( ! mFilter ) - return QStringList(); + // attributes needed by this rule + QSet 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 QgsRuleBasedRendererV2::Rule::collectZLevels() +{ + QSet 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::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& 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::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::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::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::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::iterator it = mRules.begin(); it != mRules.end(); ++it ) - { - Rule& rule = *it; - if ( rule.isScaleOK( currentScale ) ) - mCurrentRules.append( &rule ); - } - - QgsFieldMap pendingFields = vlayer->pendingFields(); - - QSet symbolZLevelsSet; - - QList::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 symbolZLevelsSet = mRootRule->collectZLevels(); // create mapping from unnormalized levels [unlimited range] to normalized levels [0..N-1] // and prepare rendering queue QMap 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::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 QgsRuleBasedRendererV2::usedAttributes() { - QSet attrs; - for ( QList::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 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::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::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::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 pair = *it; + QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( pair.second, iconSize ); + lst << qMakePair( pair.first, pix ); } return lst; } QgsLegendSymbolList QgsRuleBasedRendererV2::legendSymbolItems() { - QgsLegendSymbolList lst; - for ( QList::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::refineRuleCategories( QgsRuleBasedRendererV2::Rule& initialRule, QgsCategorizedSymbolRendererV2* r ) +QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2::refineRuleCategories( QgsRuleBasedRendererV2::Rule* initialRule, QgsCategorizedSymbolRendererV2* r ) { - QList 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::refineRuleRanges( QgsRuleBasedRendererV2::Rule& initialRule, QgsGraduatedSymbolRendererV2* r ) +QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2::refineRuleRanges( QgsRuleBasedRendererV2::Rule* initialRule, QgsGraduatedSymbolRendererV2* r ) { - QList 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::refineRuleScales( QgsRuleBasedRendererV2::Rule& initialRule, QList scales ) +QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2::refineRuleScales( QgsRuleBasedRendererV2::Rule* initialRule, QList scales ) { qSort( scales ); // make sure the scales are in ascending order - QList 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; } diff --git a/src/core/symbology-ng/qgsrulebasedrendererv2.h b/src/core/symbology-ng/qgsrulebasedrendererv2.h index ecbd7af0fd2..dd5862a9ff4 100644 --- a/src/core/symbology-ng/qgsrulebasedrendererv2.h +++ b/src/core/symbology-ng/qgsrulebasedrendererv2.h @@ -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 jobs; + }; + + // rendering queue: a list of rendering levels + typedef QList RenderQueue; + + class Rule; + typedef QList 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 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 collectZLevels(); + //! assign normalized z-levels [0..N-1] for this rule's symbol for quick access during rendering + void setNormZLevels( const QMap& 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 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 jobs; - }; - - // rendering queue: a list of rendering levels and jobs - struct RenderQueue - { - QList levels; + // temporary while rendering + QList 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 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 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 refineRuleScales( Rule& initialRule, QList scales ); + static RuleList refineRuleScales( Rule* initialRule, QList scales ); protected: - //! the list of rules - QList 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 mCurrentRules; - QgsSymbolV2* mCurrentSymbol; - RenderQueue mRenderQueue; QList mCurrentFeatures; - //QList mCurrentRenderJobs; }; #endif // QGSRULEBASEDRENDERERV2_H diff --git a/src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp b/src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp index 2d86a034cc8..42e9a5191ba 100644 --- a/src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp +++ b/src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp @@ -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 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 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 QgsRuleBasedRendererV2Widget::refineRuleCate dlg.setLayout( l ); if ( !dlg.exec() ) - return QList(); + return QgsRuleBasedRendererV2::RuleList(); // create new rules QgsCategorizedSymbolRendererV2* r = static_cast( w->renderer() ); @@ -308,7 +317,7 @@ QList QgsRuleBasedRendererV2Widget::refineRuleCate } -QList 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 QgsRuleBasedRendererV2Widget::refineRuleRang dlg.setLayout( l ); if ( !dlg.exec() ) - return QList(); + return QgsRuleBasedRendererV2::RuleList(); // create new rules QgsGraduatedSymbolRendererV2* r = static_cast( w->renderer() ); return QgsRuleBasedRendererV2::refineRuleRanges( initialRule, r ); } -QList 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(); + return QgsRuleBasedRendererV2::RuleList(); QList scales; bool ok; @@ -367,7 +376,7 @@ QList 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 scale = qMakePair( rule.scaleMinDenom(), rule.scaleMaxDenom() ); + QPair 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 ); } diff --git a/src/gui/symbology-ng/qgsrulebasedrendererv2widget.h b/src/gui/symbology-ng/qgsrulebasedrendererv2widget.h index 9f2a8ce32c4..c2a2bc78ea2 100644 --- a/src/gui/symbology-ng/qgsrulebasedrendererv2widget.h +++ b/src/gui/symbology-ng/qgsrulebasedrendererv2widget.h @@ -90,9 +90,9 @@ class GUI_EXPORT QgsRuleBasedRendererV2Widget : public QgsRendererV2Widget, priv protected: void refineRule( int type ); - QList refineRuleCategoriesGui( QgsRuleBasedRendererV2::Rule& initialRule ); - QList refineRuleRangesGui( QgsRuleBasedRendererV2::Rule& initialRule ); - QList refineRuleScalesGui( QgsRuleBasedRendererV2::Rule& initialRule ); + QgsRuleBasedRendererV2::RuleList refineRuleCategoriesGui( QgsRuleBasedRendererV2::Rule* initialRule ); + QgsRuleBasedRendererV2::RuleList refineRuleRangesGui( QgsRuleBasedRendererV2::Rule* initialRule ); + QgsRuleBasedRendererV2::RuleList refineRuleScalesGui( QgsRuleBasedRendererV2::Rule* initialRule ); QList 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; };