mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-07 00:03:52 -05:00
Merge pull request #50200 from troopa81/fix_legend_geomgenerator
Fix legend icon geom generator is involved
This commit is contained in:
commit
2d1e3fb387
@ -125,7 +125,7 @@ Returns the symbol's type.
|
|||||||
%End
|
%End
|
||||||
|
|
||||||
|
|
||||||
QgsSymbolLayerList symbolLayers();
|
QgsSymbolLayerList symbolLayers() const;
|
||||||
%Docstring
|
%Docstring
|
||||||
Returns the list of symbol layers contained in the symbol.
|
Returns the list of symbol layers contained in the symbol.
|
||||||
|
|
||||||
@ -780,7 +780,6 @@ Render editing vertex marker at specified point
|
|||||||
QgsSymbol( const QgsSymbol & );
|
QgsSymbol( const QgsSymbol & );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* This file has been generated automatically from *
|
* This file has been generated automatically from *
|
||||||
* *
|
* *
|
||||||
|
|||||||
@ -971,7 +971,7 @@ Returns -1 if the ``renderer`` is not animated.
|
|||||||
.. versionadded:: 3.26
|
.. versionadded:: 3.26
|
||||||
%End
|
%End
|
||||||
|
|
||||||
static QgsSymbol *restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height );
|
static QgsSymbol *restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height, bool *ok = 0 );
|
||||||
%Docstring
|
%Docstring
|
||||||
Creates a new symbol with size restricted to min/max size if original size is out of min/max range
|
Creates a new symbol with size restricted to min/max size if original size is out of min/max range
|
||||||
|
|
||||||
@ -980,9 +980,13 @@ Creates a new symbol with size restricted to min/max size if original size is ou
|
|||||||
:param maxSize: the maximum size in mm
|
:param maxSize: the maximum size in mm
|
||||||
:param context: the render context
|
:param context: the render context
|
||||||
:param width: expected width, can be changed by the function
|
:param width: expected width, can be changed by the function
|
||||||
:param height: expected height, can be changed by this function
|
:param height: expected height, can be changed by the function
|
||||||
|
:param ok: if not None, ok is set to false if it's not possible to compute a restricted symbol (if geometry generators
|
||||||
|
are involved for instance)
|
||||||
|
|
||||||
:return: 0 if size is within minSize/maxSize range. New symbol if size was out of min/max range. Caller takes ownership
|
:return: None if size is within minSize/maxSize range or if it's not possible to compute a
|
||||||
|
restricted size symbol. New symbol if size was out of min/max range.
|
||||||
|
Caller takes ownership
|
||||||
%End
|
%End
|
||||||
|
|
||||||
static QgsStringMap evaluatePropertiesMap( const QMap<QString, QgsProperty> &propertiesMap, const QgsExpressionContext &context );
|
static QgsStringMap evaluatePropertiesMap( const QMap<QString, QgsProperty> &propertiesMap, const QgsExpressionContext &context );
|
||||||
@ -997,8 +1001,6 @@ Evaluates a map of properties using the given ``context`` and returns a variant
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* This file has been generated automatically from *
|
* This file has been generated automatically from *
|
||||||
* *
|
* *
|
||||||
|
|||||||
@ -37,6 +37,7 @@
|
|||||||
#include "qgsmarkersymbol.h"
|
#include "qgsmarkersymbol.h"
|
||||||
#include "qgsvariantutils.h"
|
#include "qgsvariantutils.h"
|
||||||
#include "qgslayertreelayer.h"
|
#include "qgslayertreelayer.h"
|
||||||
|
#include "qgsgeometrygeneratorsymbollayer.h"
|
||||||
|
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
|
|
||||||
@ -343,25 +344,29 @@ QSize QgsSymbolLegendNode::minimumIconSize( QgsRenderContext *context ) const
|
|||||||
const int iconSize = QgsLayerTreeModel::scaleIconSize( 16 );
|
const int iconSize = QgsLayerTreeModel::scaleIconSize( 16 );
|
||||||
const int largeIconSize = QgsLayerTreeModel::scaleIconSize( 512 );
|
const int largeIconSize = QgsLayerTreeModel::scaleIconSize( 512 );
|
||||||
QSize minSz( iconSize, iconSize );
|
QSize minSz( iconSize, iconSize );
|
||||||
if ( mItem.symbol() && mItem.symbol()->type() == Qgis::SymbolType::Marker )
|
if ( mItem.symbol() && ( mItem.symbol()->type() == Qgis::SymbolType::Marker
|
||||||
|
|| mItem.symbol()->type() == Qgis::SymbolType::Line ) )
|
||||||
{
|
{
|
||||||
|
int maxSize = largeIconSize;
|
||||||
|
|
||||||
// unusued width, height variables
|
// unusued width, height variables
|
||||||
double width = 0.0;
|
double width = 0.0;
|
||||||
double height = 0.0;
|
double height = 0.0;
|
||||||
const std::unique_ptr<QgsSymbol> symbol( QgsSymbolLayerUtils::restrictedSizeSymbol( mItem.symbol(), MINIMUM_SIZE, MAXIMUM_SIZE, context, width, height ) );
|
bool ok;
|
||||||
|
std::unique_ptr<QgsSymbol> symbol( QgsSymbolLayerUtils::restrictedSizeSymbol( mItem.symbol(), MINIMUM_SIZE, MAXIMUM_SIZE, context, width, height, &ok ) );
|
||||||
|
|
||||||
|
if ( !ok && context )
|
||||||
|
{
|
||||||
|
// It's not possible to get a restricted size symbol, so we restrict
|
||||||
|
// pixmap target size to be sure it would fit MAXIMUM_SIZE
|
||||||
|
maxSize = static_cast<int>( std::round( MAXIMUM_SIZE * context->scaleFactor() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
const QSize size( mItem.symbol()->type() == Qgis::SymbolType::Marker ? maxSize : minSz.width(),
|
||||||
|
maxSize );
|
||||||
|
|
||||||
minSz = QgsImageOperation::nonTransparentImageRect(
|
minSz = QgsImageOperation::nonTransparentImageRect(
|
||||||
QgsSymbolLayerUtils::symbolPreviewPixmap( symbol ? symbol.get() : mItem.symbol(), QSize( largeIconSize, largeIconSize ), 0,
|
QgsSymbolLayerUtils::symbolPreviewPixmap( symbol ? symbol.get() : mItem.symbol(), size, 0,
|
||||||
context ).toImage(),
|
|
||||||
minSz,
|
|
||||||
true ).size();
|
|
||||||
}
|
|
||||||
else if ( mItem.symbol() && mItem.symbol()->type() == Qgis::SymbolType::Line )
|
|
||||||
{
|
|
||||||
double width = 0.0;
|
|
||||||
double height = 0.0;
|
|
||||||
const std::unique_ptr<QgsSymbol> symbol( QgsSymbolLayerUtils::restrictedSizeSymbol( mItem.symbol(), MINIMUM_SIZE, MAXIMUM_SIZE, context, width, height ) );
|
|
||||||
minSz = QgsImageOperation::nonTransparentImageRect(
|
|
||||||
QgsSymbolLayerUtils::symbolPreviewPixmap( symbol ? symbol.get() : mItem.symbol(), QSize( minSz.width(), largeIconSize ), 0,
|
|
||||||
context ).toImage(),
|
context ).toImage(),
|
||||||
minSz,
|
minSz,
|
||||||
true ).size();
|
true ).size();
|
||||||
@ -1564,4 +1569,3 @@ void QgsVectorLabelLegendNode::textWidthHeight( double &width, double &height, Q
|
|||||||
height = QgsTextRenderer::textHeight( ctx, textFormat, 'A', true );
|
height = QgsTextRenderer::textHeight( ctx, textFormat, 'A', true );
|
||||||
width = QgsTextRenderer::textWidth( ctx, textFormat, textLines, &fm );
|
width = QgsTextRenderer::textWidth( ctx, textFormat, textLines, &fm );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -160,7 +160,7 @@ class CORE_EXPORT QgsSymbol
|
|||||||
* \see symbolLayerCount
|
* \see symbolLayerCount
|
||||||
* \since QGIS 2.7
|
* \since QGIS 2.7
|
||||||
*/
|
*/
|
||||||
QgsSymbolLayerList symbolLayers() { return mLayers; }
|
QgsSymbolLayerList symbolLayers() const { return mLayers; }
|
||||||
|
|
||||||
#ifndef SIP_RUN
|
#ifndef SIP_RUN
|
||||||
|
|
||||||
@ -856,4 +856,3 @@ class CORE_EXPORT QgsSymbol
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -4983,18 +4983,34 @@ double QgsSymbolLayerUtils::rendererFrameRate( const QgsFeatureRenderer *rendere
|
|||||||
return visitor.refreshRate;
|
return visitor.refreshRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height )
|
QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height, bool *ok )
|
||||||
{
|
{
|
||||||
if ( !s || !context )
|
if ( !s || !context )
|
||||||
{
|
{
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ok )
|
||||||
|
*ok = true;
|
||||||
|
|
||||||
double size;
|
double size;
|
||||||
const QgsMarkerSymbol *markerSymbol = dynamic_cast<const QgsMarkerSymbol *>( s );
|
const QgsMarkerSymbol *markerSymbol = dynamic_cast<const QgsMarkerSymbol *>( s );
|
||||||
const QgsLineSymbol *lineSymbol = dynamic_cast<const QgsLineSymbol *>( s );
|
const QgsLineSymbol *lineSymbol = dynamic_cast<const QgsLineSymbol *>( s );
|
||||||
if ( markerSymbol )
|
if ( markerSymbol )
|
||||||
{
|
{
|
||||||
|
const QgsSymbolLayerList sls = s->symbolLayers();
|
||||||
|
for ( const QgsSymbolLayer *sl : std::as_const( sls ) )
|
||||||
|
{
|
||||||
|
// geometry generators involved, there is no way to get a restricted size symbol
|
||||||
|
if ( sl->type() != Qgis::SymbolType::Marker )
|
||||||
|
{
|
||||||
|
if ( ok )
|
||||||
|
*ok = false;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size = markerSymbol->size( *context );
|
size = markerSymbol->size( *context );
|
||||||
}
|
}
|
||||||
else if ( lineSymbol )
|
else if ( lineSymbol )
|
||||||
@ -5003,7 +5019,10 @@ QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 0; //not size restriction implemented for other symbol types
|
if ( ok )
|
||||||
|
*ok = false;
|
||||||
|
|
||||||
|
return nullptr; //not size restriction implemented for other symbol types
|
||||||
}
|
}
|
||||||
|
|
||||||
size /= context->scaleFactor();
|
size /= context->scaleFactor();
|
||||||
@ -5018,7 +5037,8 @@ QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 0;
|
// no need to restricted size symbol
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( markerSymbol )
|
if ( markerSymbol )
|
||||||
@ -5038,7 +5058,8 @@ QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double
|
|||||||
height = size;
|
height = size;
|
||||||
return ls;
|
return ls;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QgsStringMap QgsSymbolLayerUtils::evaluatePropertiesMap( const QMap<QString, QgsProperty> &propertiesMap, const QgsExpressionContext &context )
|
QgsStringMap QgsSymbolLayerUtils::evaluatePropertiesMap( const QMap<QString, QgsProperty> &propertiesMap, const QgsExpressionContext &context )
|
||||||
@ -5051,4 +5072,3 @@ QgsStringMap QgsSymbolLayerUtils::evaluatePropertiesMap( const QMap<QString, Qgs
|
|||||||
}
|
}
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -881,10 +881,14 @@ class CORE_EXPORT QgsSymbolLayerUtils
|
|||||||
* \param maxSize the maximum size in mm
|
* \param maxSize the maximum size in mm
|
||||||
* \param context the render context
|
* \param context the render context
|
||||||
* \param width expected width, can be changed by the function
|
* \param width expected width, can be changed by the function
|
||||||
* \param height expected height, can be changed by this function
|
* \param height expected height, can be changed by the function
|
||||||
* \return 0 if size is within minSize/maxSize range. New symbol if size was out of min/max range. Caller takes ownership
|
* \param ok if not nullptr, ok is set to false if it's not possible to compute a restricted symbol (if geometry generators
|
||||||
|
* are involved for instance)
|
||||||
|
* \return nullptr if size is within minSize/maxSize range or if it's not possible to compute a
|
||||||
|
* restricted size symbol. New symbol if size was out of min/max range.
|
||||||
|
* Caller takes ownership
|
||||||
*/
|
*/
|
||||||
static QgsSymbol *restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height );
|
static QgsSymbol *restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height, bool *ok = nullptr );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates a map of properties using the given \a context and returns a variant map with evaluated expressions from the properties.
|
* Evaluates a map of properties using the given \a context and returns a variant map with evaluated expressions from the properties.
|
||||||
@ -925,5 +929,3 @@ class QPolygonF;
|
|||||||
QList<QPolygonF> offsetLine( QPolygonF polyline, double dist, QgsWkbTypes::GeometryType geometryType ) SIP_SKIP;
|
QList<QPolygonF> offsetLine( QPolygonF polyline, double dist, QgsWkbTypes::GeometryType geometryType ) SIP_SKIP;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,9 @@
|
|||||||
#include "qgslegendsettings.h"
|
#include "qgslegendsettings.h"
|
||||||
#include "qgsmarkersymbol.h"
|
#include "qgsmarkersymbol.h"
|
||||||
#include "qgsannotationlayer.h"
|
#include "qgsannotationlayer.h"
|
||||||
|
#include "qgsgeometrygeneratorsymbollayer.h"
|
||||||
|
#include "qgsfillsymbol.h"
|
||||||
|
#include "qgsfillsymbollayer.h"
|
||||||
#include <QSignalSpy>
|
#include <QSignalSpy>
|
||||||
|
|
||||||
class TestQgsLayerTree : public QObject
|
class TestQgsLayerTree : public QObject
|
||||||
@ -46,7 +49,10 @@ class TestQgsLayerTree : public QObject
|
|||||||
void testCheckStateHiearchical();
|
void testCheckStateHiearchical();
|
||||||
void testCheckStateMutuallyExclusive();
|
void testCheckStateMutuallyExclusive();
|
||||||
void testCheckStateMutuallyExclusiveEdgeCases();
|
void testCheckStateMutuallyExclusiveEdgeCases();
|
||||||
|
void testRestrictedSymbolSize_data();
|
||||||
void testRestrictedSymbolSize();
|
void testRestrictedSymbolSize();
|
||||||
|
void testRestrictedSymbolSizeWithGeometryGenerator_data();
|
||||||
|
void testRestrictedSymbolSizeWithGeometryGenerator();
|
||||||
void testShowHideAllSymbolNodes();
|
void testShowHideAllSymbolNodes();
|
||||||
void testFindLegendNode();
|
void testFindLegendNode();
|
||||||
void testLegendSymbolCategorized();
|
void testLegendSymbolCategorized();
|
||||||
@ -304,10 +310,26 @@ void TestQgsLayerTree::testCheckStateMutuallyExclusiveEdgeCases()
|
|||||||
delete root3;
|
delete root3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestQgsLayerTree::testRestrictedSymbolSize_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<double>( "maxSize" );
|
||||||
|
QTest::addColumn<int>( "expectedSize" );
|
||||||
|
|
||||||
|
// QTest::newRow( "smaller than max" ) << 15. << 52;
|
||||||
|
QTest::newRow( "bigger than max" ) << 10. << 40;
|
||||||
|
}
|
||||||
|
|
||||||
void TestQgsLayerTree::testRestrictedSymbolSize()
|
void TestQgsLayerTree::testRestrictedSymbolSize()
|
||||||
{
|
{
|
||||||
|
QFETCH( double, maxSize );
|
||||||
|
QFETCH( int, expectedSize );
|
||||||
|
|
||||||
|
// to force re-read of max/min size in QgsSymbolLegendNode constructor
|
||||||
|
QgsSymbolLegendNode::MINIMUM_SIZE = -1;
|
||||||
|
QgsSymbolLegendNode::MAXIMUM_SIZE = -1;
|
||||||
|
|
||||||
QgsSettings settings;
|
QgsSettings settings;
|
||||||
settings.setValue( "/qgis/legendsymbolMaximumSize", 15.0 );
|
settings.setValue( "/qgis/legendsymbolMaximumSize", maxSize );
|
||||||
|
|
||||||
//new memory layer
|
//new memory layer
|
||||||
QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "Point?field=col1:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );
|
QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "Point?field=col1:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );
|
||||||
@ -337,7 +359,71 @@ void TestQgsLayerTree::testRestrictedSymbolSize()
|
|||||||
|
|
||||||
const QList<QgsLayerTreeModelLegendNode *> nodes = m->layerLegendNodes( n );
|
const QList<QgsLayerTreeModelLegendNode *> nodes = m->layerLegendNodes( n );
|
||||||
const QSize minimumSize = static_cast< QgsSymbolLegendNode *>( nodes.at( 0 ) )->minimumIconSize();
|
const QSize minimumSize = static_cast< QgsSymbolLegendNode *>( nodes.at( 0 ) )->minimumIconSize();
|
||||||
QCOMPARE( minimumSize.width(), 52 );
|
QCOMPARE( minimumSize.width(), expectedSize );
|
||||||
|
|
||||||
|
//cleanup
|
||||||
|
delete m;
|
||||||
|
delete root;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestQgsLayerTree::testRestrictedSymbolSizeWithGeometryGenerator_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<double>( "maxSize" );
|
||||||
|
QTest::addColumn<int>( "expectedSize" );
|
||||||
|
|
||||||
|
QTest::newRow( "smaller than max" ) << 15. << 42;
|
||||||
|
QTest::newRow( "bigger than max" ) << 10. << 38;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestQgsLayerTree::testRestrictedSymbolSizeWithGeometryGenerator()
|
||||||
|
{
|
||||||
|
QFETCH( double, maxSize );
|
||||||
|
QFETCH( int, expectedSize );
|
||||||
|
|
||||||
|
// to force re-read of max/min size in QgsSymbolLegendNode constructor
|
||||||
|
QgsSymbolLegendNode::MINIMUM_SIZE = -1;
|
||||||
|
QgsSymbolLegendNode::MAXIMUM_SIZE = -1;
|
||||||
|
|
||||||
|
QgsSettings settings;
|
||||||
|
settings.setValue( "/qgis/legendsymbolMaximumSize", maxSize );
|
||||||
|
|
||||||
|
//new memory layer
|
||||||
|
QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "Point?field=col1:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );
|
||||||
|
QVERIFY( vl->isValid() );
|
||||||
|
|
||||||
|
QgsProject project;
|
||||||
|
project.addMapLayer( vl );
|
||||||
|
|
||||||
|
//create a categorized renderer with geometry generator for layer
|
||||||
|
|
||||||
|
QVariantMap ggProps;
|
||||||
|
ggProps.insert( QStringLiteral( "SymbolType" ), QStringLiteral( "Fill" ) );
|
||||||
|
ggProps.insert( QStringLiteral( "geometryModifier" ), QStringLiteral( "buffer( $geometry, 200 )" ) );
|
||||||
|
QgsSymbolLayer *ggSymbolLayer = QgsGeometryGeneratorSymbolLayer::create( ggProps );
|
||||||
|
QgsSymbolLayerList fillSymbolLayerList;
|
||||||
|
fillSymbolLayerList << new QgsSimpleFillSymbolLayer();
|
||||||
|
ggSymbolLayer->setSubSymbol( new QgsFillSymbol( fillSymbolLayerList ) );
|
||||||
|
QgsSymbolLayerList slList;
|
||||||
|
slList << ggSymbolLayer;
|
||||||
|
QgsMarkerSymbol *symbol = new QgsMarkerSymbol( slList );
|
||||||
|
|
||||||
|
QgsCategorizedSymbolRenderer *renderer = new QgsCategorizedSymbolRenderer();
|
||||||
|
renderer->setClassAttribute( QStringLiteral( "col1" ) );
|
||||||
|
renderer->setSourceSymbol( symbol->clone() );
|
||||||
|
renderer->addCategory( QgsRendererCategory( "a", symbol->clone(), QStringLiteral( "a" ) ) );
|
||||||
|
renderer->addCategory( QgsRendererCategory( "b", symbol->clone(), QStringLiteral( "b" ) ) );
|
||||||
|
vl->setRenderer( renderer );
|
||||||
|
|
||||||
|
//create legend with symbology nodes for categorized renderer
|
||||||
|
QgsLayerTree *root = new QgsLayerTree();
|
||||||
|
QgsLayerTreeLayer *n = new QgsLayerTreeLayer( vl );
|
||||||
|
root->addChildNode( n );
|
||||||
|
QgsLayerTreeModel *m = new QgsLayerTreeModel( root, nullptr );
|
||||||
|
m->setLegendMapViewData( 10, 96, 10 );
|
||||||
|
|
||||||
|
const QList<QgsLayerTreeModelLegendNode *> nodes = m->layerLegendNodes( n );
|
||||||
|
const QSize minimumSize = static_cast< QgsSymbolLegendNode *>( nodes.at( 0 ) )->minimumIconSize();
|
||||||
|
QCOMPARE( minimumSize.width(), expectedSize );
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
delete m;
|
delete m;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user