mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[FEATURE] Added rule-based renderer for symbology-ng.
Developed for Faunalia (http://www.faunalia.it) with funding from Regione Toscana - Sistema Informativo per la Gestione del Territorio e dell' Ambiente [RT-SIGTA]". For the project: "Sviluppo di prodotti software GIS open-source basati sui prodotti QuantumGIS e Postgis (CIG 037728516E) git-svn-id: http://svn.osgeo.org/qgis/trunk@13710 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
parent
65b1cc2416
commit
0a4f1c5947
@ -1,5 +1,3 @@
|
||||
/** polyline is just a list of points */
|
||||
typedef QMap<int, QgsField> QgsFieldMap;
|
||||
|
||||
/** \ingroup analysis
|
||||
* The QGis class provides vector geometry analysis functions
|
||||
|
@ -51,6 +51,8 @@ class QgsFeatureRendererV2
|
||||
sipClass = sipClass_QgsCategorizedSymbolRendererV2;
|
||||
else if (sipCpp->type() == "graduatedSymbol")
|
||||
sipClass = sipClass_QgsGraduatedSymbolRendererV2;
|
||||
else if (sipCpp->type() == "RuleRenderer")
|
||||
sipClass = sipClass_QgsRuleBasedRendererV2;
|
||||
else
|
||||
sipClass = 0;
|
||||
%End
|
||||
@ -350,6 +352,101 @@ protected:
|
||||
QgsSymbolV2* symbolForValue(double value);
|
||||
};
|
||||
|
||||
///////////////
|
||||
|
||||
class QgsRuleBasedRendererV2 : QgsFeatureRendererV2
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <qgsrulebasedrendererv2.h>
|
||||
%End
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
This class keeps data about a rules for rule-based renderer.
|
||||
A rule consists of a symbol, filter expression and range of scales.
|
||||
If filter is empty, it matches all features.
|
||||
If scale range has both values zero, it matches all scales.
|
||||
If one of the min/max scale denominators is zero, there is no lower/upper bound for scales.
|
||||
A rule matches if both filter and scale range match.
|
||||
*/
|
||||
class Rule
|
||||
{
|
||||
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();
|
||||
QString dump() const;
|
||||
QStringList needsFields() const;
|
||||
bool isFilterOK( const QgsFieldMap& fields, QgsFeature& f ) const;
|
||||
bool isScaleOK( double scale ) const;
|
||||
|
||||
QgsSymbolV2* symbol();
|
||||
bool dependsOnScale() const;
|
||||
int scaleMinDenom() const;
|
||||
int scaleMaxDenom() const;
|
||||
QString filterExpression() const;
|
||||
|
||||
void setScaleMinDenom( int scaleMinDenom );
|
||||
void setScaleMaxDenom( int scaleMaxDenom );
|
||||
void setFilterExpression( QString filterExp );
|
||||
|
||||
//Rule& operator=( const Rule& other );
|
||||
};
|
||||
|
||||
/////
|
||||
|
||||
static QgsFeatureRendererV2* create( QDomElement& element ) /Factory/;
|
||||
|
||||
//! Constructor. Takes ownership of the defult symbol.
|
||||
QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol /Transfer/ );
|
||||
|
||||
//! return symbol for current feature. Should not be used individually: there could be more symbols for a feature
|
||||
virtual QgsSymbolV2* symbolForFeature( QgsFeature& feature );
|
||||
|
||||
virtual void renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer = -1, bool selected = false, bool drawVertexMarker = false );
|
||||
|
||||
virtual void startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer );
|
||||
|
||||
virtual void stopRender( QgsRenderContext& context );
|
||||
|
||||
virtual QList<QString> usedAttributes();
|
||||
|
||||
virtual QgsFeatureRendererV2* clone() /Factory/;
|
||||
|
||||
virtual QgsSymbolV2List symbols();
|
||||
|
||||
//! store renderer info to XML element
|
||||
virtual QDomElement save( QDomDocument& doc );
|
||||
|
||||
/////
|
||||
|
||||
//! return the total number of rules
|
||||
int ruleCount();
|
||||
//! get reference to rule at index (valid indexes: 0...count-1)
|
||||
QgsRuleBasedRendererV2::Rule& ruleAt( int index );
|
||||
//! add rule to the end of the list of rules
|
||||
void addRule( const QgsRuleBasedRendererV2::Rule& rule );
|
||||
//! insert rule to a specific position of the list of rules
|
||||
void insertRule( int index, const QgsRuleBasedRendererV2::Rule& rule );
|
||||
//! modify the rule at a specific position of the list of rules
|
||||
void updateRuleAt( int index, const 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 );
|
||||
//! 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 );
|
||||
//! 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 );
|
||||
|
||||
};
|
||||
|
||||
|
||||
//////////
|
||||
|
||||
class QgsSymbolLayerV2
|
||||
@ -663,6 +760,8 @@ public:
|
||||
|
||||
typedef QMap<QString, QString> QgsStringMap;
|
||||
|
||||
typedef QMap<int, QgsField> QgsFieldMap;
|
||||
|
||||
//////////
|
||||
|
||||
class QgsSymbolLayerV2Widget /External/;
|
||||
|
@ -32,6 +32,7 @@ SET(QGIS_CORE_SRCS
|
||||
symbology-ng/qgssinglesymbolrendererv2.cpp
|
||||
symbology-ng/qgscategorizedsymbolrendererv2.cpp
|
||||
symbology-ng/qgsgraduatedsymbolrendererv2.cpp
|
||||
symbology-ng/qgsrulebasedrendererv2.cpp
|
||||
symbology-ng/qgsvectorcolorrampv2.cpp
|
||||
symbology-ng/qgsstylev2.cpp
|
||||
symbology-ng/qgssymbologyv2conversion.cpp
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "qgssinglesymbolrendererv2.h"
|
||||
#include "qgscategorizedsymbolrendererv2.h"
|
||||
#include "qgsgraduatedsymbolrendererv2.h"
|
||||
|
||||
#include "qgsrulebasedrendererv2.h"
|
||||
|
||||
QgsRendererV2Registry* QgsRendererV2Registry::mInstance = NULL;
|
||||
|
||||
@ -20,6 +20,10 @@ QgsRendererV2Registry::QgsRendererV2Registry()
|
||||
addRenderer( new QgsRendererV2Metadata( "graduatedSymbol",
|
||||
QObject::tr( "Graduated" ),
|
||||
QgsGraduatedSymbolRendererV2::create ) );
|
||||
|
||||
addRenderer( new QgsRendererV2Metadata( "RuleRenderer",
|
||||
QObject::tr( "Rule-based" ),
|
||||
QgsRuleBasedRendererV2::create ) );
|
||||
}
|
||||
|
||||
QgsRendererV2Registry::~QgsRendererV2Registry()
|
||||
|
368
src/core/symbology-ng/qgsrulebasedrendererv2.cpp
Normal file
368
src/core/symbology-ng/qgsrulebasedrendererv2.cpp
Normal file
@ -0,0 +1,368 @@
|
||||
/***************************************************************************
|
||||
qgsrulebasedrendererv2.cpp - Rule-based renderer (symbology-ng)
|
||||
---------------------
|
||||
begin : May 2010
|
||||
copyright : (C) 2010 by Martin Dobias
|
||||
email : wonder.sk at gmail.com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsrulebasedrendererv2.h"
|
||||
|
||||
#include "qgssearchtreenode.h"
|
||||
#include "qgssymbollayerv2utils.h"
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgslogger.h"
|
||||
|
||||
#include <QSet>
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
|
||||
|
||||
|
||||
QgsRuleBasedRendererV2::Rule::Rule( QgsSymbolV2* symbol, int scaleMinDenom, int scaleMaxDenom, QString filterExp )
|
||||
: mSymbol( symbol ),
|
||||
mScaleMinDenom( scaleMinDenom ), mScaleMaxDenom( scaleMaxDenom ),
|
||||
mFilterExp( filterExp )
|
||||
{
|
||||
initFilter();
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2::Rule::Rule( const QgsRuleBasedRendererV2::Rule& other )
|
||||
: mSymbol( NULL )
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2::Rule::~Rule()
|
||||
{
|
||||
delete mSymbol;
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2::Rule::initFilter()
|
||||
{
|
||||
if ( !mFilterExp.isEmpty() )
|
||||
{
|
||||
mFilterParsed.setString( mFilterExp );
|
||||
mFilterTree = mFilterParsed.tree(); // may be NULL if there's no input
|
||||
}
|
||||
else
|
||||
{
|
||||
mFilterTree = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
QString QgsRuleBasedRendererV2::Rule::dump() const
|
||||
{
|
||||
return QString( "RULE - scale [%1,%2] - filter %3 - symbol %4" )
|
||||
.arg( mScaleMinDenom ).arg( mScaleMaxDenom )
|
||||
.arg( mFilterExp ).arg( mSymbol->dump() );
|
||||
|
||||
}
|
||||
|
||||
QStringList QgsRuleBasedRendererV2::Rule::needsFields() const
|
||||
{
|
||||
if ( ! mFilterTree )
|
||||
return QStringList();
|
||||
|
||||
return mFilterTree->referencedColumns();
|
||||
}
|
||||
|
||||
bool QgsRuleBasedRendererV2::Rule::isFilterOK( const QgsFieldMap& fields, QgsFeature& f ) const
|
||||
{
|
||||
if ( ! mFilterTree )
|
||||
return true;
|
||||
|
||||
bool res = mFilterTree->checkAgainst( fields, f.attributeMap() );
|
||||
//print "is_ok", res, feature.id(), feature.attributeMap()
|
||||
return res;
|
||||
}
|
||||
|
||||
bool QgsRuleBasedRendererV2::Rule::isScaleOK( double scale ) const
|
||||
{
|
||||
if ( mScaleMinDenom == 0 && mScaleMaxDenom == 0 )
|
||||
return true;
|
||||
if ( mScaleMinDenom != 0 && mScaleMinDenom > scale )
|
||||
return false;
|
||||
if ( mScaleMaxDenom != 0 && mScaleMaxDenom < scale )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2::Rule& QgsRuleBasedRendererV2::Rule::operator=( const QgsRuleBasedRendererV2::Rule & other )
|
||||
{
|
||||
if ( this != &other )
|
||||
{
|
||||
delete mSymbol;
|
||||
mSymbol = other.mSymbol->clone();
|
||||
|
||||
mScaleMinDenom = other.mScaleMinDenom;
|
||||
mScaleMaxDenom = other.mScaleMaxDenom;
|
||||
mFilterExp = other.mFilterExp;
|
||||
initFilter();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
|
||||
QgsRuleBasedRendererV2::QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol )
|
||||
: QgsFeatureRendererV2( "RuleRenderer" )
|
||||
{
|
||||
mDefaultSymbol = defaultSymbol;
|
||||
|
||||
// add the default rule
|
||||
mRules << Rule( defaultSymbol->clone() );
|
||||
}
|
||||
|
||||
|
||||
QgsSymbolV2* QgsRuleBasedRendererV2::symbolForFeature( QgsFeature& feature )
|
||||
{
|
||||
return mCurrentSymbol;
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2::renderFeature( QgsFeature& feature,
|
||||
QgsRenderContext& context,
|
||||
int layer,
|
||||
bool selected,
|
||||
bool drawVertexMarker )
|
||||
{
|
||||
for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
|
||||
{
|
||||
Rule* rule = *it;
|
||||
if ( rule->isFilterOK( mCurrentFields, feature ) )
|
||||
{
|
||||
mCurrentSymbol = rule->symbol();
|
||||
// will ask for mCurrentSymbol
|
||||
QgsFeatureRendererV2::renderFeature( feature, context, layer, selected, drawVertexMarker );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QgsRuleBasedRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
|
||||
{
|
||||
double currentScale = context.rendererScale();
|
||||
// filter out rules which are not compatible 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 );
|
||||
}
|
||||
|
||||
mCurrentFields = vlayer->pendingFields();
|
||||
|
||||
for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
|
||||
{
|
||||
Rule* rule = *it;
|
||||
rule->symbol()->startRender( context );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2::stopRender( QgsRenderContext& context )
|
||||
{
|
||||
for ( QList<Rule*>::iterator it = mCurrentRules.begin(); it != mCurrentRules.end(); ++it )
|
||||
{
|
||||
Rule* rule = *it;
|
||||
rule->symbol()->stopRender( context );
|
||||
}
|
||||
|
||||
mCurrentRules.clear();
|
||||
mCurrentFields.clear();
|
||||
}
|
||||
|
||||
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() );
|
||||
}
|
||||
return attrs.values();
|
||||
}
|
||||
|
||||
QgsFeatureRendererV2* QgsRuleBasedRendererV2::clone()
|
||||
{
|
||||
QgsSymbolV2* s = mDefaultSymbol->clone();
|
||||
QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( s );
|
||||
r->mRules = mRules;
|
||||
return r;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
QDomElement QgsRuleBasedRendererV2::save( QDomDocument& doc )
|
||||
{
|
||||
QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
|
||||
rendererElem.setAttribute( "type", "RuleRenderer" );
|
||||
|
||||
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() );
|
||||
rulesElem.appendChild( ruleElem );
|
||||
}
|
||||
rendererElem.appendChild( rulesElem );
|
||||
|
||||
QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
|
||||
rendererElem.appendChild( symbolsElem );
|
||||
|
||||
return rendererElem;
|
||||
}
|
||||
|
||||
|
||||
QgsFeatureRendererV2* QgsRuleBasedRendererV2::create( QDomElement& element )
|
||||
{
|
||||
// load symbols
|
||||
QDomElement symbolsElem = element.firstChildElement( "symbols" );
|
||||
if ( symbolsElem.isNull() )
|
||||
return NULL;
|
||||
|
||||
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" );
|
||||
int scaleMinDenom = ruleElem.attribute( "scalemindenom", "0" ).toInt();
|
||||
int scaleMaxDenom = ruleElem.attribute( "scalemaxdenom", "0" ).toInt();
|
||||
r->mRules.append( Rule( symbolMap.take( symbolIdx ), scaleMinDenom, scaleMaxDenom, filterExp ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( "symbol for rule " + symbolIdx + " not found! (skipping)" );
|
||||
}
|
||||
ruleElem = ruleElem.nextSiblingElement( "rule" );
|
||||
}
|
||||
|
||||
// delete symbols if there are any more
|
||||
QgsSymbolLayerV2Utils::clearSymbolMap( symbolMap );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int QgsRuleBasedRendererV2::ruleCount()
|
||||
{
|
||||
return mRules.count();
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2::Rule& QgsRuleBasedRendererV2::ruleAt( int index )
|
||||
{
|
||||
return mRules[index];
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2::addRule( const QgsRuleBasedRendererV2::Rule& rule )
|
||||
{
|
||||
mRules.append( rule );
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2::insertRule( int index, const QgsRuleBasedRendererV2::Rule& rule )
|
||||
{
|
||||
mRules.insert( index, rule );
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2::updateRuleAt( int index, const QgsRuleBasedRendererV2::Rule& rule )
|
||||
{
|
||||
mRules[index] = rule;
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2::removeRuleAt( int index )
|
||||
{
|
||||
mRules.removeAt( index );
|
||||
}
|
||||
|
||||
#include "qgscategorizedsymbolrendererv2.h"
|
||||
#include "qgsgraduatedsymbolrendererv2.h"
|
||||
|
||||
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2::refineRuleCategories( QgsRuleBasedRendererV2::Rule& initialRule, QgsCategorizedSymbolRendererV2* r )
|
||||
{
|
||||
QList<Rule> rules;
|
||||
foreach( const QgsRendererCategoryV2& cat, r->categories() )
|
||||
{
|
||||
QString newfilter = QString( "%1 = '%2'" ).arg( r->classAttribute() ).arg( cat.value().toString() );
|
||||
QString filter = initialRule.filterExpression();
|
||||
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 ) );
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2::refineRuleRanges( QgsRuleBasedRendererV2::Rule& initialRule, QgsGraduatedSymbolRendererV2* r )
|
||||
{
|
||||
QList<Rule> 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();
|
||||
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 ) );
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2::refineRuleScales( QgsRuleBasedRendererV2::Rule& initialRule, QList<int> scales )
|
||||
{
|
||||
QList<Rule> rules;
|
||||
int oldScale = 0;
|
||||
foreach( int scale, scales )
|
||||
{
|
||||
rules.append( Rule( initialRule.symbol()->clone(), oldScale, scale, initialRule.filterExpression() ) );
|
||||
oldScale = scale;
|
||||
}
|
||||
// last rule
|
||||
rules.append( Rule( initialRule.symbol()->clone(), oldScale, 0, initialRule.filterExpression() ) );
|
||||
return rules;
|
||||
}
|
141
src/core/symbology-ng/qgsrulebasedrendererv2.h
Normal file
141
src/core/symbology-ng/qgsrulebasedrendererv2.h
Normal file
@ -0,0 +1,141 @@
|
||||
/***************************************************************************
|
||||
qgsrulebasedrendererv2.h - Rule-based renderer (symbology-ng)
|
||||
---------------------
|
||||
begin : May 2010
|
||||
copyright : (C) 2010 by Martin Dobias
|
||||
email : wonder.sk at gmail.com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSRULEBASEDRENDERERV2_H
|
||||
#define QGSRULEBASEDRENDERERV2_H
|
||||
|
||||
#include "qgsfield.h"
|
||||
#include "qgssearchstring.h"
|
||||
|
||||
#include "qgsrendererv2.h"
|
||||
|
||||
class QgsCategorizedSymbolRendererV2;
|
||||
class QgsGraduatedSymbolRendererV2;
|
||||
|
||||
/**
|
||||
When drawing a vector layer with rule-based renderer, it goes through
|
||||
the rules and draws features with symbols from rules that match.
|
||||
*/
|
||||
class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
This class keeps data about a rules for rule-based renderer.
|
||||
A rule consists of a symbol, filter expression and range of scales.
|
||||
If filter is empty, it matches all features.
|
||||
If scale range has both values zero, it matches all scales.
|
||||
If one of the min/max scale denominators is zero, there is no lower/upper bound for scales.
|
||||
A rule matches if both filter and scale range match.
|
||||
*/
|
||||
class Rule
|
||||
{
|
||||
public:
|
||||
//! Constructor takes ownership of the symbol
|
||||
Rule( QgsSymbolV2* symbol, int scaleMinDenom = 0, int scaleMaxDenom = 0, QString filterExp = QString() );
|
||||
Rule( const Rule& other );
|
||||
~Rule();
|
||||
QString dump() const;
|
||||
QStringList needsFields() const;
|
||||
bool isFilterOK( const QgsFieldMap& fields, QgsFeature& f ) const;
|
||||
bool isScaleOK( double scale ) const;
|
||||
|
||||
QgsSymbolV2* symbol() { return mSymbol; }
|
||||
bool dependsOnScale() const { return mScaleMinDenom != 0 || mScaleMaxDenom != 0; }
|
||||
int scaleMinDenom() const { return mScaleMinDenom; }
|
||||
int scaleMaxDenom() const { return mScaleMaxDenom; }
|
||||
QString filterExpression() const { return mFilterExp; }
|
||||
|
||||
void setScaleMinDenom( int scaleMinDenom ) { mScaleMinDenom = scaleMinDenom; }
|
||||
void setScaleMaxDenom( int scaleMaxDenom ) { mScaleMaxDenom = scaleMaxDenom; }
|
||||
void setFilterExpression( QString filterExp ) { mFilterExp = filterExp; initFilter(); }
|
||||
|
||||
Rule& operator=( const Rule& other );
|
||||
|
||||
protected:
|
||||
|
||||
void initFilter();
|
||||
|
||||
QgsSymbolV2* mSymbol;
|
||||
int mScaleMinDenom, mScaleMaxDenom;
|
||||
QString mFilterExp;
|
||||
|
||||
// temporary
|
||||
QgsSearchString mFilterParsed;
|
||||
QgsSearchTreeNode* mFilterTree;
|
||||
};
|
||||
|
||||
/////
|
||||
|
||||
static QgsFeatureRendererV2* create( QDomElement& element );
|
||||
|
||||
//! Constructor. Takes ownership of the defult symbol.
|
||||
QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol );
|
||||
|
||||
//! return symbol for current feature. Should not be used individually: there could be more symbols for a feature
|
||||
virtual QgsSymbolV2* symbolForFeature( QgsFeature& feature );
|
||||
|
||||
virtual void renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer = -1, bool selected = false, bool drawVertexMarker = false );
|
||||
|
||||
virtual void startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer );
|
||||
|
||||
virtual void stopRender( QgsRenderContext& context );
|
||||
|
||||
virtual QList<QString> usedAttributes();
|
||||
|
||||
virtual QgsFeatureRendererV2* clone();
|
||||
|
||||
virtual QgsSymbolV2List symbols();
|
||||
|
||||
//! store renderer info to XML element
|
||||
virtual QDomElement save( QDomDocument& doc );
|
||||
|
||||
/////
|
||||
|
||||
//! 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 );
|
||||
//! 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<Rule> 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 );
|
||||
//! 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 );
|
||||
|
||||
protected:
|
||||
//! the list of rules
|
||||
QList<Rule> mRules;
|
||||
//! the default symbol, used for the first rule with no filter
|
||||
QgsSymbolV2* mDefaultSymbol;
|
||||
|
||||
// temporary
|
||||
QList<Rule*> mCurrentRules;
|
||||
QgsFieldMap mCurrentFields;
|
||||
QgsSymbolV2* mCurrentSymbol;
|
||||
};
|
||||
|
||||
#endif // QGSRULEBASEDRENDERERV2_H
|
@ -10,6 +10,7 @@ symbology-ng/qgsrendererv2widget.cpp
|
||||
symbology-ng/qgssinglesymbolrendererv2widget.cpp
|
||||
symbology-ng/qgscategorizedsymbolrendererv2widget.cpp
|
||||
symbology-ng/qgsgraduatedsymbolrendererv2widget.cpp
|
||||
symbology-ng/qgsrulebasedrendererv2widget.cpp
|
||||
symbology-ng/qgsrendererv2propertiesdialog.cpp
|
||||
symbology-ng/qgsstylev2managerdialog.cpp
|
||||
symbology-ng/qgssymbollevelsv2dialog.cpp
|
||||
@ -63,6 +64,7 @@ symbology-ng/qgssymbolv2propertiesdialog.h
|
||||
symbology-ng/qgssinglesymbolrendererv2widget.h
|
||||
symbology-ng/qgscategorizedsymbolrendererv2widget.h
|
||||
symbology-ng/qgsgraduatedsymbolrendererv2widget.h
|
||||
symbology-ng/qgsrulebasedrendererv2widget.h
|
||||
symbology-ng/qgsrendererv2propertiesdialog.h
|
||||
symbology-ng/qgsstylev2managerdialog.h
|
||||
symbology-ng/qgssymbollevelsv2dialog.h
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "qgssinglesymbolrendererv2widget.h"
|
||||
#include "qgscategorizedsymbolrendererv2widget.h"
|
||||
#include "qgsgraduatedsymbolrendererv2widget.h"
|
||||
#include "qgsrulebasedrendererv2widget.h"
|
||||
|
||||
#include "qgssymbollevelsv2dialog.h"
|
||||
|
||||
@ -18,7 +19,7 @@
|
||||
#include <QKeyEvent>
|
||||
#include <QMessageBox>
|
||||
|
||||
static bool _initRenderer( QString name, QgsRendererV2WidgetFunc f, QString iconName )
|
||||
static bool _initRenderer( QString name, QgsRendererV2WidgetFunc f, QString iconName = QString() )
|
||||
{
|
||||
QgsRendererV2Registry* reg = QgsRendererV2Registry::instance();
|
||||
QgsRendererV2AbstractMetadata* am = reg->rendererMetadata( name );
|
||||
@ -30,10 +31,13 @@ static bool _initRenderer( QString name, QgsRendererV2WidgetFunc f, QString icon
|
||||
|
||||
m->setWidgetFunction( f );
|
||||
|
||||
QString iconPath = QgsApplication::defaultThemePath() + iconName;
|
||||
QPixmap pix;
|
||||
if ( pix.load( iconPath, "png" ) )
|
||||
m->setIcon( pix );
|
||||
if ( !iconName.isEmpty() )
|
||||
{
|
||||
QString iconPath = QgsApplication::defaultThemePath() + iconName;
|
||||
QPixmap pix;
|
||||
if ( pix.load( iconPath, "png" ) )
|
||||
m->setIcon( pix );
|
||||
}
|
||||
|
||||
QgsDebugMsg( "Set for " + name );
|
||||
return true;
|
||||
@ -48,6 +52,7 @@ static void _initRendererWidgetFunctions()
|
||||
_initRenderer( "singleSymbol", QgsSingleSymbolRendererV2Widget::create, "rendererSingleSymbol.png" );
|
||||
_initRenderer( "categorizedSymbol", QgsCategorizedSymbolRendererV2Widget::create, "rendererCategorizedSymbol.png" );
|
||||
_initRenderer( "graduatedSymbol", QgsGraduatedSymbolRendererV2Widget::create, "rendererGraduatedSymbol.png" );
|
||||
_initRenderer( "RuleRenderer", QgsRuleBasedRendererV2Widget::create );
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
|
493
src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp
Normal file
493
src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp
Normal file
@ -0,0 +1,493 @@
|
||||
/***************************************************************************
|
||||
qgsrulebasedrendererv2widget.cpp - Settings widget for rule-based renderer
|
||||
---------------------
|
||||
begin : May 2010
|
||||
copyright : (C) 2010 by Martin Dobias
|
||||
email : wonder.sk at gmail.com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsrulebasedrendererv2widget.h"
|
||||
|
||||
#include "qgsrulebasedrendererv2.h"
|
||||
#include "qgssymbollayerv2utils.h"
|
||||
#include "qgssymbolv2.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgssearchtreenode.h"
|
||||
#include "qgssymbolv2selectordialog.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QVBoxLayout>
|
||||
#include <QMessageBox>
|
||||
|
||||
QgsRendererV2Widget* QgsRuleBasedRendererV2Widget::create( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer )
|
||||
{
|
||||
return new QgsRuleBasedRendererV2Widget( layer, style, renderer );
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2Widget::QgsRuleBasedRendererV2Widget( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer )
|
||||
: QgsRendererV2Widget( layer, style )
|
||||
{
|
||||
|
||||
// try to recognize the previous renderer
|
||||
// (null renderer means "no previous renderer")
|
||||
if ( !renderer || renderer->type() != "RuleRenderer" )
|
||||
{
|
||||
// we're not going to use it - so let's delete the renderer
|
||||
delete renderer;
|
||||
|
||||
// some default options
|
||||
QgsSymbolV2* symbol = QgsSymbolV2::defaultSymbol( mLayer->geometryType() );
|
||||
|
||||
mRenderer = new QgsRuleBasedRendererV2( symbol );
|
||||
}
|
||||
else
|
||||
{
|
||||
mRenderer = static_cast<QgsRuleBasedRendererV2*>( renderer );
|
||||
}
|
||||
|
||||
setupUi( this );
|
||||
|
||||
treeRules->setRenderer( mRenderer );
|
||||
|
||||
mRefineMenu = new QMenu( btnRefineRule );
|
||||
mRefineMenu->addAction( tr( "Add scales" ), this, SLOT( refineRuleScales() ) );
|
||||
mRefineMenu->addAction( tr( "Add categories" ), this, SLOT( refineRuleCategories() ) );
|
||||
mRefineMenu->addAction( tr( "Add ranges" ), this, SLOT( refineRuleRanges() ) );
|
||||
btnRefineRule->setMenu( mRefineMenu );
|
||||
|
||||
btnAddRule->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.png" ) ) );
|
||||
btnEditRule->setIcon( QIcon( QgsApplication::iconPath( "symbologyEdit.png" ) ) );
|
||||
btnRemoveRule->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.png" ) ) );
|
||||
|
||||
connect( treeRules, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( editRule() ) );
|
||||
|
||||
connect( btnAddRule, SIGNAL( clicked() ), this, SLOT( addRule() ) );
|
||||
connect( btnEditRule, SIGNAL( clicked() ), this, SLOT( editRule() ) );
|
||||
connect( btnRemoveRule, SIGNAL( clicked() ), this, SLOT( removeRule() ) );
|
||||
|
||||
connect( radNoGrouping, SIGNAL( clicked() ), this, SLOT( setGrouping() ) );
|
||||
connect( radGroupFilter, SIGNAL( clicked() ), this, SLOT( setGrouping() ) );
|
||||
connect( radGroupScale, SIGNAL( clicked() ), this, SLOT( setGrouping() ) );
|
||||
|
||||
treeRules->populateRules();
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2Widget::~QgsRuleBasedRendererV2Widget()
|
||||
{
|
||||
delete mRenderer;
|
||||
}
|
||||
|
||||
QgsFeatureRendererV2* QgsRuleBasedRendererV2Widget::renderer()
|
||||
{
|
||||
return mRenderer;
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::setGrouping()
|
||||
{
|
||||
QObject* origin = sender();
|
||||
if ( origin == radNoGrouping )
|
||||
treeRules->setGrouping( QgsRendererRulesTreeWidget::NoGrouping );
|
||||
else if ( origin == radGroupFilter )
|
||||
treeRules->setGrouping( QgsRendererRulesTreeWidget::GroupingByFilter );
|
||||
else if ( origin == radGroupScale )
|
||||
treeRules->setGrouping( QgsRendererRulesTreeWidget::GroupingByScale );
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::addRule()
|
||||
{
|
||||
QgsRuleBasedRendererV2::Rule newrule( QgsSymbolV2::defaultSymbol( mLayer->geometryType() ) );
|
||||
|
||||
QgsRendererRulePropsDialog dlg( newrule, mLayer, mStyle );
|
||||
if ( dlg.exec() )
|
||||
{
|
||||
// add rule
|
||||
dlg.updateRuleFromGui();
|
||||
mRenderer->addRule( dlg.rule() );
|
||||
treeRules->populateRules();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::editRule()
|
||||
{
|
||||
QTreeWidgetItem * item = treeRules->currentItem();
|
||||
if ( ! item ) return;
|
||||
|
||||
int rule_index = item->data( 0, Qt::UserRole + 1 ).toInt();
|
||||
if ( rule_index < 0 )
|
||||
{
|
||||
QMessageBox::information( this, tr( "Edit rule" ), tr( "Groups of rules cannot be edited." ) );
|
||||
return;
|
||||
}
|
||||
QgsRuleBasedRendererV2::Rule& rule = mRenderer->ruleAt( rule_index );
|
||||
|
||||
QgsRendererRulePropsDialog dlg( rule, mLayer, mStyle );
|
||||
if ( dlg.exec() )
|
||||
{
|
||||
// update rule
|
||||
dlg.updateRuleFromGui();
|
||||
mRenderer->updateRuleAt( rule_index, dlg.rule() );
|
||||
|
||||
treeRules->populateRules();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::removeRule()
|
||||
{
|
||||
QTreeWidgetItem * item = treeRules->currentItem();
|
||||
if ( ! item ) return;
|
||||
|
||||
int rule_index = item->data( 0, Qt::UserRole + 1 ).toInt();
|
||||
if ( rule_index < 0 )
|
||||
{
|
||||
QList<int> rule_indexes;
|
||||
// this is a group
|
||||
for ( int i = 0; i < item->childCount(); i++ )
|
||||
{
|
||||
int idx = item->child( i )->data( 0, Qt::UserRole + 1 ).toInt();
|
||||
rule_indexes.append( idx );
|
||||
}
|
||||
// delete in decreasing order to avoid shifting of indexes
|
||||
qSort( rule_indexes.begin(), rule_indexes.end(), qGreater<int>() );
|
||||
foreach( int idx, rule_indexes )
|
||||
mRenderer->removeRuleAt( idx );
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a rule
|
||||
mRenderer->removeRuleAt( rule_index );
|
||||
}
|
||||
|
||||
treeRules->populateRules();
|
||||
}
|
||||
|
||||
|
||||
#include "qgscategorizedsymbolrendererv2.h"
|
||||
#include "qgscategorizedsymbolrendererv2widget.h"
|
||||
#include "qgsgraduatedsymbolrendererv2.h"
|
||||
#include "qgsgraduatedsymbolrendererv2widget.h"
|
||||
#include <QDialogButtonBox>
|
||||
#include <QInputDialog>
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::refineRule( int type )
|
||||
{
|
||||
QTreeWidgetItem * item = treeRules->currentItem();
|
||||
if ( ! item ) return;
|
||||
|
||||
int rule_index = item->data( 0, Qt::UserRole + 1 ).toInt();
|
||||
if ( rule_index < 0 ) return;
|
||||
|
||||
QgsRuleBasedRendererV2::Rule& initialRule = mRenderer->ruleAt( rule_index );
|
||||
|
||||
|
||||
QList<QgsRuleBasedRendererV2::Rule> refinedRules;
|
||||
if ( type == 0 ) // categories
|
||||
refinedRules = refineRuleCategoriesGui( initialRule );
|
||||
else if ( type == 1 ) // ranges
|
||||
refinedRules = refineRuleRangesGui( initialRule );
|
||||
else // scales
|
||||
refinedRules = refineRuleScalesGui( initialRule );
|
||||
|
||||
if ( refinedRules.count() == 0 )
|
||||
return;
|
||||
|
||||
// delete original rule
|
||||
mRenderer->removeRuleAt( rule_index );
|
||||
|
||||
// add new rules
|
||||
for ( int i = 0; i < refinedRules.count(); i++ )
|
||||
{
|
||||
mRenderer->insertRule( rule_index + i, refinedRules.at( i ) );
|
||||
}
|
||||
|
||||
treeRules->populateRules();
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::refineRuleCategories()
|
||||
{
|
||||
refineRule( 0 );
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::refineRuleRanges()
|
||||
{
|
||||
refineRule( 1 );
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::refineRuleScales()
|
||||
{
|
||||
refineRule( 2 );
|
||||
}
|
||||
|
||||
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2Widget::refineRuleCategoriesGui( QgsRuleBasedRendererV2::Rule& initialRule )
|
||||
{
|
||||
QDialog dlg;
|
||||
dlg.setWindowTitle( tr( "Refine a rule to categories" ) );
|
||||
QVBoxLayout* l = new QVBoxLayout();
|
||||
QgsCategorizedSymbolRendererV2Widget* w = new QgsCategorizedSymbolRendererV2Widget( mLayer, mStyle, NULL );
|
||||
l->addWidget( w );
|
||||
QDialogButtonBox* bb = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
|
||||
l->addWidget( bb );
|
||||
connect( bb, SIGNAL( accepted() ), &dlg, SLOT( accept() ) );
|
||||
connect( bb, SIGNAL( rejected() ), &dlg, SLOT( reject() ) );
|
||||
dlg.setLayout( l );
|
||||
|
||||
if ( !dlg.exec() )
|
||||
return QList<QgsRuleBasedRendererV2::Rule>();
|
||||
|
||||
// create new rules
|
||||
QgsCategorizedSymbolRendererV2* r = static_cast<QgsCategorizedSymbolRendererV2*>( w->renderer() );
|
||||
return QgsRuleBasedRendererV2::refineRuleCategories( initialRule, r );
|
||||
}
|
||||
|
||||
|
||||
QList<QgsRuleBasedRendererV2::Rule> QgsRuleBasedRendererV2Widget::refineRuleRangesGui( QgsRuleBasedRendererV2::Rule& initialRule )
|
||||
{
|
||||
QDialog dlg;
|
||||
dlg.setWindowTitle( tr( "Refine a rule to ranges" ) );
|
||||
QVBoxLayout* l = new QVBoxLayout();
|
||||
QgsGraduatedSymbolRendererV2Widget* w = new QgsGraduatedSymbolRendererV2Widget( mLayer, mStyle, NULL );
|
||||
l->addWidget( w );
|
||||
QDialogButtonBox* bb = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
|
||||
l->addWidget( bb );
|
||||
connect( bb, SIGNAL( accepted() ), &dlg, SLOT( accept() ) );
|
||||
connect( bb, SIGNAL( rejected() ), &dlg, SLOT( reject() ) );
|
||||
dlg.setLayout( l );
|
||||
|
||||
if ( !dlg.exec() )
|
||||
return QList<QgsRuleBasedRendererV2::Rule>();
|
||||
|
||||
// create new rules
|
||||
QgsGraduatedSymbolRendererV2* r = static_cast<QgsGraduatedSymbolRendererV2*>( w->renderer() );
|
||||
return QgsRuleBasedRendererV2::refineRuleRanges( initialRule, r );
|
||||
}
|
||||
|
||||
QList<QgsRuleBasedRendererV2::Rule> 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>();
|
||||
|
||||
QList<int> scales;
|
||||
bool ok;
|
||||
foreach( QString item, txt.split( ',' ) )
|
||||
{
|
||||
int scale = item.toInt( &ok );
|
||||
if ( ok )
|
||||
scales.append( scale );
|
||||
else
|
||||
QMessageBox::information( this, tr( "Error" ), QString( tr( "\"%1\" is not valid scale denominator, ignoring it." ) ).arg( item ) );
|
||||
}
|
||||
|
||||
return QgsRuleBasedRendererV2::refineRuleScales( initialRule, scales );
|
||||
}
|
||||
|
||||
|
||||
///////////
|
||||
|
||||
QgsRendererRulePropsDialog::QgsRendererRulePropsDialog( const QgsRuleBasedRendererV2::Rule& rule, QgsVectorLayer* layer, QgsStyleV2* style )
|
||||
: mRule( rule ), mLayer( layer )
|
||||
{
|
||||
setupUi( this );
|
||||
|
||||
editFilter->setText( mRule.filterExpression() );
|
||||
|
||||
if ( mRule.dependsOnScale() )
|
||||
{
|
||||
groupScale->setChecked( true );
|
||||
spinMinScale->setValue( rule.scaleMinDenom() );
|
||||
spinMaxScale->setValue( rule.scaleMaxDenom() );
|
||||
}
|
||||
|
||||
QgsSymbolV2SelectorDialog* symbolSel = new QgsSymbolV2SelectorDialog( mRule.symbol(), style, this, true );
|
||||
QVBoxLayout* l = new QVBoxLayout;
|
||||
l->addWidget( symbolSel );
|
||||
groupSymbol->setLayout( l );
|
||||
|
||||
connect( btnTestFilter, SIGNAL( clicked() ), this, SLOT( testFilter() ) );
|
||||
}
|
||||
|
||||
void QgsRendererRulePropsDialog::testFilter()
|
||||
{
|
||||
QgsSearchString filterParsed;
|
||||
if ( ! filterParsed.setString( editFilter->text() ) )
|
||||
{
|
||||
QMessageBox::critical( this, tr( "Error" ), tr( "Filter expression parsing error:\n" ) + filterParsed.parserErrorMsg() );
|
||||
return;
|
||||
}
|
||||
|
||||
QgsSearchTreeNode* tree = filterParsed.tree();
|
||||
if ( ! tree )
|
||||
{
|
||||
QMessageBox::critical( this, tr( "Error" ), tr( "Filter is empty" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
QApplication::setOverrideCursor( Qt::WaitCursor );
|
||||
|
||||
const QgsFieldMap& fields = mLayer->pendingFields();
|
||||
mLayer->select( fields.keys(), QgsRectangle(), false );
|
||||
|
||||
int count = 0;
|
||||
QgsFeature f;
|
||||
while ( mLayer->nextFeature( f ) )
|
||||
{
|
||||
if ( tree->checkAgainst( fields, f.attributeMap() ) )
|
||||
count++;
|
||||
if ( tree->hasError() )
|
||||
break;
|
||||
}
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
QMessageBox::information( this, tr( "Filter" ), tr( "Filter returned %1 features" ).arg( count ) );
|
||||
}
|
||||
|
||||
void QgsRendererRulePropsDialog::updateRuleFromGui()
|
||||
{
|
||||
mRule.setFilterExpression( editFilter->text() );
|
||||
mRule.setScaleMinDenom( groupScale->isChecked() ? spinMinScale->value() : 0 );
|
||||
mRule.setScaleMaxDenom( groupScale->isChecked() ? spinMaxScale->value() : 0 );
|
||||
}
|
||||
|
||||
////////
|
||||
|
||||
QgsRendererRulesTreeWidget::QgsRendererRulesTreeWidget( QWidget* parent )
|
||||
: QTreeWidget( parent ), mR( NULL ), mGrouping( NoGrouping )
|
||||
{
|
||||
setSelectionMode( QAbstractItemView::SingleSelection );
|
||||
/*
|
||||
setDragEnabled(true);
|
||||
viewport()->setAcceptDrops(true);
|
||||
setDropIndicatorShown(true);
|
||||
setDragDropMode(QAbstractItemView::InternalMove);
|
||||
*/
|
||||
}
|
||||
|
||||
void QgsRendererRulesTreeWidget::setRenderer( QgsRuleBasedRendererV2* r )
|
||||
{
|
||||
mR = r;
|
||||
}
|
||||
|
||||
void QgsRendererRulesTreeWidget::setGrouping( Grouping g )
|
||||
{
|
||||
mGrouping = g;
|
||||
setRootIsDecorated( mGrouping != NoGrouping );
|
||||
populateRules();
|
||||
}
|
||||
|
||||
void QgsRendererRulesTreeWidget::populateRules()
|
||||
{
|
||||
if ( !mR ) return;
|
||||
|
||||
clear();
|
||||
if ( mGrouping == NoGrouping )
|
||||
populateRulesNoGrouping();
|
||||
else if ( mGrouping == GroupingByScale )
|
||||
populateRulesGroupByScale();
|
||||
else
|
||||
populateRulesGroupByFilter();
|
||||
}
|
||||
|
||||
void QgsRendererRulesTreeWidget::populateRulesNoGrouping()
|
||||
{
|
||||
QList<QTreeWidgetItem *> lst;
|
||||
for ( int i = 0; i < mR->ruleCount(); ++i )
|
||||
{
|
||||
QgsRuleBasedRendererV2::Rule& rule = mR->ruleAt( i );
|
||||
|
||||
QTreeWidgetItem* item = new QTreeWidgetItem;
|
||||
QString txt = rule.filterExpression();
|
||||
if ( txt.isEmpty() ) txt = tr( "(no filter)" );
|
||||
if ( rule.dependsOnScale() )
|
||||
{
|
||||
txt += QString( ", scale <1:%1, 1:%2>" ).arg( rule.scaleMinDenom() ).arg( rule.scaleMaxDenom() );
|
||||
}
|
||||
|
||||
item->setText( 0, txt );
|
||||
item->setData( 0, Qt::UserRole + 1, i );
|
||||
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule.symbol(), QSize( 16, 16 ) ) );
|
||||
|
||||
lst << item;
|
||||
}
|
||||
|
||||
addTopLevelItems( lst );
|
||||
}
|
||||
|
||||
void QgsRendererRulesTreeWidget::populateRulesGroupByScale()
|
||||
{
|
||||
QMap< QPair<int, int>, QTreeWidgetItem*> scale_items;
|
||||
|
||||
for ( int i = 0; i < mR->ruleCount(); ++i )
|
||||
{
|
||||
QgsRuleBasedRendererV2::Rule& rule = mR->ruleAt( i );
|
||||
|
||||
QPair<int, int> scale = qMakePair( rule.scaleMinDenom(), rule.scaleMaxDenom() );
|
||||
if ( ! scale_items.contains( scale ) )
|
||||
{
|
||||
QString txt;
|
||||
if ( rule.dependsOnScale() )
|
||||
txt = QString( "scale <1:%1, 1:%2>" ).arg( rule.scaleMinDenom() ).arg( rule.scaleMaxDenom() );
|
||||
else
|
||||
txt = "any scale";
|
||||
|
||||
QTreeWidgetItem* scale_item = new QTreeWidgetItem;
|
||||
scale_item->setText( 0, txt );
|
||||
scale_item->setData( 0, Qt::UserRole + 1, -2 );
|
||||
scale_item->setFlags( scale_item->flags() & ~Qt::ItemIsDragEnabled ); // groups cannot be dragged
|
||||
scale_items[scale] = scale_item;
|
||||
}
|
||||
|
||||
QString filter = rule.filterExpression();
|
||||
|
||||
QTreeWidgetItem* item = new QTreeWidgetItem( scale_items[scale] );
|
||||
item->setText( 0, filter.isEmpty() ? tr( "(no filter)" ) : filter );
|
||||
item->setData( 0, Qt::UserRole + 1, i );
|
||||
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule.symbol(), QSize( 16, 16 ) ) );
|
||||
}
|
||||
addTopLevelItems( scale_items.values() );
|
||||
}
|
||||
|
||||
void QgsRendererRulesTreeWidget::populateRulesGroupByFilter()
|
||||
{
|
||||
QMap<QString, QTreeWidgetItem *> filter_items;
|
||||
|
||||
for ( int i = 0; i < mR->ruleCount(); ++i )
|
||||
{
|
||||
QgsRuleBasedRendererV2::Rule& rule = mR->ruleAt( i );
|
||||
|
||||
QString filter = rule.filterExpression();
|
||||
if ( ! filter_items.contains( filter ) )
|
||||
{
|
||||
QTreeWidgetItem* filter_item = new QTreeWidgetItem;
|
||||
filter_item->setText( 0, filter.isEmpty() ? tr( "(no filter)" ) : filter );
|
||||
filter_item->setData( 0, Qt::UserRole + 1, -1 );
|
||||
filter_item->setFlags( filter_item->flags() & ~Qt::ItemIsDragEnabled ); // groups cannot be dragged
|
||||
filter_items[filter] = filter_item;
|
||||
}
|
||||
|
||||
QString txt;
|
||||
if ( rule.dependsOnScale() )
|
||||
txt = QString( "scale <1:%1, 1:%2>" ).arg( rule.scaleMinDenom() ).arg( rule.scaleMaxDenom() );
|
||||
else
|
||||
txt = "any scale";
|
||||
|
||||
QTreeWidgetItem* item = new QTreeWidgetItem( filter_items[filter] );
|
||||
item->setText( 0, txt );
|
||||
item->setData( 0, Qt::UserRole + 1, i );
|
||||
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule.symbol(), QSize( 16, 16 ) ) );
|
||||
|
||||
}
|
||||
addTopLevelItems( filter_items.values() );
|
||||
}
|
117
src/gui/symbology-ng/qgsrulebasedrendererv2widget.h
Normal file
117
src/gui/symbology-ng/qgsrulebasedrendererv2widget.h
Normal file
@ -0,0 +1,117 @@
|
||||
/***************************************************************************
|
||||
qgsrulebasedrendererv2widget.h - Settings widget for rule-based renderer
|
||||
---------------------
|
||||
begin : May 2010
|
||||
copyright : (C) 2010 by Martin Dobias
|
||||
email : wonder.sk at gmail.com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSRULEBASEDRENDERERV2WIDGET_H
|
||||
#define QGSRULEBASEDRENDERERV2WIDGET_H
|
||||
|
||||
#include "qgsrendererv2widget.h"
|
||||
|
||||
#include "qgsrulebasedrendererv2.h"
|
||||
class QMenu;
|
||||
|
||||
///////
|
||||
|
||||
#include <QTreeWidget>
|
||||
|
||||
class QgsRendererRulesTreeWidget : public QTreeWidget
|
||||
{
|
||||
public:
|
||||
QgsRendererRulesTreeWidget( QWidget* parent = 0 );
|
||||
|
||||
void setRenderer( QgsRuleBasedRendererV2* r );
|
||||
|
||||
enum Grouping { NoGrouping, GroupingByScale, GroupingByFilter };
|
||||
|
||||
void setGrouping( Grouping g );
|
||||
|
||||
void populateRules();
|
||||
|
||||
protected:
|
||||
void populateRulesNoGrouping();
|
||||
void populateRulesGroupByScale();
|
||||
void populateRulesGroupByFilter();
|
||||
|
||||
QgsRuleBasedRendererV2* mR;
|
||||
Grouping mGrouping;
|
||||
};
|
||||
|
||||
///////
|
||||
|
||||
#include "ui_qgsrulebasedrendererv2widget.h"
|
||||
|
||||
class GUI_EXPORT QgsRuleBasedRendererV2Widget : public QgsRendererV2Widget, private Ui::QgsRuleBasedRendererV2Widget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
static QgsRendererV2Widget* create( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer );
|
||||
|
||||
QgsRuleBasedRendererV2Widget( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer );
|
||||
~QgsRuleBasedRendererV2Widget();
|
||||
|
||||
virtual QgsFeatureRendererV2* renderer();
|
||||
|
||||
public slots:
|
||||
|
||||
void addRule();
|
||||
void editRule();
|
||||
void removeRule();
|
||||
|
||||
void setGrouping();
|
||||
|
||||
void refineRuleScales();
|
||||
void refineRuleCategories();
|
||||
void refineRuleRanges();
|
||||
|
||||
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* mRenderer;
|
||||
|
||||
QMenu* mRefineMenu;
|
||||
};
|
||||
|
||||
///////
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "ui_qgsrendererrulepropsdialogbase.h"
|
||||
|
||||
class GUI_EXPORT QgsRendererRulePropsDialog : public QDialog, private Ui::QgsRendererRulePropsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QgsRendererRulePropsDialog( const QgsRuleBasedRendererV2::Rule& rule, QgsVectorLayer* layer, QgsStyleV2* style );
|
||||
|
||||
void updateRuleFromGui();
|
||||
const QgsRuleBasedRendererV2::Rule& rule() { return mRule; }
|
||||
|
||||
public slots:
|
||||
void testFilter();
|
||||
|
||||
protected:
|
||||
QgsRuleBasedRendererV2::Rule mRule;
|
||||
QgsVectorLayer* mLayer;
|
||||
QgsStyleV2* mStyle;
|
||||
};
|
||||
|
||||
|
||||
#endif // QGSRULEBASEDRENDERERV2WIDGET_H
|
171
src/ui/qgsrendererrulepropsdialogbase.ui
Normal file
171
src/ui/qgsrendererrulepropsdialogbase.ui
Normal file
@ -0,0 +1,171 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QgsRendererRulePropsDialog</class>
|
||||
<widget class="QDialog" name="QgsRendererRulePropsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>547</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Rule properties</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Filter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="editFilter"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnTestFilter">
|
||||
<property name="text">
|
||||
<string>Test</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupScale">
|
||||
<property name="title">
|
||||
<string>Scale range</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Min. scale</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinMinScale">
|
||||
<property name="prefix">
|
||||
<string>1 : </string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000000000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Max. scale</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinMaxScale">
|
||||
<property name="prefix">
|
||||
<string>1 : </string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000000000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupSymbol">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Symbol</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>QgsRendererRulePropsDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>QgsRendererRulePropsDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
115
src/ui/qgsrulebasedrendererv2widget.ui
Normal file
115
src/ui/qgsrulebasedrendererv2widget.ui
Normal file
@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QgsRuleBasedRendererV2Widget</class>
|
||||
<widget class="QWidget" name="QgsRuleBasedRendererV2Widget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>460</width>
|
||||
<height>221</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Rules:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QgsRendererRulesTreeWidget" name="treeRules">
|
||||
<property name="rootIsDecorated">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="headerHidden">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Rule</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnAddRule">
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRefineRule">
|
||||
<property name="text">
|
||||
<string>Refine</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnEditRule">
|
||||
<property name="text">
|
||||
<string>Edit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRemoveRule">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Rule grouping</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radNoGrouping">
|
||||
<property name="text">
|
||||
<string>No grouping</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radGroupFilter">
|
||||
<property name="text">
|
||||
<string>Group by filter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radGroupScale">
|
||||
<property name="text">
|
||||
<string>Group by scale</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QgsRendererRulesTreeWidget</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header>qgsrulebasedrendererv2widget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
Loading…
x
Reference in New Issue
Block a user