[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:
wonder 2010-06-12 10:11:19 +00:00
parent 65b1cc2416
commit 0a4f1c5947
12 changed files with 1522 additions and 8 deletions

View File

@ -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

View File

@ -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/;

View File

@ -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

View File

@ -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()

View 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;
}

View 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

View File

@ -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

View File

@ -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;
}

View 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() );
}

View 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

View 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>

View 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>