26 QgsCategorizeUsingStyleAlgorithm::QgsCategorizeUsingStyleAlgorithm() =
default;
28 QgsCategorizeUsingStyleAlgorithm::~QgsCategorizeUsingStyleAlgorithm() =
default;
30 void QgsCategorizeUsingStyleAlgorithm::initAlgorithm(
const QVariantMap & )
34 addParameter(
new QgsProcessingParameterExpression( QStringLiteral(
"FIELD" ), QObject::tr(
"Categorize using expression" ), QVariant(), QStringLiteral(
"INPUT" ) ) );
37 addParameter(
new QgsProcessingParameterBoolean( QStringLiteral(
"CASE_SENSITIVE" ), QObject::tr(
"Use case-sensitive match to symbol names" ),
false ) );
38 addParameter(
new QgsProcessingParameterBoolean( QStringLiteral(
"TOLERANT" ), QObject::tr(
"Ignore non-alphanumeric characters while matching" ),
false ) );
42 std::unique_ptr< QgsProcessingParameterFeatureSink > failCategories = qgis::make_unique< QgsProcessingParameterFeatureSink >( QStringLiteral(
"NON_MATCHING_CATEGORIES" ), QObject::tr(
"Non-matching categories" ),
46 addParameter( failCategories.release() );
48 std::unique_ptr< QgsProcessingParameterFeatureSink > failSymbols = qgis::make_unique< QgsProcessingParameterFeatureSink >( QStringLiteral(
"NON_MATCHING_SYMBOLS" ), QObject::tr(
"Non-matching symbol names" ),
51 addParameter( failSymbols.release() );
54 QString QgsCategorizeUsingStyleAlgorithm::name()
const 56 return QStringLiteral(
"categorizeusingstyle" );
59 QString QgsCategorizeUsingStyleAlgorithm::displayName()
const 61 return QObject::tr(
"Create categorized renderer from styles" );
64 QStringList QgsCategorizeUsingStyleAlgorithm::tags()
const 66 return QObject::tr(
"file,database,symbols,names,category,categories" ).split(
',' );
69 QString QgsCategorizeUsingStyleAlgorithm::group()
const 71 return QObject::tr(
"Cartography" );
74 QString QgsCategorizeUsingStyleAlgorithm::groupId()
const 76 return QStringLiteral(
"cartography" );
79 QString QgsCategorizeUsingStyleAlgorithm::shortHelpString()
const 81 return QObject::tr(
"Sets a vector layer's renderer to a categorized renderer using matching symbols from a style database. If no " 82 "style file is specified, symbols from the user's current style library are used instead.\n\n" 83 "The specified expression (or field name) is used to create categories for the renderer. A category will be " 84 "created for each unique value within the layer.\n\n" 85 "Each category is individually matched to the symbols which exist within the specified QGIS XML style database. Whenever " 86 "a matching symbol name is found, the category's symbol will be set to this matched symbol.\n\n" 87 "The matching is case-insensitive by default, but can be made case-sensitive if required.\n\n" 88 "Optionally, non-alphanumeric characters in both the category value and symbol name can be ignored " 89 "while performing the match. This allows for greater tolerance when matching categories to symbols.\n\n" 90 "If desired, tables can also be output containing lists of the categories which could not be matched " 91 "to symbols, and symbols which were not matched to categories." 95 QString QgsCategorizeUsingStyleAlgorithm::shortDescription()
const 97 return QObject::tr(
"Sets a vector layer's renderer to a categorized renderer using symbols from a style database." );
100 QgsCategorizeUsingStyleAlgorithm *QgsCategorizeUsingStyleAlgorithm::createInstance()
const 102 return new QgsCategorizeUsingStyleAlgorithm();
109 SetCategorizedRendererPostProcessor( std::unique_ptr< QgsCategorizedSymbolRenderer > renderer )
110 : mRenderer( std::move( renderer ) )
115 if (
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
118 vl->setRenderer( mRenderer.release() );
119 vl->triggerRepaint();
125 std::unique_ptr<QgsCategorizedSymbolRenderer> mRenderer;
132 QgsVectorLayer *layer = parameterAsVectorLayer( parameters, QStringLiteral(
"INPUT" ), context );
136 mField = parameterAsString( parameters, QStringLiteral(
"FIELD" ), context );
138 mLayerId = layer->
id();
139 mLayerName = layer->
name();
141 mLayerFields = layer->
fields();
148 mExpression.prepare( &mExpressionContext );
152 if ( !mExpression.needsGeometry() )
162 const QString styleFile = parameterAsFile( parameters, QStringLiteral(
"STYLE" ), context );
163 const bool caseSensitive = parameterAsBoolean( parameters, QStringLiteral(
"CASE_SENSITIVE" ), context );
164 const bool tolerant = parameterAsBoolean( parameters, QStringLiteral(
"TOLERANT" ), context );
167 std::unique_ptr< QgsStyle >importedStyle;
168 if ( !styleFile.isEmpty() )
170 importedStyle = qgis::make_unique< QgsStyle >();
171 if ( !importedStyle->importXml( styleFile ) )
173 throw QgsProcessingException( QObject::tr(
"An error occurred while reading style file: %1" ).arg( importedStyle->errorString() ) );
175 style = importedStyle.get();
183 nonMatchingCategoryFields.
append(
QgsField( QStringLiteral(
"category" ), QVariant::String ) );
184 QString nonMatchingCategoriesDest;
185 std::unique_ptr< QgsFeatureSink > nonMatchingCategoriesSink( parameterAsSink( parameters, QStringLiteral(
"NON_MATCHING_CATEGORIES" ), context, nonMatchingCategoriesDest, nonMatchingCategoryFields,
QgsWkbTypes::NoGeometry ) );
186 if ( !nonMatchingCategoriesSink && parameters.contains( QStringLiteral(
"NON_MATCHING_CATEGORIES" ) ) && parameters.value( QStringLiteral(
"NON_MATCHING_CATEGORIES" ) ).isValid() )
187 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral(
"NON_MATCHING_CATEGORIES" ) ) );
190 nonMatchingSymbolFields.
append(
QgsField( QStringLiteral(
"name" ), QVariant::String ) );
191 QString nonMatchingSymbolsDest;
192 std::unique_ptr< QgsFeatureSink > nonMatchingSymbolsSink( parameterAsSink( parameters, QStringLiteral(
"NON_MATCHING_SYMBOLS" ), context, nonMatchingSymbolsDest, nonMatchingSymbolFields,
QgsWkbTypes::NoGeometry ) );
193 if ( !nonMatchingSymbolsSink && parameters.contains( QStringLiteral(
"NON_MATCHING_SYMBOLS" ) ) && parameters.value( QStringLiteral(
"NON_MATCHING_SYMBOLS" ) ).isValid() )
196 QSet<QVariant> uniqueVals;
198 while ( mIterator.nextFeature( feature ) )
200 mExpressionContext.setFeature( feature );
201 QVariant value = mExpression.evaluate( &mExpressionContext );
202 if ( uniqueVals.contains( value ) )
207 QVariantList sortedUniqueVals = uniqueVals.toList();
208 std::sort( sortedUniqueVals.begin(), sortedUniqueVals.end() );
211 cats.reserve( uniqueVals.count() );
213 for (
const QVariant &val : qgis::as_const( sortedUniqueVals ) )
218 mRenderer = qgis::make_unique< QgsCategorizedSymbolRenderer >( mField, cats );
224 QVariantList unmatchedCategories;
225 QStringList unmatchedSymbols;
226 const int matched = mRenderer->matchToSymbols( style, type, unmatchedCategories, unmatchedSymbols, caseSensitive, tolerant );
230 feedback->
pushInfo( QObject::tr(
"Matched %1 categories to symbols from file." ).arg( matched ) );
234 feedback->
reportError( QObject::tr(
"No categories could be matched to symbols in file." ) );
237 if ( !unmatchedCategories.empty() )
239 feedback->
pushInfo( QObject::tr(
"\n%1 categories could not be matched:" ).arg( unmatchedCategories.count() ) );
240 std::sort( unmatchedCategories.begin(), unmatchedCategories.end() );
241 for (
const QVariant &cat : qgis::as_const( unmatchedCategories ) )
243 feedback->
pushInfo( QStringLiteral(
"∙ “%1”" ).arg( cat.toString() ) );
244 if ( nonMatchingCategoriesSink )
253 if ( !unmatchedSymbols.empty() )
255 feedback->
pushInfo( QObject::tr(
"\n%1 symbols in style were not matched:" ).arg( unmatchedSymbols.count() ) );
256 std::sort( unmatchedSymbols.begin(), unmatchedSymbols.end() );
257 for (
const QString &name : qgis::as_const( unmatchedSymbols ) )
259 feedback->
pushInfo( QStringLiteral(
"∙ “%1”" ).arg( name ) );
260 if ( nonMatchingSymbolsSink )
273 results.insert( QStringLiteral(
"OUTPUT" ), mLayerId );
274 if ( nonMatchingCategoriesSink )
275 results.insert( QStringLiteral(
"NON_MATCHING_CATEGORIES" ), nonMatchingCategoriesDest );
276 if ( nonMatchingSymbolsSink )
277 results.insert( QStringLiteral(
"NON_MATCHING_SYMBOLS" ), nonMatchingSymbolsDest );
A boolean parameter for processing algorithms.
Class for parsing and evaluation of expressions (formerly called "search strings").
An input file or folder parameter for processing algorithms.
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
Base class for all map layer types.
Base class for providing feedback from a processing algorithm.
Represents an individual category (class) from a QgsCategorizedSymbolRenderer.
An interface for layer post-processing handlers for execution following a processing algorithm operat...
An expression parameter for processing algorithms.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
void setPostProcessor(QgsProcessingLayerPostProcessorInterface *processor)
Sets the layer post-processor.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Container of fields for a vector layer.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
A vector layer output for processing algorithms.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
static QgsStyle * defaultStyle()
Returns default application-wide style.
QList< QgsRendererCategory > QgsCategoryList
SymbolType
Type of the symbol.
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
Parameter is a single file.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
Custom exception class for processing related exceptions.
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false) ...
A vector layer (with or without geometry) parameter for processing algorithms.
Encapsulate a field in an attribute table or data source.
Details for layers to load into projects.
void addLayerToLoadOnCompletion(const QString &layer, const QgsProcessingContext::LayerDetails &details)
Adds a layer to load (by ID or datasource) into the canvas upon completion of the algorithm or model...
QgsProcessingContext::LayerDetails & layerToLoadOnCompletionDetails(const QString &layer)
Returns a reference to the details for a given layer which is loaded on completion of the algorithm o...
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
virtual void postProcessLayer(QgsMapLayer *layer, QgsProcessingContext &context, QgsProcessingFeedback *feedback)=0
Post-processes the specified layer, following successful execution of a processing algorithm...
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Represents a vector layer which manages a vector based data sets.
Contains information about the context in which a processing algorithm is executed.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.