mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
Model/view-based tree of rules. Added basic unit test, GUI renderer test
This commit is contained in:
parent
83ec8104bd
commit
245e76daa4
@ -430,8 +430,10 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2
|
||||
|
||||
static QgsFeatureRendererV2* create( QDomElement& element ) /Factory/;
|
||||
|
||||
//! Constructor. Takes ownership of the defult symbol.
|
||||
QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol /Transfer/ = NULL );
|
||||
//! Constructs the renderer from given tree of rules
|
||||
QgsRuleBasedRendererV2( QgsRuleBasedRendererV2::Rule* root /Transfer/ );
|
||||
//! Constructor for convenience. Creates a root rule and adds a default rule with 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 );
|
||||
@ -456,18 +458,6 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2
|
||||
|
||||
/////
|
||||
|
||||
//! return the total number of rules
|
||||
int ruleCount();
|
||||
//! get reference to rule at index (valid indexes: 0...count-1)
|
||||
QgsRuleBasedRendererV2::Rule* ruleAt( int index );
|
||||
//! add rule to the end of the list of rules
|
||||
void addRule( QgsRuleBasedRendererV2::Rule* rule );
|
||||
//! insert rule to a specific position of the list of rules
|
||||
void insertRule( int index, QgsRuleBasedRendererV2::Rule* rule );
|
||||
//! modify the rule at a specific position of the list of rules
|
||||
void updateRuleAt( int index, QgsRuleBasedRendererV2::Rule* rule );
|
||||
//! remove the rule at the specified index
|
||||
void removeRuleAt( int index );
|
||||
|
||||
//////
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
|
||||
QgsRuleBasedRendererV2::Rule::Rule( QgsSymbolV2* symbol, int scaleMinDenom, int scaleMaxDenom, QString filterExp, QString label, QString description )
|
||||
: mSymbol( symbol ),
|
||||
: mParent( NULL ), mSymbol( symbol ),
|
||||
mScaleMinDenom( scaleMinDenom ), mScaleMaxDenom( scaleMaxDenom ),
|
||||
mFilterExp( filterExp ), mLabel( label ), mDescription( description ),
|
||||
mFilter( NULL )
|
||||
@ -41,6 +41,8 @@ QgsRuleBasedRendererV2::Rule::~Rule()
|
||||
{
|
||||
delete mSymbol;
|
||||
delete mFilter;
|
||||
qDeleteAll( mChildren );
|
||||
// do NOT delete parent
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2::Rule::initFilter()
|
||||
@ -145,9 +147,7 @@ QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::clone() const
|
||||
Rule* newrule = new Rule( sym, mScaleMinDenom, mScaleMaxDenom, mFilterExp, mLabel, mDescription );
|
||||
// clone children
|
||||
foreach( Rule* rule, mChildren )
|
||||
{
|
||||
newrule->mChildren.append( rule->clone() );
|
||||
}
|
||||
newrule->appendChild( rule->clone() );
|
||||
return newrule;
|
||||
}
|
||||
|
||||
@ -320,7 +320,7 @@ QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::create( QDomElement&
|
||||
{
|
||||
Rule* childRule = create( childRuleElem, symbolMap );
|
||||
if ( childRule )
|
||||
rule->mChildren.append( childRule );
|
||||
rule->appendChild( childRule );
|
||||
else
|
||||
QgsDebugMsg( "failed to init a child rule!" );
|
||||
childRuleElem = childRuleElem.nextSiblingElement( "rule" );
|
||||
@ -332,16 +332,16 @@ QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::create( QDomElement&
|
||||
|
||||
/////////////////////
|
||||
|
||||
QgsRuleBasedRendererV2::QgsRuleBasedRendererV2( QgsRuleBasedRendererV2::Rule* root )
|
||||
: QgsFeatureRendererV2( "RuleRenderer" ), mRootRule( root )
|
||||
{
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2::QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol )
|
||||
: QgsFeatureRendererV2( "RuleRenderer" )
|
||||
{
|
||||
mRootRule = new Rule( NULL );
|
||||
|
||||
if ( defaultSymbol )
|
||||
{
|
||||
// add the default rule
|
||||
mRootRule->children().append( new Rule( defaultSymbol ) );
|
||||
}
|
||||
mRootRule = new Rule( NULL ); // root has no symbol, no filter etc - just a container
|
||||
mRootRule->appendChild( new Rule( defaultSymbol ) );
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2::~QgsRuleBasedRendererV2()
|
||||
@ -454,9 +454,7 @@ QList<QString> QgsRuleBasedRendererV2::usedAttributes()
|
||||
|
||||
QgsFeatureRendererV2* QgsRuleBasedRendererV2::clone()
|
||||
{
|
||||
QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2();
|
||||
delete r->mRootRule;
|
||||
r->mRootRule = mRootRule->clone();
|
||||
QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( mRootRule->clone() );
|
||||
|
||||
r->setUsingSymbolLevels( usingSymbolLevels() );
|
||||
setUsingSymbolLevels( usingSymbolLevels() );
|
||||
@ -477,8 +475,8 @@ QDomElement QgsRuleBasedRendererV2::save( QDomDocument& doc )
|
||||
|
||||
QgsSymbolV2Map symbols;
|
||||
|
||||
QDomElement rulesElem = doc.createElement( "rules" );
|
||||
rulesElem.appendChild( mRootRule->save( doc, symbols ) );
|
||||
QDomElement rulesElem = mRootRule->save( doc, symbols );
|
||||
rulesElem.setTagName( "rules" ); // instead of just "rule"
|
||||
rendererElem.appendChild( rulesElem );
|
||||
|
||||
QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
|
||||
@ -518,14 +516,11 @@ QgsFeatureRendererV2* QgsRuleBasedRendererV2::create( QDomElement& element )
|
||||
|
||||
QDomElement rulesElem = element.firstChildElement( "rules" );
|
||||
|
||||
QDomElement rootRuleElem = rulesElem.firstChildElement( "rule" );
|
||||
Rule* root = Rule::create( rootRuleElem, symbolMap );
|
||||
Rule* root = Rule::create( rulesElem, symbolMap );
|
||||
if ( root == NULL )
|
||||
return NULL;
|
||||
|
||||
QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2();
|
||||
delete r->mRootRule;
|
||||
r->mRootRule = root;
|
||||
QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( root );
|
||||
|
||||
// delete symbols if there are any more
|
||||
QgsSymbolLayerV2Utils::clearSymbolMap( symbolMap );
|
||||
@ -534,48 +529,10 @@ QgsFeatureRendererV2* QgsRuleBasedRendererV2::create( QDomElement& element )
|
||||
}
|
||||
|
||||
|
||||
int QgsRuleBasedRendererV2::ruleCount()
|
||||
{
|
||||
return mRootRule->children().count();
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::ruleAt( int index )
|
||||
{
|
||||
return mRootRule->children()[index];
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2::addRule( QgsRuleBasedRendererV2::Rule* rule )
|
||||
{
|
||||
mRootRule->children().append( rule );
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2::insertRule( int index, QgsRuleBasedRendererV2::Rule* rule )
|
||||
{
|
||||
mRootRule->children().insert( index, rule );
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2::updateRuleAt( int index, QgsRuleBasedRendererV2::Rule* rule )
|
||||
{
|
||||
RuleList& rules = mRootRule->children();
|
||||
delete rules[index]; // delete previous
|
||||
rules[index] = rule;
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2::removeRuleAt( int index )
|
||||
{
|
||||
delete mRootRule->children().takeAt( index );
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2::swapRules( int index1, int index2 )
|
||||
{
|
||||
mRootRule->children().swap( index1, index2 );
|
||||
}
|
||||
|
||||
|
||||
#include "qgscategorizedsymbolrendererv2.h"
|
||||
#include "qgsgraduatedsymbolrendererv2.h"
|
||||
|
||||
QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2::refineRuleCategories( QgsRuleBasedRendererV2::Rule* initialRule, QgsCategorizedSymbolRendererV2* r )
|
||||
void QgsRuleBasedRendererV2::refineRuleCategories( QgsRuleBasedRendererV2::Rule* initialRule, QgsCategorizedSymbolRendererV2* r )
|
||||
{
|
||||
RuleList rules;
|
||||
foreach( const QgsRendererCategoryV2& cat, r->categories() )
|
||||
@ -588,14 +545,12 @@ QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2::refineRuleCategories( Q
|
||||
filter = newfilter;
|
||||
else
|
||||
filter = QString( "(%1) AND (%2)" ).arg( filter ).arg( newfilter );
|
||||
rules.append( new Rule( cat.symbol()->clone(), initialRule->scaleMinDenom(), initialRule->scaleMaxDenom(), filter, label, description ) );
|
||||
initialRule->appendChild( new Rule( cat.symbol()->clone(), initialRule->scaleMinDenom(), initialRule->scaleMaxDenom(), filter, label, description ) );
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2::refineRuleRanges( QgsRuleBasedRendererV2::Rule* initialRule, QgsGraduatedSymbolRendererV2* r )
|
||||
void QgsRuleBasedRendererV2::refineRuleRanges( QgsRuleBasedRendererV2::Rule* initialRule, QgsGraduatedSymbolRendererV2* r )
|
||||
{
|
||||
RuleList rules;
|
||||
foreach( const QgsRendererRangeV2& rng, r->ranges() )
|
||||
{
|
||||
QString newfilter = QString( "%1 >= '%2' AND %1 <= '%3'" ).arg( r->classAttribute() ).arg( rng.lowerValue() ).arg( rng.upperValue() );
|
||||
@ -606,15 +561,13 @@ QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2::refineRuleRanges( QgsRu
|
||||
filter = newfilter;
|
||||
else
|
||||
filter = QString( "(%1) AND (%2)" ).arg( filter ).arg( newfilter );
|
||||
rules.append( new Rule( rng.symbol()->clone(), initialRule->scaleMinDenom(), initialRule->scaleMaxDenom(), filter, label, description ) );
|
||||
initialRule->appendChild( new Rule( rng.symbol()->clone(), initialRule->scaleMinDenom(), initialRule->scaleMaxDenom(), filter, label, description ) );
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2::refineRuleScales( QgsRuleBasedRendererV2::Rule* initialRule, QList<int> scales )
|
||||
void QgsRuleBasedRendererV2::refineRuleScales( QgsRuleBasedRendererV2::Rule* initialRule, QList<int> scales )
|
||||
{
|
||||
qSort( scales ); // make sure the scales are in ascending order
|
||||
RuleList rules;
|
||||
int oldScale = initialRule->scaleMinDenom();
|
||||
int maxDenom = initialRule->scaleMaxDenom();
|
||||
QString filter = initialRule->filterExpression();
|
||||
@ -627,12 +580,11 @@ QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2::refineRuleScales( QgsRu
|
||||
continue; // jump over the first scales out of the interval
|
||||
if ( maxDenom != 0 && maxDenom <= scale )
|
||||
break; // ignore the latter scales out of the interval
|
||||
rules.append( new Rule( symbol->clone(), oldScale, scale, filter, label, description ) );
|
||||
initialRule->appendChild( new Rule( symbol->clone(), oldScale, scale, filter, label, description ) );
|
||||
oldScale = scale;
|
||||
}
|
||||
// last rule
|
||||
rules.append( new Rule( symbol->clone(), oldScale, maxDenom, filter, label, description ) );
|
||||
return rules;
|
||||
initialRule->appendChild( new Rule( symbol->clone(), oldScale, maxDenom, filter, label, description ) );
|
||||
}
|
||||
|
||||
QString QgsRuleBasedRendererV2::dump()
|
||||
|
@ -119,11 +119,22 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2
|
||||
static Rule* create( QDomElement& ruleElem, QgsSymbolV2Map& symbolMap );
|
||||
|
||||
RuleList& children() { return mChildren; }
|
||||
Rule* parent() { return mParent; }
|
||||
|
||||
//! add child rule, take ownership, sets this as parent
|
||||
void appendChild( Rule* rule ) { mChildren.append( rule ); rule->mParent = this; }
|
||||
//! add child rule, take ownership, sets this as parent
|
||||
void insertChild( int i, Rule* rule ) { mChildren.insert( i, rule ); rule->mParent = this; }
|
||||
//! delete child rule
|
||||
void removeChild( Rule* rule ) { mChildren.removeAll( rule ); delete rule; }
|
||||
//! take child rule out, set parent as null
|
||||
void takeChild( Rule* rule ) { mChildren.removeAll( rule ); rule->mParent = NULL; }
|
||||
|
||||
protected:
|
||||
|
||||
void initFilter();
|
||||
|
||||
Rule* mParent; // parent rule (NULL only for root rule)
|
||||
QgsSymbolV2* mSymbol;
|
||||
int mScaleMinDenom, mScaleMaxDenom;
|
||||
QString mFilterExp, mLabel, mDescription;
|
||||
@ -141,8 +152,10 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2
|
||||
|
||||
static QgsFeatureRendererV2* create( QDomElement& element );
|
||||
|
||||
//! Constructor. Adds default rule if the symbol is not null (and takes ownership of it)
|
||||
QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol = NULL );
|
||||
//! Constructs the renderer from given tree of rules (takes ownership)
|
||||
QgsRuleBasedRendererV2( QgsRuleBasedRendererV2::Rule* root );
|
||||
//! Constructor for convenience. Creates a root rule and adds a default rule with symbol (takes ownership)
|
||||
QgsRuleBasedRendererV2( QgsSymbolV2* defaultSymbol );
|
||||
|
||||
~QgsRuleBasedRendererV2();
|
||||
|
||||
@ -178,31 +191,14 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2
|
||||
|
||||
Rule* rootRule() { return mRootRule; }
|
||||
|
||||
|
||||
//! return the total number of rules
|
||||
int ruleCount();
|
||||
//! get reference to rule at index (valid indexes: 0...count-1)
|
||||
Rule* ruleAt( int index );
|
||||
//! add rule to the end of the list of rules. takes ownership
|
||||
void addRule( Rule* rule );
|
||||
//! insert rule to a specific position of the list of rules. takes ownership
|
||||
void insertRule( int index, Rule* rule );
|
||||
//! modify the rule at a specific position of the list of rules. takes ownership
|
||||
void updateRuleAt( int index, Rule* rule );
|
||||
//! remove the rule at the specified index
|
||||
void removeRuleAt( int index );
|
||||
//! swap the two rules specified by the indices
|
||||
void swapRules( int index1, int index2 );
|
||||
|
||||
|
||||
//////
|
||||
|
||||
//! take a rule and create a list of new rules based on the categories from categorized symbol renderer
|
||||
static RuleList refineRuleCategories( Rule* initialRule, QgsCategorizedSymbolRendererV2* r );
|
||||
static void refineRuleCategories( Rule* initialRule, QgsCategorizedSymbolRendererV2* r );
|
||||
//! take a rule and create a list of new rules based on the ranges from graduated symbol renderer
|
||||
static RuleList refineRuleRanges( Rule* initialRule, QgsGraduatedSymbolRendererV2* r );
|
||||
static void 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 RuleList refineRuleScales( Rule* initialRule, QList<int> scales );
|
||||
static void refineRuleScales( Rule* initialRule, QList<int> scales );
|
||||
|
||||
protected:
|
||||
//! the root node with hierarchical list of rules
|
||||
|
@ -58,7 +58,9 @@ QgsRuleBasedRendererV2Widget::QgsRuleBasedRendererV2Widget( QgsVectorLayer* laye
|
||||
|
||||
setupUi( this );
|
||||
|
||||
treeRules->setRenderer( mRenderer );
|
||||
mModel = new QgsRuleBasedRendererV2Model( mRenderer );
|
||||
viewRules->setModel( mModel );
|
||||
|
||||
mRefineMenu = new QMenu( btnRefineRule );
|
||||
mRefineMenu->addAction( tr( "Add scales" ), this, SLOT( refineRuleScales() ) );
|
||||
mRefineMenu->addAction( tr( "Add categories" ), this, SLOT( refineRuleCategories() ) );
|
||||
@ -71,8 +73,10 @@ QgsRuleBasedRendererV2Widget::QgsRuleBasedRendererV2Widget( QgsVectorLayer* laye
|
||||
btnMoveUp->setIcon( QIcon( QgsApplication::iconPath( "symbologyUp.png" ) ) );
|
||||
btnMoveDown->setIcon( QIcon( QgsApplication::iconPath( "symbologyDown.png" ) ) );
|
||||
|
||||
connect( treeRules, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( editRule() ) );
|
||||
connect( treeRules, SIGNAL( customContextMenuRequested( const QPoint& ) ), this, SLOT( contextMenuViewCategories( const QPoint& ) ) );
|
||||
connect( viewRules, SIGNAL( doubleClicked( const QModelIndex & ) ), this, SLOT( editRule( const QModelIndex & ) ) );
|
||||
|
||||
// support for context menu (now handled generically)
|
||||
connect( viewRules, SIGNAL( customContextMenuRequested( const QPoint& ) ), this, SLOT( contextMenuViewCategories( const QPoint& ) ) );
|
||||
|
||||
connect( btnAddRule, SIGNAL( clicked() ), this, SLOT( addRule() ) );
|
||||
connect( btnEditRule, SIGNAL( clicked() ), this, SLOT( editRule() ) );
|
||||
@ -80,13 +84,7 @@ QgsRuleBasedRendererV2Widget::QgsRuleBasedRendererV2Widget( QgsVectorLayer* laye
|
||||
connect( btnMoveUp, SIGNAL( clicked() ), this, SLOT( moveUp() ) );
|
||||
connect( btnMoveDown, SIGNAL( clicked() ), this, SLOT( moveDown() ) );
|
||||
|
||||
connect( radNoGrouping, SIGNAL( clicked() ), this, SLOT( setGrouping() ) );
|
||||
connect( radGroupFilter, SIGNAL( clicked() ), this, SLOT( setGrouping() ) );
|
||||
connect( radGroupScale, SIGNAL( clicked() ), this, SLOT( setGrouping() ) );
|
||||
|
||||
connect( btnRenderingOrder, SIGNAL( clicked() ), this, SLOT( setRenderingOrder() ) );
|
||||
|
||||
treeRules->setGrouping( QgsRendererRulesTreeWidget::NoGrouping );
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2Widget::~QgsRuleBasedRendererV2Widget()
|
||||
@ -99,17 +97,6 @@ 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()
|
||||
{
|
||||
QgsSymbolV2* s = QgsSymbolV2::defaultSymbol( mLayer->geometryType() );
|
||||
@ -118,10 +105,21 @@ void QgsRuleBasedRendererV2Widget::addRule()
|
||||
QgsRendererRulePropsDialog dlg( newrule, mLayer, mStyle );
|
||||
if ( dlg.exec() )
|
||||
{
|
||||
// add rule
|
||||
dlg.updateRuleFromGui();
|
||||
mRenderer->addRule( newrule ); // takes ownership
|
||||
treeRules->populateRules();
|
||||
|
||||
QgsRuleBasedRendererV2::Rule* current = currentRule();
|
||||
if ( current )
|
||||
{
|
||||
// add after this rule
|
||||
QModelIndex currentIndex = viewRules->selectionModel()->currentIndex();
|
||||
mModel->insertRule( currentIndex.parent(), currentIndex.row() + 1, newrule );
|
||||
}
|
||||
else
|
||||
{
|
||||
// append to root rule
|
||||
int rows = mModel->rowCount();
|
||||
mModel->insertRule( QModelIndex(), rows, newrule );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -129,110 +127,56 @@ void QgsRuleBasedRendererV2Widget::addRule()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2Widget::currentRule()
|
||||
{
|
||||
QItemSelectionModel* sel = viewRules->selectionModel();
|
||||
QModelIndex idx = sel->currentIndex();
|
||||
if ( !idx.isValid() )
|
||||
return NULL;
|
||||
return static_cast<QgsRuleBasedRendererV2::Rule*>( idx.internalPointer() );
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::editRule()
|
||||
{
|
||||
QTreeWidgetItem * item = treeRules->currentItem();
|
||||
if ( ! item )
|
||||
return;
|
||||
editRule( viewRules->selectionModel()->currentIndex() );
|
||||
}
|
||||
|
||||
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." ) );
|
||||
void QgsRuleBasedRendererV2Widget::editRule( const QModelIndex& index )
|
||||
{
|
||||
if ( !index.isValid() )
|
||||
return;
|
||||
}
|
||||
QgsRuleBasedRendererV2::Rule* rule = mRenderer->ruleAt( rule_index )->clone();
|
||||
QgsRuleBasedRendererV2::Rule* rule = static_cast<QgsRuleBasedRendererV2::Rule*>( index.internalPointer() );
|
||||
|
||||
QgsRendererRulePropsDialog dlg( rule, mLayer, mStyle );
|
||||
if ( dlg.exec() )
|
||||
{
|
||||
// update rule
|
||||
dlg.updateRuleFromGui();
|
||||
mRenderer->updateRuleAt( rule_index, rule );
|
||||
|
||||
treeRules->populateRules();
|
||||
}
|
||||
else
|
||||
{
|
||||
delete rule;
|
||||
// model should know about the change and emit dataChanged signal for the view
|
||||
mModel->updateRule( index );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::removeRule()
|
||||
{
|
||||
QTreeWidgetItem * item = treeRules->currentItem();
|
||||
if ( ! item )
|
||||
QModelIndex index = viewRules->selectionModel()->currentIndex();
|
||||
if ( !index.isValid() )
|
||||
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();
|
||||
mModel->removeRule( index );
|
||||
}
|
||||
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::moveUp()
|
||||
{
|
||||
QTreeWidgetItem * item = treeRules->currentItem();
|
||||
if ( ! item ) return; // No rule selected, exit
|
||||
int rule_index = item->data( 0, Qt::UserRole + 1 ).toInt();
|
||||
if ( rule_index < 0 )
|
||||
{
|
||||
return;// Group of rules selected, exit
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rule_index > 0 ) // do not move up the first rule
|
||||
{
|
||||
mRenderer->swapRules( rule_index, rule_index - 1 );
|
||||
treeRules->populateRules();
|
||||
// TODO: find out where the moved rule goes and reselect it (at least for non-grouped display)
|
||||
// maybe based on the following functions :
|
||||
// findItems(QString(rule_index - 1), Qt::MatchExactly, 4).first.index)
|
||||
// setCurrentItem, setSelected, scrollToItem
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: solve directly by drag'n'drop
|
||||
}
|
||||
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::moveDown()
|
||||
{
|
||||
QTreeWidgetItem * item = treeRules->currentItem();
|
||||
if ( ! item ) return; // No rule selected, exit
|
||||
int rule_index = item->data( 0, Qt::UserRole + 1 ).toInt();
|
||||
if ( rule_index < 0 )
|
||||
{
|
||||
return;// Group of rules selected, exit
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rule_index + 1 < mRenderer->ruleCount() ) // do not move down the last rule
|
||||
{
|
||||
mRenderer->swapRules( rule_index, rule_index + 1 );
|
||||
treeRules->populateRules();
|
||||
}
|
||||
}
|
||||
// TODO: solve directly by drag'n'drop
|
||||
}
|
||||
|
||||
|
||||
@ -248,38 +192,23 @@ void QgsRuleBasedRendererV2Widget::moveDown()
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::refineRule( int type )
|
||||
{
|
||||
QTreeWidgetItem * item = treeRules->currentItem();
|
||||
if ( ! item )
|
||||
QModelIndex index = viewRules->selectionModel()->currentIndex();
|
||||
if ( !index.isValid() )
|
||||
return;
|
||||
|
||||
int rule_index = item->data( 0, Qt::UserRole + 1 ).toInt();
|
||||
if ( rule_index < 0 )
|
||||
return;
|
||||
QgsRuleBasedRendererV2::Rule* initialRule = static_cast<QgsRuleBasedRendererV2::Rule*>( index.internalPointer() );
|
||||
|
||||
QgsRuleBasedRendererV2::Rule* initialRule = mRenderer->ruleAt( rule_index );
|
||||
|
||||
|
||||
QgsRuleBasedRendererV2::RuleList refinedRules;
|
||||
if ( type == 0 ) // categories
|
||||
refinedRules = refineRuleCategoriesGui( initialRule );
|
||||
refineRuleCategoriesGui( initialRule );
|
||||
else if ( type == 1 ) // ranges
|
||||
refinedRules = refineRuleRangesGui( initialRule );
|
||||
refineRuleRangesGui( initialRule );
|
||||
else // scales
|
||||
refinedRules = refineRuleScalesGui( initialRule );
|
||||
refineRuleScalesGui( initialRule );
|
||||
|
||||
if ( refinedRules.count() == 0 )
|
||||
return;
|
||||
// TODO: set initial rule's symbol to NULL (?)
|
||||
|
||||
// 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();
|
||||
// TODO: let model know things have changed
|
||||
mModel->updateRule( index );
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::refineRuleCategories()
|
||||
@ -297,7 +226,7 @@ void QgsRuleBasedRendererV2Widget::refineRuleScales()
|
||||
refineRule( 2 );
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2Widget::refineRuleCategoriesGui( QgsRuleBasedRendererV2::Rule* initialRule )
|
||||
void QgsRuleBasedRendererV2Widget::refineRuleCategoriesGui( QgsRuleBasedRendererV2::Rule* initialRule )
|
||||
{
|
||||
QDialog dlg;
|
||||
dlg.setWindowTitle( tr( "Refine a rule to categories" ) );
|
||||
@ -311,15 +240,15 @@ QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2Widget::refineRuleCategor
|
||||
dlg.setLayout( l );
|
||||
|
||||
if ( !dlg.exec() )
|
||||
return QgsRuleBasedRendererV2::RuleList();
|
||||
return;
|
||||
|
||||
// create new rules
|
||||
QgsCategorizedSymbolRendererV2* r = static_cast<QgsCategorizedSymbolRendererV2*>( w->renderer() );
|
||||
return QgsRuleBasedRendererV2::refineRuleCategories( initialRule, r );
|
||||
QgsRuleBasedRendererV2::refineRuleCategories( initialRule, r );
|
||||
}
|
||||
|
||||
|
||||
QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2Widget::refineRuleRangesGui( QgsRuleBasedRendererV2::Rule* initialRule )
|
||||
void QgsRuleBasedRendererV2Widget::refineRuleRangesGui( QgsRuleBasedRendererV2::Rule* initialRule )
|
||||
{
|
||||
QDialog dlg;
|
||||
dlg.setWindowTitle( tr( "Refine a rule to ranges" ) );
|
||||
@ -333,20 +262,20 @@ QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2Widget::refineRuleRangesG
|
||||
dlg.setLayout( l );
|
||||
|
||||
if ( !dlg.exec() )
|
||||
return QgsRuleBasedRendererV2::RuleList();
|
||||
return;
|
||||
|
||||
// create new rules
|
||||
QgsGraduatedSymbolRendererV2* r = static_cast<QgsGraduatedSymbolRendererV2*>( w->renderer() );
|
||||
return QgsRuleBasedRendererV2::refineRuleRanges( initialRule, r );
|
||||
QgsRuleBasedRendererV2::refineRuleRanges( initialRule, r );
|
||||
}
|
||||
|
||||
QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2Widget::refineRuleScalesGui( QgsRuleBasedRendererV2::Rule* initialRule )
|
||||
void 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 QgsRuleBasedRendererV2::RuleList();
|
||||
return;
|
||||
|
||||
QList<int> scales;
|
||||
bool ok;
|
||||
@ -359,7 +288,7 @@ QgsRuleBasedRendererV2::RuleList QgsRuleBasedRendererV2Widget::refineRuleScalesG
|
||||
QMessageBox::information( this, tr( "Error" ), QString( tr( "\"%1\" is not valid scale denominator, ignoring it." ) ).arg( item ) );
|
||||
}
|
||||
|
||||
return QgsRuleBasedRendererV2::refineRuleScales( initialRule, scales );
|
||||
QgsRuleBasedRendererV2::refineRuleScales( initialRule, scales );
|
||||
}
|
||||
|
||||
QList<QgsSymbolV2*> QgsRuleBasedRendererV2Widget::selectedSymbols()
|
||||
@ -371,14 +300,16 @@ QList<QgsSymbolV2*> QgsRuleBasedRendererV2Widget::selectedSymbols()
|
||||
return symbolList;
|
||||
}
|
||||
|
||||
QList<QTreeWidgetItem*> selectedItems = treeRules->selectedItems();
|
||||
QList<QTreeWidgetItem*>::const_iterator it = selectedItems.constBegin();
|
||||
for ( ; it != selectedItems.constEnd(); ++it )
|
||||
QItemSelection sel = viewRules->selectionModel()->selection();
|
||||
foreach( QItemSelectionRange range, sel )
|
||||
{
|
||||
int priority = ( *it )->data( 0, Qt::UserRole + 1 ).toInt();
|
||||
if ( priority < mRenderer->ruleCount() )
|
||||
QModelIndex parent = range.parent();
|
||||
QgsRuleBasedRendererV2::Rule* parentRule = !parent.isValid() ? mRenderer->rootRule() :
|
||||
static_cast<QgsRuleBasedRendererV2::Rule*>( parent.internalPointer() );
|
||||
QgsRuleBasedRendererV2::RuleList& children = parentRule->children();
|
||||
for ( int row = range.top(); row <= range.bottom(); row++ )
|
||||
{
|
||||
symbolList.append( mRenderer->ruleAt( priority )->symbol() );
|
||||
symbolList.append( children[row]->symbol() );
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,10 +318,13 @@ QList<QgsSymbolV2*> QgsRuleBasedRendererV2Widget::selectedSymbols()
|
||||
|
||||
void QgsRuleBasedRendererV2Widget::refreshSymbolView()
|
||||
{
|
||||
// TODO: model/view
|
||||
/*
|
||||
if ( treeRules )
|
||||
{
|
||||
treeRules->populateRules();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
#include "qgssymbollevelsv2dialog.h"
|
||||
@ -488,254 +422,197 @@ void QgsRendererRulePropsDialog::updateRuleFromGui()
|
||||
|
||||
////////
|
||||
|
||||
QgsRendererRulesTreeWidget::QgsRendererRulesTreeWidget( QWidget* parent )
|
||||
: QTreeWidget( parent ), mR( NULL ), mGrouping( NoGrouping )
|
||||
{
|
||||
mLongestMinDenom = 0;
|
||||
mLongestMaxDenom = 0;
|
||||
/*
|
||||
setDragEnabled(true);
|
||||
viewport()->setAcceptDrops(true);
|
||||
setDropIndicatorShown(true);
|
||||
setDragDropMode(QAbstractItemView::InternalMove);
|
||||
*/
|
||||
|
||||
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( true ); //mGrouping != NoGrouping );
|
||||
populateRules();
|
||||
}
|
||||
|
||||
QString QgsRendererRulesTreeWidget::formatScaleRange( int minDenom, int maxDenom )
|
||||
{
|
||||
if ( maxDenom != 0 )
|
||||
return QString( "<1:%L1, 1:%L2>" ).arg( minDenom ).arg( maxDenom );
|
||||
else
|
||||
return QString( "<1:%L1, 1:inf>" ).arg( minDenom );
|
||||
|
||||
}
|
||||
|
||||
QString QgsRendererRulesTreeWidget::formatScale( int denom, int size )
|
||||
static QString _formatScale( int denom )
|
||||
{
|
||||
if ( denom != 0 )
|
||||
{
|
||||
QString txt = QString( "1:%L1" ).arg( denom );
|
||||
if ( size > 0 )
|
||||
txt.prepend( QString( size - txt.count(), QChar( ' ' ) ) );
|
||||
return txt;
|
||||
}
|
||||
else
|
||||
return QString();
|
||||
}
|
||||
|
||||
#include "qgslogger.h"
|
||||
void QgsRendererRulesTreeWidget::populateRules()
|
||||
/////
|
||||
|
||||
QgsRuleBasedRendererV2Model::QgsRuleBasedRendererV2Model( QgsRuleBasedRendererV2* r )
|
||||
: mR( r )
|
||||
{
|
||||
if ( !mR )
|
||||
return;
|
||||
}
|
||||
|
||||
clear();
|
||||
Qt::ItemFlags QgsRuleBasedRendererV2Model::flags( const QModelIndex &index ) const
|
||||
{
|
||||
if ( !index.isValid() )
|
||||
return 0;
|
||||
|
||||
mLongestMinDenom = 0;
|
||||
mLongestMaxDenom = 0;
|
||||
// find longest scale string for future padding
|
||||
// TODO: use a custom model and implement custom sorting
|
||||
for ( int i = 0; i < mR->ruleCount(); ++i )
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
|
||||
}
|
||||
|
||||
QVariant QgsRuleBasedRendererV2Model::data( const QModelIndex &index, int role ) const
|
||||
{
|
||||
if ( !index.isValid() )
|
||||
return QVariant();
|
||||
|
||||
QgsRuleBasedRendererV2::Rule* rule = static_cast<QgsRuleBasedRendererV2::Rule*>( index.internalPointer() );
|
||||
|
||||
if ( role == Qt::DisplayRole )
|
||||
{
|
||||
QgsRuleBasedRendererV2::Rule* rule = mR->ruleAt( i );
|
||||
|
||||
mLongestMinDenom = qMax( mLongestMinDenom, formatScale( rule->scaleMinDenom() ).size() );
|
||||
mLongestMaxDenom = qMax( mLongestMaxDenom, formatScale( rule->scaleMaxDenom() ).size() );
|
||||
switch ( index.column() )
|
||||
{
|
||||
case 0: return rule->label();
|
||||
case 1: return rule->filterExpression().isEmpty() ? tr( "(no filter)" ) : rule->filterExpression();
|
||||
case 2: return rule->dependsOnScale() ? _formatScale( rule->scaleMinDenom() ) : QVariant();
|
||||
case 3: return rule->dependsOnScale() ? _formatScale( rule->scaleMaxDenom() ) : QVariant();
|
||||
default: return QVariant();
|
||||
}
|
||||
}
|
||||
else if ( role == Qt::DecorationRole && index.column() == 0 && rule->symbol() )
|
||||
{
|
||||
return QgsSymbolLayerV2Utils::symbolPreviewIcon( rule->symbol(), QSize( 16, 16 ) );
|
||||
}
|
||||
else if ( role == Qt::TextAlignmentRole )
|
||||
{
|
||||
return ( index.column() == 2 || index.column() == 3 ) ? Qt::AlignRight : Qt::AlignLeft;
|
||||
}
|
||||
else if ( role == Qt::EditRole )
|
||||
{
|
||||
switch ( index.column() )
|
||||
{
|
||||
case 0: return rule->label();
|
||||
case 1: return rule->filterExpression();
|
||||
case 2: return rule->scaleMinDenom();
|
||||
case 3: return rule->scaleMaxDenom();
|
||||
default: return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ( mGrouping == NoGrouping )
|
||||
populateRulesNoGrouping();
|
||||
else if ( mGrouping == GroupingByScale )
|
||||
populateRulesGroupByScale();
|
||||
else
|
||||
populateRulesGroupByFilter();
|
||||
|
||||
setColumnWidth( 1, 200 ); // make the column for filter a bit bigger
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QTreeWidgetItem* QgsRendererRulesTreeWidget::populateRulesNoGrouping( QgsRuleBasedRendererV2::Rule* rule, int i, QTreeWidgetItem* parentItem )
|
||||
QVariant QgsRuleBasedRendererV2Model::headerData( int section, Qt::Orientation orientation, int role ) const
|
||||
{
|
||||
QTreeWidgetItem* item = new QTreeWidgetItem( parentItem );
|
||||
|
||||
QString txtLabel = rule->label();
|
||||
item->setText( 0, txtLabel );
|
||||
item->setData( 0, Qt::UserRole + 1, i );
|
||||
if ( rule->symbol() )
|
||||
if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 5 )
|
||||
{
|
||||
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule->symbol(), QSize( 16, 16 ) ) );
|
||||
QStringList lst; lst << tr( "Label" ) << tr( "Rule" ) << tr( "Min. scale" ) << tr( "Max.scale" );
|
||||
return lst[section];
|
||||
}
|
||||
|
||||
QString txtRule = rule->filterExpression();
|
||||
if ( txtRule.isEmpty() )
|
||||
txtRule = tr( "(no filter)" );
|
||||
item->setText( 1, txtRule );
|
||||
|
||||
if ( rule->dependsOnScale() )
|
||||
{
|
||||
item->setText( 2, formatScale( rule->scaleMinDenom(), mLongestMinDenom ) );
|
||||
item->setText( 3, formatScale( rule->scaleMaxDenom(), mLongestMaxDenom ) );
|
||||
item->setTextAlignment( 2, Qt::AlignRight );
|
||||
item->setTextAlignment( 3, Qt::AlignRight );
|
||||
}
|
||||
|
||||
// process children
|
||||
QgsRuleBasedRendererV2::RuleList& children = rule->children();
|
||||
for ( int i = 0; i < children.count(); ++i )
|
||||
{
|
||||
populateRulesNoGrouping( children[i], i, item );
|
||||
}
|
||||
|
||||
return item;
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void QgsRendererRulesTreeWidget::populateRulesNoGrouping()
|
||||
int QgsRuleBasedRendererV2Model::rowCount( const QModelIndex &parent ) const
|
||||
{
|
||||
QList<QTreeWidgetItem *> lst;
|
||||
QgsRuleBasedRendererV2::Rule* parentRule;
|
||||
if ( parent.column() > 0 )
|
||||
return 0;
|
||||
|
||||
QgsRuleBasedRendererV2::Rule* rule = mR->rootRule();
|
||||
QTreeWidgetItem* item = populateRulesNoGrouping( rule, -1, NULL );
|
||||
if ( !parent.isValid() )
|
||||
parentRule = mR->rootRule();
|
||||
else
|
||||
parentRule = static_cast<QgsRuleBasedRendererV2::Rule*>( parent.internalPointer() );
|
||||
|
||||
lst << item;
|
||||
addTopLevelItems( lst );
|
||||
return parentRule->children().count();
|
||||
}
|
||||
|
||||
|
||||
void QgsRendererRulesTreeWidget::populateRulesGroupByScale()
|
||||
int QgsRuleBasedRendererV2Model::columnCount( const QModelIndex & ) const
|
||||
{
|
||||
QMap< QPair<int, int>, QTreeWidgetItem*> scale_items;
|
||||
|
||||
QFont italicFont;
|
||||
italicFont.setItalic( true );
|
||||
|
||||
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 = tr( "scale " ) + formatScaleRange( rule->scaleMinDenom(), rule->scaleMaxDenom() );
|
||||
else
|
||||
txt = tr( "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_item->setFont( 0, italicFont );
|
||||
scale_items[scale] = scale_item;
|
||||
// need to add the item before setFirstColumnSpanned,
|
||||
// see http://qt.nokia.com/developer/task-tracker/index_html?method=entry&id=214686
|
||||
addTopLevelItem( scale_item );
|
||||
scale_item->setFirstColumnSpanned( true );
|
||||
}
|
||||
|
||||
QString filter = rule->filterExpression();
|
||||
|
||||
QTreeWidgetItem* item = new QTreeWidgetItem( scale_items[scale] );
|
||||
|
||||
QString txtLabel = rule->label();
|
||||
item->setText( 0, txtLabel );
|
||||
item->setData( 0, Qt::UserRole + 1, i );
|
||||
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule->symbol(), QSize( 16, 16 ) ) );
|
||||
|
||||
QString txtRule = rule->filterExpression();
|
||||
if ( txtRule.isEmpty() )
|
||||
txtRule = tr( "(no filter)" );
|
||||
item->setText( 1, txtRule );
|
||||
|
||||
if ( rule->dependsOnScale() )
|
||||
{
|
||||
// Displaying scales is redundant here, but keeping them allows to keep constant the layout and width of all columns when switching to one of the two other views
|
||||
item->setText( 2, formatScale( rule->scaleMinDenom(), mLongestMinDenom ) );
|
||||
item->setText( 3, formatScale( rule->scaleMaxDenom(), mLongestMaxDenom ) );
|
||||
item->setTextAlignment( 2, Qt::AlignRight );
|
||||
item->setTextAlignment( 3, Qt::AlignRight );
|
||||
}
|
||||
|
||||
//item->setBackground( 1, Qt::lightGray );
|
||||
//item->setBackground( 3, Qt::lightGray );
|
||||
|
||||
// Priority (Id): add 1 to rule number and convert to string
|
||||
item->setText( 4, QString( "%1" ).arg( i + 1, 4 ) );
|
||||
item->setTextAlignment( 4, Qt::AlignRight );
|
||||
|
||||
}
|
||||
addTopLevelItems( scale_items.values() );
|
||||
return 4;
|
||||
}
|
||||
|
||||
void QgsRendererRulesTreeWidget::populateRulesGroupByFilter()
|
||||
QModelIndex QgsRuleBasedRendererV2Model::index( int row, int column, const QModelIndex &parent ) const
|
||||
{
|
||||
QMap<QString, QTreeWidgetItem *> filter_items;
|
||||
if ( !hasIndex( row, column, parent ) )
|
||||
return QModelIndex();
|
||||
|
||||
QFont italicFont;
|
||||
italicFont.setItalic( true );
|
||||
QgsRuleBasedRendererV2::Rule* parentRule;
|
||||
|
||||
for ( int i = 0; i < mR->ruleCount(); ++i )
|
||||
if ( !parent.isValid() )
|
||||
parentRule = mR->rootRule();
|
||||
else
|
||||
parentRule = static_cast<QgsRuleBasedRendererV2::Rule*>( parent.internalPointer() );
|
||||
|
||||
QgsRuleBasedRendererV2::Rule* childRule = parentRule->children()[row];
|
||||
if ( childRule )
|
||||
return createIndex( row, column, childRule );
|
||||
else
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex QgsRuleBasedRendererV2Model::parent( const QModelIndex &index ) const
|
||||
{
|
||||
if ( !index.isValid() )
|
||||
return QModelIndex();
|
||||
|
||||
QgsRuleBasedRendererV2::Rule* childRule = static_cast<QgsRuleBasedRendererV2::Rule*>( index.internalPointer() );
|
||||
QgsRuleBasedRendererV2::Rule* parentRule = childRule->parent();
|
||||
|
||||
if ( parentRule == mR->rootRule() )
|
||||
return QModelIndex();
|
||||
|
||||
int row = parentRule->children().indexOf( childRule );
|
||||
|
||||
return createIndex( row, 0, parentRule );
|
||||
}
|
||||
|
||||
bool QgsRuleBasedRendererV2Model::setData( const QModelIndex & index, const QVariant & value, int role )
|
||||
{
|
||||
if ( !index.isValid() || role != Qt::EditRole )
|
||||
return false;
|
||||
|
||||
QgsRuleBasedRendererV2::Rule* rule = static_cast<QgsRuleBasedRendererV2::Rule*>( index.internalPointer() );
|
||||
|
||||
switch ( index.column() )
|
||||
{
|
||||
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_item->setFont( 0, italicFont );
|
||||
filter_items[filter] = filter_item;
|
||||
// need to add the item before setFirstColumnSpanned,
|
||||
// see http://qt.nokia.com/developer/task-tracker/index_html?method=entry&id=214686
|
||||
addTopLevelItem( filter_item );
|
||||
filter_item->setFirstColumnSpanned( true );
|
||||
}
|
||||
|
||||
QTreeWidgetItem* item = new QTreeWidgetItem( filter_items[filter] );
|
||||
|
||||
QString txtLabel = rule->label();
|
||||
item->setText( 0, txtLabel );
|
||||
item->setData( 0, Qt::UserRole + 1, i );
|
||||
item->setIcon( 0, QgsSymbolLayerV2Utils::symbolPreviewIcon( rule->symbol(), QSize( 16, 16 ) ) );
|
||||
|
||||
// Displaying filter is redundant here, but keeping it allows to keep constant the layout and width of all columns when switching to one of the two other views
|
||||
item->setText( 1, filter );
|
||||
|
||||
// Makes table layout slightly more readable when filters are long strings
|
||||
//item->setBackground( 1, Qt::lightGray );
|
||||
//item->setBackground( 3, Qt::lightGray );
|
||||
|
||||
if ( rule->dependsOnScale() )
|
||||
{
|
||||
item->setText( 2, formatScale( rule->scaleMinDenom(), mLongestMinDenom ) );
|
||||
item->setText( 3, formatScale( rule->scaleMaxDenom(), mLongestMaxDenom ) );
|
||||
item->setTextAlignment( 2, Qt::AlignRight );
|
||||
item->setTextAlignment( 3, Qt::AlignRight );
|
||||
}
|
||||
|
||||
// Priority (Id): add 1 to rule number and convert to string
|
||||
item->setText( 4, QString( "%1" ).arg( i + 1, 4 ) );
|
||||
item->setTextAlignment( 4, Qt::AlignRight );
|
||||
case 0: // label
|
||||
rule->setLabel( value.toString() );
|
||||
break;
|
||||
case 1: // filter
|
||||
rule->setFilterExpression( value.toString() );
|
||||
break;
|
||||
case 2: // scale min
|
||||
rule->setScaleMinDenom( value.toInt() );
|
||||
break;
|
||||
case 3: // scale max
|
||||
rule->setScaleMaxDenom( value.toInt() );
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
addTopLevelItems( filter_items.values() );
|
||||
|
||||
|
||||
emit dataChanged( index, index );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void QgsRuleBasedRendererV2Model::insertRule( const QModelIndex& parent, int before, QgsRuleBasedRendererV2::Rule* newrule )
|
||||
{
|
||||
beginInsertRows( parent, before, before );
|
||||
|
||||
QgsRuleBasedRendererV2::Rule* parentRule = parent.isValid() ?
|
||||
static_cast<QgsRuleBasedRendererV2::Rule*>( parent.internalPointer() ) : mR->rootRule();
|
||||
parentRule->insertChild( before, newrule );
|
||||
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2Model::updateRule( const QModelIndex& index )
|
||||
{
|
||||
emit dataChanged( index, index );
|
||||
}
|
||||
|
||||
void QgsRuleBasedRendererV2Model::removeRule( const QModelIndex& index )
|
||||
{
|
||||
beginRemoveRows( index.parent(), index.row(), index.row() );
|
||||
|
||||
QgsRuleBasedRendererV2::Rule* rule = static_cast<QgsRuleBasedRendererV2::Rule*>( index.internalPointer() );
|
||||
rule->parent()->removeChild( rule );
|
||||
|
||||
endRemoveRows();
|
||||
}
|
||||
|
@ -23,41 +23,44 @@ class QMenu;
|
||||
|
||||
///////
|
||||
|
||||
#include <QTreeWidget>
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
class GUI_EXPORT QgsRendererRulesTreeWidget : public QTreeWidget
|
||||
/*
|
||||
Tree model for the rules:
|
||||
|
||||
(invalid) == root node
|
||||
+--- top level rule
|
||||
+--- top level rule
|
||||
*/
|
||||
class QgsRuleBasedRendererV2Model : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QgsRendererRulesTreeWidget( QWidget* parent = 0 );
|
||||
QgsRuleBasedRendererV2Model( QgsRuleBasedRendererV2* r );
|
||||
|
||||
void setRenderer( QgsRuleBasedRendererV2* r );
|
||||
virtual Qt::ItemFlags flags( const QModelIndex &index ) const;
|
||||
virtual QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const;
|
||||
virtual QVariant headerData( int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole ) const;
|
||||
virtual int rowCount( const QModelIndex &parent = QModelIndex() ) const;
|
||||
virtual int columnCount( const QModelIndex & = QModelIndex() ) const;
|
||||
//! provide model index for parent's child item
|
||||
virtual QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const;
|
||||
//! provide parent model index
|
||||
virtual QModelIndex parent( const QModelIndex &index ) const;
|
||||
|
||||
enum Grouping { NoGrouping, GroupingByScale, GroupingByFilter };
|
||||
virtual bool setData( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole );
|
||||
|
||||
void setGrouping( Grouping g );
|
||||
// new methods
|
||||
|
||||
void populateRules();
|
||||
void insertRule( const QModelIndex& parent, int before, QgsRuleBasedRendererV2::Rule* newrule );
|
||||
void updateRule( const QModelIndex& index );
|
||||
void removeRule( const QModelIndex& index );
|
||||
|
||||
protected:
|
||||
void populateRulesNoGrouping();
|
||||
void populateRulesGroupByScale();
|
||||
void populateRulesGroupByFilter();
|
||||
|
||||
QTreeWidgetItem* populateRulesNoGrouping( QgsRuleBasedRendererV2::Rule* rule, int i, QTreeWidgetItem* parentItem );
|
||||
|
||||
QString formatScaleRange( int minDenom, int maxDenom );
|
||||
|
||||
QString formatScale( int denom, int size = 0 );
|
||||
|
||||
QgsRuleBasedRendererV2* mR;
|
||||
Grouping mGrouping;
|
||||
|
||||
int mLongestMinDenom;
|
||||
int mLongestMaxDenom;
|
||||
};
|
||||
|
||||
|
||||
///////
|
||||
|
||||
#include "ui_qgsrulebasedrendererv2widget.h"
|
||||
@ -79,12 +82,11 @@ class GUI_EXPORT QgsRuleBasedRendererV2Widget : public QgsRendererV2Widget, priv
|
||||
|
||||
void addRule();
|
||||
void editRule();
|
||||
void editRule( const QModelIndex& index );
|
||||
void removeRule();
|
||||
void moveUp();
|
||||
void moveDown();
|
||||
|
||||
void setGrouping();
|
||||
|
||||
void refineRuleScales();
|
||||
void refineRuleCategories();
|
||||
void refineRuleRanges();
|
||||
@ -94,14 +96,17 @@ class GUI_EXPORT QgsRuleBasedRendererV2Widget : public QgsRendererV2Widget, priv
|
||||
protected:
|
||||
|
||||
void refineRule( int type );
|
||||
QgsRuleBasedRendererV2::RuleList refineRuleCategoriesGui( QgsRuleBasedRendererV2::Rule* initialRule );
|
||||
QgsRuleBasedRendererV2::RuleList refineRuleRangesGui( QgsRuleBasedRendererV2::Rule* initialRule );
|
||||
QgsRuleBasedRendererV2::RuleList refineRuleScalesGui( QgsRuleBasedRendererV2::Rule* initialRule );
|
||||
void refineRuleCategoriesGui( QgsRuleBasedRendererV2::Rule* initialRule );
|
||||
void refineRuleRangesGui( QgsRuleBasedRendererV2::Rule* initialRule );
|
||||
void refineRuleScalesGui( QgsRuleBasedRendererV2::Rule* initialRule );
|
||||
|
||||
QgsRuleBasedRendererV2::Rule* currentRule();
|
||||
|
||||
QList<QgsSymbolV2*> selectedSymbols();
|
||||
void refreshSymbolView();
|
||||
|
||||
QgsRuleBasedRendererV2* mRenderer;
|
||||
QgsRuleBasedRendererV2Model* mModel;
|
||||
|
||||
QMenu* mRefineMenu;
|
||||
};
|
||||
|
@ -11,42 +11,6 @@
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QgsRendererRulesTreeWidget" name="treeRules">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="rootIsDecorated">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="headerHidden">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Label</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Rule</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Min. scale</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Max. scale</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
@ -99,37 +63,6 @@
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Rule grouping</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radNoGrouping">
|
||||
<property name="text">
|
||||
<string comment="No grouping for displaying rules">None</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radGroupFilter">
|
||||
<property name="text">
|
||||
<string comment="Group rules by filter">By filter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radGroupScale">
|
||||
<property name="text">
|
||||
<string comment="Group rules by scale">By scale</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRenderingOrder">
|
||||
<property name="text">
|
||||
@ -140,15 +73,18 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QTreeView" name="viewRules">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QgsRendererRulesTreeWidget</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header>qgsrulebasedrendererv2widget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -84,4 +84,5 @@ ADD_QGIS_TEST(coordinatereferencesystemtest testqgscoordinatereferencesystem.cpp
|
||||
ADD_QGIS_TEST(pointtest testqgspoint.cpp)
|
||||
ADD_QGIS_TEST(searchstringtest testqgssearchstring.cpp)
|
||||
ADD_QGIS_TEST(vectorlayertest testqgsvectorlayer.cpp)
|
||||
ADD_QGIS_TEST(rulebasedrenderertest testqgsrulebasedrenderer.cpp)
|
||||
|
||||
|
96
tests/src/core/testqgsrulebasedrenderer.cpp
Normal file
96
tests/src/core/testqgsrulebasedrenderer.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
/***************************************************************************
|
||||
test_template.cpp
|
||||
--------------------------------------
|
||||
Date : Sun Sep 16 12:22:23 AKDT 2007
|
||||
Copyright : (C) 2007 by Gary E. Sherman
|
||||
Email : sherman at mrcc dot 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 <QtTest>
|
||||
#include <QDomDocument>
|
||||
#include <QFile>
|
||||
//header for class being tested
|
||||
#include <qgsrulebasedrendererv2.h>
|
||||
|
||||
#if QT_VERSION < 0x40701
|
||||
// See http://hub.qgis.org/issues/4284
|
||||
Q_DECLARE_METATYPE( QVariant )
|
||||
#endif
|
||||
|
||||
|
||||
class TestQgsRuleBasedRenderer: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
|
||||
void test_load_xml()
|
||||
{
|
||||
QDomDocument doc;
|
||||
xml2domElement( "rulebasedrenderer_simple.xml", doc );
|
||||
QDomElement elem = doc.documentElement();
|
||||
|
||||
QgsRuleBasedRendererV2* r = static_cast<QgsRuleBasedRendererV2*>( QgsRuleBasedRendererV2::create( elem ) );
|
||||
QVERIFY( r );
|
||||
check_tree_valid( r->rootRule() );
|
||||
delete r;
|
||||
}
|
||||
|
||||
void test_load_invalid_xml()
|
||||
{
|
||||
QDomDocument doc;
|
||||
xml2domElement( "rulebasedrenderer_invalid.xml", doc );
|
||||
QDomElement elem = doc.documentElement();
|
||||
|
||||
QgsRuleBasedRendererV2* r = static_cast<QgsRuleBasedRendererV2*>( QgsRuleBasedRendererV2::create( elem ) );
|
||||
QVERIFY( r == NULL );
|
||||
}
|
||||
|
||||
private:
|
||||
void xml2domElement( QString testFile, QDomDocument& doc )
|
||||
{
|
||||
QString fileName = QString( TEST_DATA_DIR ) + QDir::separator() + testFile;
|
||||
QFile f(fileName);
|
||||
bool fileOpen = f.open(QIODevice::ReadOnly);
|
||||
QVERIFY( fileOpen );
|
||||
|
||||
QString msg;
|
||||
int line, col;
|
||||
bool parse = doc.setContent( &f, &msg, &line, &col );
|
||||
QVERIFY( parse );
|
||||
}
|
||||
|
||||
void check_tree_valid( QgsRuleBasedRendererV2::Rule* root )
|
||||
{
|
||||
// root must always exist (although it does not have children)
|
||||
QVERIFY( root );
|
||||
// and does not have a parent
|
||||
QVERIFY( root->parent() == NULL );
|
||||
|
||||
foreach ( QgsRuleBasedRendererV2::Rule* node, root->children() )
|
||||
check_non_root_rule( node );
|
||||
}
|
||||
|
||||
void check_non_root_rule( QgsRuleBasedRendererV2::Rule* node )
|
||||
{
|
||||
qDebug() << node->dump();
|
||||
// children must not be NULL
|
||||
QVERIFY( node );
|
||||
// and must have a parent
|
||||
QVERIFY( node->parent() );
|
||||
// check that all children are okay
|
||||
foreach ( QgsRuleBasedRendererV2::Rule* child, node->children() )
|
||||
check_non_root_rule( child );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
QTEST_MAIN( TestQgsRuleBasedRenderer )
|
||||
|
||||
#include "moc_testqgsrulebasedrenderer.cxx"
|
||||
|
@ -7,10 +7,13 @@ SET (util_SRCS ../core/qgsrenderchecker.cpp)
|
||||
# the UI file won't be wrapped!
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../../../src/ui
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../core #for render checker class
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/symbology-ng
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/raster
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/symbology-ng
|
||||
${QT_INCLUDE_DIR}
|
||||
${GDAL_INCLUDE_DIR}
|
||||
${PROJ_INCLUDE_DIR}
|
||||
@ -73,4 +76,23 @@ ENDIF (APPLE)
|
||||
#ENDIF (APPLE)
|
||||
|
||||
|
||||
# a simple app for testing GUI of renderers
|
||||
|
||||
SET(rendererv2gui_SRCS testrendererv2gui.cpp)
|
||||
SET(rendererv2gui_HDRS testrendererv2gui.h)
|
||||
|
||||
QT4_WRAP_CPP(rendererv2gui_MOC_SRCS ${rendererv2gui_HDRS})
|
||||
|
||||
ADD_EXECUTABLE(qgis_rendererv2gui ${rendererv2gui_SRCS} ${rendererv2gui_MOC_SRCS})
|
||||
|
||||
TARGET_LINK_LIBRARIES(qgis_rendererv2gui
|
||||
qgis_core
|
||||
qgis_gui
|
||||
${QT_QTCORE_LIBRARY}
|
||||
${QT_QTNETWORK_LIBRARY}
|
||||
${QT_QTSVG_LIBRARY}
|
||||
${QT_QTXML_LIBRARY}
|
||||
${QT_QTWEBKIT_LIBRARY}
|
||||
${QT_QTMAIN_LIBRARY}
|
||||
#${QT_QTTEST_LIBRARY}
|
||||
)
|
||||
|
84
tests/src/gui/testrendererv2gui.cpp
Normal file
84
tests/src/gui/testrendererv2gui.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
#include "testrendererv2gui.h"
|
||||
|
||||
#include <qgsapplication.h>
|
||||
#include <qgsmapcanvas.h>
|
||||
#include <qgsvectorlayer.h>
|
||||
#include <qgsmaplayerregistry.h>
|
||||
#include <qgsproject.h>
|
||||
#include <qgsrendererv2propertiesdialog.h>
|
||||
#include <qgsstylev2.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QToolBar>
|
||||
|
||||
TestRendererV2GUI::TestRendererV2GUI(QWidget *parent) :
|
||||
QMainWindow(parent)
|
||||
{
|
||||
resize(640,480);
|
||||
|
||||
QToolBar* toolBar = addToolBar("Actions");
|
||||
toolBar->addAction( "set renderer", this, SLOT(setRenderer()) );
|
||||
|
||||
mMapCanvas = new QgsMapCanvas(this);
|
||||
mMapCanvas->setCanvasColor( Qt::white );
|
||||
setCentralWidget(mMapCanvas);
|
||||
|
||||
connect( QgsProject::instance(), SIGNAL(readProject(QDomDocument)), mMapCanvas, SLOT(readProject(QDomDocument)));
|
||||
}
|
||||
|
||||
void TestRendererV2GUI::loadLayers()
|
||||
{
|
||||
// load just first vector layer
|
||||
QList<QgsMapCanvasLayer> canvasLayers;
|
||||
foreach (QgsMapLayer* layer, QgsMapLayerRegistry::instance()->mapLayers().values())
|
||||
{
|
||||
if ( layer->type() == QgsMapLayer::VectorLayer )
|
||||
canvasLayers << QgsMapCanvasLayer( layer );
|
||||
}
|
||||
|
||||
mMapCanvas->setLayerSet(canvasLayers);
|
||||
}
|
||||
|
||||
void TestRendererV2GUI::setRenderer()
|
||||
{
|
||||
QgsMapLayer* layer = mMapCanvas->layer(0);
|
||||
Q_ASSERT( layer );
|
||||
Q_ASSERT( layer->type() == QgsMapLayer::VectorLayer );
|
||||
QgsVectorLayer* vlayer = static_cast<QgsVectorLayer*>(layer);
|
||||
|
||||
QgsRendererV2PropertiesDialog dlg( vlayer, QgsStyleV2::defaultStyle() );
|
||||
dlg.exec();
|
||||
|
||||
mMapCanvas->refresh();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
if ( argc < 2 )
|
||||
{
|
||||
qDebug( "Provide a project file name with at least one vector layer!" );
|
||||
return 1;
|
||||
}
|
||||
|
||||
QgsApplication::init();
|
||||
QgsApplication::initQgis();
|
||||
|
||||
TestRendererV2GUI gui;
|
||||
|
||||
QString projectFileName( argv[1] );
|
||||
QgsProject::instance()->setFileName( projectFileName );
|
||||
bool res = QgsProject::instance()->read();
|
||||
if ( !res )
|
||||
{
|
||||
qDebug("Failed to open project!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// the layers are in the registry - now load them!
|
||||
gui.loadLayers();
|
||||
|
||||
gui.show();
|
||||
return app.exec();
|
||||
}
|
24
tests/src/gui/testrendererv2gui.h
Normal file
24
tests/src/gui/testrendererv2gui.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef TESTRENDERERV2GUI_H
|
||||
#define TESTRENDERERV2GUI_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
class QgsMapCanvas;
|
||||
|
||||
class TestRendererV2GUI : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestRendererV2GUI(QWidget *parent = 0);
|
||||
void loadLayers();
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
void setRenderer();
|
||||
|
||||
protected:
|
||||
QgsMapCanvas* mMapCanvas;
|
||||
};
|
||||
|
||||
#endif // TESTRENDERERV2GUI_H
|
2
tests/testdata/rulebasedrenderer_invalid.xml
vendored
Normal file
2
tests/testdata/rulebasedrenderer_invalid.xml
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
<renderer-v2 symbollevels="0" type="RuleRenderer">
|
||||
</renderer-v2>
|
32
tests/testdata/rulebasedrenderer_simple.xml
vendored
Normal file
32
tests/testdata/rulebasedrenderer_simple.xml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<renderer-v2 symbollevels="0" type="RuleRenderer">
|
||||
<rules>
|
||||
<rule filter="type=3" symbol="0" label="type3"/>
|
||||
<rule filter="type=1" symbol="1" label="type1"/>
|
||||
</rules>
|
||||
<symbols>
|
||||
<symbol outputUnit="MM" alpha="1" type="line" name="0">
|
||||
<layer pass="0" class="SimpleLine" locked="0">
|
||||
<prop k="capstyle" v="square"/>
|
||||
<prop k="color" v="220,0,0,255"/>
|
||||
<prop k="customdash" v="5;2"/>
|
||||
<prop k="joinstyle" v="bevel"/>
|
||||
<prop k="offset" v="0"/>
|
||||
<prop k="penstyle" v="solid"/>
|
||||
<prop k="use_custom_dash" v="0"/>
|
||||
<prop k="width" v="0.26"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
<symbol outputUnit="MM" alpha="1" type="line" name="1">
|
||||
<layer pass="0" class="SimpleLine" locked="0">
|
||||
<prop k="capstyle" v="square"/>
|
||||
<prop k="color" v="94,116,254,255"/>
|
||||
<prop k="customdash" v="5;2"/>
|
||||
<prop k="joinstyle" v="bevel"/>
|
||||
<prop k="offset" v="0"/>
|
||||
<prop k="penstyle" v="solid"/>
|
||||
<prop k="use_custom_dash" v="0"/>
|
||||
<prop k="width" v="0.26"/>
|
||||
</layer>
|
||||
</symbol>
|
||||
</symbols>
|
||||
</renderer-v2>
|
Loading…
x
Reference in New Issue
Block a user