Skip to content
Permalink
Browse files

Fix crash when using the identify tool on a categorized render

with an unchecked category corresponding to the feature at the
clicked point

Also fix count of default category symbols
  • Loading branch information
nyalldawson committed Mar 1, 2018
1 parent 4e182be commit 0acdcfadfd938c7bbe4cabfdc63ba5267a2475a9
@@ -45,7 +45,22 @@ copy constructor
void setLabel( const QString &label );

bool renderState() const;
%Docstring
Returns true if the category is currently enabled and should be rendered.

.. seealso:: :py:func:`setRenderState`

.. versionadded:: 2.5
%End

void setRenderState( bool render );
%Docstring
Sets whether the category is currently enabled and should be rendered.

.. seealso:: :py:func:`renderState`

.. versionadded:: 2.5
%End

QString dump() const;

@@ -252,9 +267,36 @@ Will return null if the functionality is disabled.
hashtable for faster access to symbols
%End

QgsSymbol *skipRender();
QgsSymbol *skipRender() /Deprecated/;
%Docstring

QgsSymbol *symbolForValue( const QVariant &value );
.. deprecated:: No longer used, will be removed in QGIS 4.0
%End

QgsSymbol *symbolForValue( const QVariant &value ) /Deprecated/;
%Docstring
Returns the matching symbol corresponding to an attribute ``value``.

.. deprecated:: use variant which takes a second bool argument instead.
%End


QgsSymbol *symbolForValue( const QVariant &value, bool &foundMatchingSymbol /Out/ ) /PyName=symbolForValue2/;
%Docstring
Returns the matching symbol corresponding to an attribute ``value``.

Will return None if no matching symbol was found for ``value``, or
if the category corresponding to ``value`` is currently disabled (see QgsRendererCategory.renderState()).

If ``foundMatchingSymbol`` is specified then it will be set to true if
a matching category was found. This can be used to differentiate between
a None returned as a result of no matching category vs a None as a result
of disabled categories.

.. note::

available in Python bindings as symbolForValue2
%End

private:
QgsCategorizedSymbolRenderer( const QgsCategorizedSymbolRenderer & );
@@ -849,6 +849,7 @@ Unregister a previously registered custom drop ``handler`` for layout windows.
%End



virtual void openURL( const QString &url, bool useQgisDocDirectory = true ) = 0 /Deprecated/;
%Docstring
Open a url in the users browser. By default the QGIS doc directory is used
@@ -16,7 +16,7 @@ class QgsMapServiceException : QgsOgcServiceException
%Docstring
Exception class for WMS service exceptions (for compatibility only).

\deprecated Use QsgServerException
.. deprecated:: Use QsgServerException

