From 8db77fcff73ab5c8f3bde9cca132fc59569760e7 Mon Sep 17 00:00:00 2001 From: Martin Dobias Date: Fri, 24 Oct 2014 12:15:47 +0700 Subject: [PATCH] Fix Andreas' problem with checkboxes in legend + update SIP bindings The problem was that rule-based renderer allowed cloned rules to have the same unique rule key. That in turn created the confusion with checkboxes in legend. Now rules always have new rule key when cloned. The only exception is when the whole renderer is cloned - in such case we preserve their rule keys, so that other components (legend / visibility presets) can still keep using the original rule keys. Projects where this problem appears need to be fixed - the easiest way is to select all rules, copy&paste them and remove the previous rules. --- .../core/symbology-ng/qgsrulebasedrendererv2.sip | 15 +++++++++++++++ src/core/symbology-ng/qgsrulebasedrendererv2.cpp | 14 ++++++++++++-- src/core/symbology-ng/qgsrulebasedrendererv2.h | 3 +++ .../symbology-ng/qgsrulebasedrendererv2widget.cpp | 6 +++++- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/python/core/symbology-ng/qgsrulebasedrendererv2.sip b/python/core/symbology-ng/qgsrulebasedrendererv2.sip index 1e57f8276ac..b45f29fd784 100644 --- a/python/core/symbology-ng/qgsrulebasedrendererv2.sip +++ b/python/core/symbology-ng/qgsrulebasedrendererv2.sip @@ -76,6 +76,15 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2 QgsExpression* filter() const; QString filterExpression() const; QString description() const; + //! @note added in 2.6 + bool checkState() const; + + //! Unique rule identifier (for identification of rule within renderer) + //! @note added in 2.6 + QString ruleKey() const; + //! Override the assigned rule key (should be used just internally by rule-based renderer) + //! @note added in 2.6 + void setRuleKey( const QString& key ); //! set a new symbol (or NULL). Deletes old symbol. void setSymbol( QgsSymbolV2* sym /Transfer/ ); @@ -84,6 +93,8 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2 void setScaleMaxDenom( int scaleMaxDenom ); void setFilterExpression( QString filterExp ); void setDescription( QString description ); + //! @note added in 2.6 + void setCheckState( bool state ); //! clone this rule, return new instance QgsRuleBasedRendererV2::Rule* clone() const /Factory/; @@ -135,6 +146,10 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2 //! take child rule out, set parent as null QgsRuleBasedRendererV2::Rule* takeChildAt( int i ) /TransferBack/; + //! Try to find a rule given its unique key + //! @note added in 2.6 + QgsRuleBasedRendererV2::Rule* findRuleByKey( QString key ); + void updateElseRules(); void setIsElse( bool iselse ); diff --git a/src/core/symbology-ng/qgsrulebasedrendererv2.cpp b/src/core/symbology-ng/qgsrulebasedrendererv2.cpp index 2080a0779c9..6d282c3f10c 100644 --- a/src/core/symbology-ng/qgsrulebasedrendererv2.cpp +++ b/src/core/symbology-ng/qgsrulebasedrendererv2.cpp @@ -257,7 +257,6 @@ QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2::Rule::clone() const { QgsSymbolV2* sym = mSymbol ? mSymbol->clone() : NULL; Rule* newrule = new Rule( sym, mScaleMinDenom, mScaleMaxDenom, mFilterExp, mLabel, mDescription ); - newrule->mRuleKey = mRuleKey; newrule->setCheckState( mCheckState ); // clone children foreach ( Rule* rule, mChildren ) @@ -850,7 +849,18 @@ QList QgsRuleBasedRendererV2::usedAttributes() QgsFeatureRendererV2* QgsRuleBasedRendererV2::clone() const { - QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( mRootRule->clone() ); + QgsRuleBasedRendererV2::Rule* clonedRoot = mRootRule->clone(); + + // normally with clone() the individual rules get new keys (UUID), but here we want to keep + // the tree of rules intact, so that other components that may use the rule keys work nicely (e.g. visibility presets) + clonedRoot->setRuleKey( mRootRule->ruleKey() ); + RuleList origDescendants = mRootRule->descendants(); + RuleList clonedDescendants = clonedRoot->descendants(); + Q_ASSERT( origDescendants.count() == clonedDescendants.count() ); + for ( int i = 0; i < origDescendants.count(); ++i ) + clonedDescendants[i]->setRuleKey( origDescendants[i]->ruleKey() ); + + QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( clonedRoot ); r->setUsingSymbolLevels( usingSymbolLevels() ); return r; diff --git a/src/core/symbology-ng/qgsrulebasedrendererv2.h b/src/core/symbology-ng/qgsrulebasedrendererv2.h index bfc2b280e6d..83ffa43af8f 100644 --- a/src/core/symbology-ng/qgsrulebasedrendererv2.h +++ b/src/core/symbology-ng/qgsrulebasedrendererv2.h @@ -113,6 +113,9 @@ class CORE_EXPORT QgsRuleBasedRendererV2 : public QgsFeatureRendererV2 //! Unique rule identifier (for identification of rule within renderer) //! @note added in 2.6 QString ruleKey() const { return mRuleKey; } + //! Override the assigned rule key (should be used just internally by rule-based renderer) + //! @note added in 2.6 + void setRuleKey( const QString& key ) { mRuleKey = key; } //! set a new symbol (or NULL). Deletes old symbol. void setSymbol( QgsSymbolV2* sym ); diff --git a/src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp b/src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp index 057e77744c9..32e413f2759 100644 --- a/src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp +++ b/src/gui/symbology-ng/qgsrulebasedrendererv2widget.cpp @@ -938,7 +938,9 @@ QMimeData *QgsRuleBasedRendererV2Model::mimeData( const QModelIndexList &indexes if ( !index.isValid() || index.column() != 0 ) continue; - QgsRuleBasedRendererV2::Rule* rule = ruleForIndex( index ); + // we use a clone of the existing rule because it has a new unique rule key + // non-unique rule keys would confuse other components using them (e.g. legend) + QgsRuleBasedRendererV2::Rule* rule = ruleForIndex( index )->clone(); QDomDocument doc; QgsSymbolV2Map symbols; @@ -949,6 +951,8 @@ QMimeData *QgsRuleBasedRendererV2Model::mimeData( const QModelIndexList &indexes rootElem.appendChild( symbolsElem ); doc.appendChild( rootElem ); + delete rule; + stream << doc.toString( -1 ); }