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 = std::make_unique< QgsProcessingParameterFeatureSink >( QStringLiteral( 
"NON_MATCHING_CATEGORIES" ),  QObject::tr( 
"Non-matching categories" ),
 
   46   addParameter( failCategories.release() );
 
   48   std::unique_ptr< QgsProcessingParameterFeatureSink > failSymbols = std::make_unique< QgsProcessingParameterFeatureSink >( QStringLiteral( 
"NON_MATCHING_SYMBOLS" ),  QObject::tr( 
"Non-matching symbol names" ),
 
   51   addParameter( failSymbols.release() );
 
   54 QgsProcessingAlgorithm::Flags QgsCategorizeUsingStyleAlgorithm::flags()
 const 
   57   f |= FlagNotAvailableInStandaloneTool;
 
   61 QString QgsCategorizeUsingStyleAlgorithm::name()
 const 
   63   return QStringLiteral( 
"categorizeusingstyle" );
 
   66 QString QgsCategorizeUsingStyleAlgorithm::displayName()
 const 
   68   return QObject::tr( 
"Create categorized renderer from styles" );
 
   71 QStringList QgsCategorizeUsingStyleAlgorithm::tags()
 const 
   73   return QObject::tr( 
"file,database,symbols,names,category,categories" ).split( 
',' );
 
   76 QString QgsCategorizeUsingStyleAlgorithm::group()
 const 
   78   return QObject::tr( 
"Cartography" );
 
   81 QString QgsCategorizeUsingStyleAlgorithm::groupId()
 const 
   83   return QStringLiteral( 
"cartography" );
 
   86 QString QgsCategorizeUsingStyleAlgorithm::shortHelpString()
 const 
   88   return QObject::tr( 
"Sets a vector layer's renderer to a categorized renderer using matching symbols from a style database. If no " 
   89                       "style file is specified, symbols from the user's current style library are used instead.\n\n" 
   90                       "The specified expression (or field name) is used to create categories for the renderer. A category will be " 
   91                       "created for each unique value within the layer.\n\n" 
   92                       "Each category is individually matched to the symbols which exist within the specified QGIS XML style database. Whenever " 
   93                       "a matching symbol name is found, the category's symbol will be set to this matched symbol.\n\n" 
   94                       "The matching is case-insensitive by default, but can be made case-sensitive if required.\n\n" 
   95                       "Optionally, non-alphanumeric characters in both the category value and symbol name can be ignored " 
   96                       "while performing the match. This allows for greater tolerance when matching categories to symbols.\n\n" 
   97                       "If desired, tables can also be output containing lists of the categories which could not be matched " 
   98                       "to symbols, and symbols which were not matched to categories." 
  102 QString QgsCategorizeUsingStyleAlgorithm::shortDescription()
 const 
  104   return QObject::tr( 
"Sets a vector layer's renderer to a categorized renderer using symbols from a style database." );
 
  107 QgsCategorizeUsingStyleAlgorithm *QgsCategorizeUsingStyleAlgorithm::createInstance()
 const 
  109   return new QgsCategorizeUsingStyleAlgorithm();
 
  116     SetCategorizedRendererPostProcessor( std::unique_ptr< QgsCategorizedSymbolRenderer > renderer )
 
  117       : mRenderer( std::move( renderer ) )
 
  122       if ( 
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
 
  125         vl->setRenderer( mRenderer.release() );
 
  126         vl->triggerRepaint();
 
  132     std::unique_ptr<QgsCategorizedSymbolRenderer> mRenderer;
 
  139   QgsVectorLayer *layer = parameterAsVectorLayer( parameters, QStringLiteral( 
"INPUT" ), context );
 
  143   mField = parameterAsString( parameters, QStringLiteral( 
"FIELD" ), context );
 
  145   mLayerId = layer->
id();
 
  146   mLayerName = layer->
name();
 
  148   mLayerFields = layer->
fields();
 
  155   mExpression.prepare( &mExpressionContext );
 
  159   if ( !mExpression.needsGeometry() )
 
  169   const QString styleFile = parameterAsFile( parameters, QStringLiteral( 
"STYLE" ), context );
 
  170   const bool caseSensitive = parameterAsBoolean( parameters, QStringLiteral( 
"CASE_SENSITIVE" ), context );
 
  171   const bool tolerant = parameterAsBoolean( parameters, QStringLiteral( 
"TOLERANT" ), context );
 
  174   std::unique_ptr< QgsStyle >importedStyle;
 
  175   if ( !styleFile.isEmpty() )
 
  177     importedStyle = std::make_unique< QgsStyle >();
 
  178     if ( !importedStyle->importXml( styleFile ) )
 
  180       throw QgsProcessingException( QObject::tr( 
"An error occurred while reading style file: %1" ).arg( importedStyle->errorString() ) );
 
  182     style = importedStyle.get();
 
  190   nonMatchingCategoryFields.
append( 
QgsField( QStringLiteral( 
"category" ), QVariant::String ) );
 
  191   QString nonMatchingCategoriesDest;
 
  192   std::unique_ptr< QgsFeatureSink > nonMatchingCategoriesSink( parameterAsSink( parameters, QStringLiteral( 
"NON_MATCHING_CATEGORIES" ), context, nonMatchingCategoriesDest, nonMatchingCategoryFields, 
QgsWkbTypes::NoGeometry ) );
 
  193   if ( !nonMatchingCategoriesSink && parameters.contains( QStringLiteral( 
"NON_MATCHING_CATEGORIES" ) ) && parameters.value( QStringLiteral( 
"NON_MATCHING_CATEGORIES" ) ).isValid() )
 
  194     throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( 
"NON_MATCHING_CATEGORIES" ) ) );
 
  197   nonMatchingSymbolFields.
append( 
QgsField( QStringLiteral( 
"name" ), QVariant::String ) );
 
  198   QString nonMatchingSymbolsDest;
 
  199   std::unique_ptr< QgsFeatureSink > nonMatchingSymbolsSink( parameterAsSink( parameters, QStringLiteral( 
"NON_MATCHING_SYMBOLS" ), context, nonMatchingSymbolsDest, nonMatchingSymbolFields, 
QgsWkbTypes::NoGeometry ) );
 
  200   if ( !nonMatchingSymbolsSink && parameters.contains( QStringLiteral( 
"NON_MATCHING_SYMBOLS" ) ) && parameters.value( QStringLiteral( 
"NON_MATCHING_SYMBOLS" ) ).isValid() )
 
  203   QSet<QVariant> uniqueVals;
 
  205   while ( mIterator.nextFeature( feature ) )
 
  207     mExpressionContext.setFeature( feature );
 
  208     QVariant value = mExpression.evaluate( &mExpressionContext );
 
  209     if ( uniqueVals.contains( value ) )
 
  214   QVariantList sortedUniqueVals = qgis::setToList( uniqueVals );
 
  215   std::sort( sortedUniqueVals.begin(), sortedUniqueVals.end() );
 
  218   cats.reserve( uniqueVals.count() );
 
  220   for ( 
const QVariant &val : std::as_const( sortedUniqueVals ) )
 
  225   mRenderer = std::make_unique< QgsCategorizedSymbolRenderer >( mField, cats );
 
  231   QVariantList unmatchedCategories;
 
  232   QStringList unmatchedSymbols;
 
  233   const int matched = mRenderer->matchToSymbols( style, type, unmatchedCategories, unmatchedSymbols, caseSensitive, tolerant );
 
  237     feedback->
pushInfo( QObject::tr( 
"Matched %1 categories to symbols from file." ).arg( matched ) );
 
  241     feedback->
reportError( QObject::tr( 
"No categories could be matched to symbols in file." ) );
 
  244   if ( !unmatchedCategories.empty() )
 
  246     feedback->
pushInfo( QObject::tr( 
"\n%1 categories could not be matched:" ).arg( unmatchedCategories.count() ) );
 
  247     std::sort( unmatchedCategories.begin(), unmatchedCategories.end() );
 
  248     for ( 
const QVariant &cat : std::as_const( unmatchedCategories ) )
 
  250       feedback->
pushInfo( QStringLiteral( 
"∙ “%1”" ).arg( cat.toString() ) );
 
  251       if ( nonMatchingCategoriesSink )
 
  260   if ( !unmatchedSymbols.empty() )
 
  262     feedback->
pushInfo( QObject::tr( 
"\n%1 symbols in style were not matched:" ).arg( unmatchedSymbols.count() ) );
 
  263     std::sort( unmatchedSymbols.begin(), unmatchedSymbols.end() );
 
  264     for ( 
const QString &name : std::as_const( unmatchedSymbols ) )
 
  266       feedback->
pushInfo( QStringLiteral( 
"∙ “%1”" ).arg( name ) );
 
  267       if ( nonMatchingSymbolsSink )
 
  280   results.insert( QStringLiteral( 
"OUTPUT" ), mLayerId );
 
  281   if ( nonMatchingCategoriesSink )
 
  282     results.insert( QStringLiteral( 
"NON_MATCHING_CATEGORIES" ), nonMatchingCategoriesDest );
 
  283   if ( nonMatchingSymbolsSink )
 
  284     results.insert( QStringLiteral( 
"NON_MATCHING_SYMBOLS" ), nonMatchingSymbolsDest );
 
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Class for parsing and evaluation of expressions (formerly called "search strings").
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Encapsulate a field in an attribute table or data source.
Container of fields for a vector layer.
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)
Base class for all map layer types.
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
virtual Flags flags() const
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
Details for layers to load into projects.
void setPostProcessor(QgsProcessingLayerPostProcessorInterface *processor)
Sets the layer post-processor.
Contains information about the context in which a processing algorithm is executed.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
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...
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
An interface for layer post-processing handlers for execution following a processing algorithm operat...
virtual void postProcessLayer(QgsMapLayer *layer, QgsProcessingContext &context, QgsProcessingFeedback *feedback)=0
Post-processes the specified layer, following successful execution of a processing algorithm.
A vector layer output for processing algorithms.
A boolean parameter for processing algorithms.
An expression parameter for processing algorithms.
An input file or folder parameter for processing algorithms.
@ File
Parameter is a single file.
A vector layer (with or without geometry) parameter for processing algorithms.
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Represents an individual category (class) from a QgsCategorizedSymbolRenderer.
static QgsStyle * defaultStyle()
Returns default application-wide style.
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QList< QgsRendererCategory > QgsCategoryList