The most important codes are:
* "InvalidFormat"
@@ -192,6 +192,9 @@ sub processDoxygenLine {
if ( $line =~ m/\\since .*?([\d\.]+)/i ) {
return "\n.. versionadded:: $1\n";
}
if ( $line =~ m/\\deprecated (.*)/i ) {
return "\n.. deprecated:: $1\n";
}

# create links in see also
if ( $line =~ m/\\see +(\w+(\.\w+)*)(\([^()]*\))?/ ) {
@@ -596,7 +599,7 @@ sub detect_non_method_member{
next;
}
# Skip Q_OBJECT, Q_PROPERTY, Q_ENUM, Q_GADGET etc.
if ($LINE =~ m/^\s*Q_(OBJECT|ENUMS|ENUM|FLAG|PROPERTY|GADGET|DECLARE_METATYPE|DECLARE_TYPEINFO|DECL_DEPRECATED|NOWARN_DEPRECATED_(PUSH|POP))\b.*?$/){
if ($LINE =~ m/^\s*Q_(OBJECT|ENUMS|ENUM|FLAG|PROPERTY|GADGET|DECLARE_METATYPE|DECLARE_TYPEINFO|NOWARN_DEPRECATED_(PUSH|POP))\b.*?$/){
next;
}

@@ -848,7 +851,8 @@ sub detect_non_method_member{
$LINE =~ s/\s*\boverride\b//;
$LINE =~ s/\s*\bextern \b//;
$LINE =~ s/\s*\bMAYBE_UNUSED \b//;
$LINE =~ s/\s*\bNODISCARD \b//;
$LINE =~ s/\s*\bNODISCARD \b//;
$LINE =~ s/\s*\bQ_DECL_DEPRECATED\b//;
$LINE =~ s/^(\s*)?(const )?(virtual |static )?inline /$1$2$3/;
$LINE =~ s/\bconstexpr\b/const/;
$LINE =~ s/\bnullptr\b/0/g;
@@ -168,21 +168,25 @@ void QgsCategorizedSymbolRenderer::rebuildHash()
for ( int i = 0; i < mCategories.size(); ++i )
{
const QgsRendererCategory &cat = mCategories.at( i );
mSymbolHash.insert( cat.value().toString(), ( cat.renderState() || mCounting ) ? cat.symbol() : skipRender() );
mSymbolHash.insert( cat.value().toString(), ( cat.renderState() || mCounting ) ? cat.symbol() : nullptr );
}
}

QgsSymbol *QgsCategorizedSymbolRenderer::skipRender()
{
static QgsMarkerSymbol *skipRender = nullptr;
if ( !skipRender )
skipRender = new QgsMarkerSymbol();

return skipRender;
return nullptr;
}

QgsSymbol *QgsCategorizedSymbolRenderer::symbolForValue( const QVariant &value )
{
bool found = false;
return symbolForValue( value, found );
}

QgsSymbol *QgsCategorizedSymbolRenderer::symbolForValue( const QVariant &value, bool &foundMatchingSymbol )
{
foundMatchingSymbol = false;

// TODO: special case for int, double
QHash<QString, QgsSymbol *>::const_iterator it = mSymbolHash.constFind( value.isNull() ? QLatin1String( "" ) : value.toString() );
if ( it == mSymbolHash.constEnd() )
@@ -198,6 +202,8 @@ QgsSymbol *QgsCategorizedSymbolRenderer::symbolForValue( const QVariant &value )
return nullptr;
}

foundMatchingSymbol = true;

return *it;
}

@@ -228,15 +234,14 @@ QgsSymbol *QgsCategorizedSymbolRenderer::originalSymbolForFeature( QgsFeature &f
{
QVariant value = valueForFeature( feature, context );

bool foundCategory = false;
// find the right symbol for the category
QgsSymbol *symbol = symbolForValue( value );
if ( symbol == skipRender() )
return nullptr;
QgsSymbol *symbol = symbolForValue( value, foundCategory );

if ( !symbol )
if ( !foundCategory )
{
// if no symbol found use default one
return symbolForValue( QVariant( "" ) );
// if no symbol found, use default symbol
return symbolForValue( QVariant( "" ), foundCategory );
}

return symbol;
@@ -793,7 +798,7 @@ QSet<QString> QgsCategorizedSymbolRenderer::legendKeysForFeature( QgsFeature &fe
{
if ( value == cat.value() )
{
if ( cat.renderState() )
if ( cat.renderState() || mCounting )
return QSet< QString >() << QString::number( i );
else
return QSet< QString >();
@@ -56,8 +56,18 @@ class CORE_EXPORT QgsRendererCategory
void setSymbol( QgsSymbol *s SIP_TRANSFER );
void setLabel( const QString &label );

// \since QGIS 2.5
/**
* Returns true if the category is currently enabled and should be rendered.
* \see setRenderState()
* \since QGIS 2.5
*/
bool renderState() const;

/**
* Sets whether the category is currently enabled and should be rendered.
* \see renderState()
* \since QGIS 2.5
*/
void setRenderState( bool render );

// debugging
@@ -233,9 +243,33 @@ class CORE_EXPORT QgsCategorizedSymbolRenderer : public QgsFeatureRenderer

void rebuildHash();

QgsSymbol *skipRender();
/**
* \deprecated No longer used, will be removed in QGIS 4.0
*/
Q_DECL_DEPRECATED QgsSymbol *skipRender() SIP_DEPRECATED;

/**
* Returns the matching symbol corresponding to an attribute \a value.
* \deprecated use variant which takes a second bool argument instead.
*/
Q_DECL_DEPRECATED QgsSymbol *symbolForValue( const QVariant &value ) SIP_DEPRECATED;

QgsSymbol *symbolForValue( const QVariant &value );
// TODO QGIS 4.0 - rename Python method to symbolForValue

/**
* Returns the matching symbol corresponding to an attribute \a value.
*
* Will return nullptr if no matching symbol was found for \a value, or
* if the category corresponding to \a value is currently disabled (see QgsRendererCategory::renderState()).
*
* If \a foundMatchingSymbol is specified then it will be set to true if
* a matching category was found. This can be used to differentiate between
* a nullptr returned as a result of no matching category vs a nullptr as a result
* of disabled categories.
*
* \note available in Python bindings as symbolForValue2
*/
QgsSymbol *symbolForValue( const QVariant &value, bool &foundMatchingSymbol SIP_OUT ) SIP_PYNAME( symbolForValue2 );

private:
#ifdef SIP_RUN

0 comments on commit 0acdcfa

Please sign in to comment.
You can’t perform that action at this time.