26QgsCategorizeUsingStyleAlgorithm::QgsCategorizeUsingStyleAlgorithm() = 
default;
 
   28QgsCategorizeUsingStyleAlgorithm::~QgsCategorizeUsingStyleAlgorithm() = 
default;
 
   30void QgsCategorizeUsingStyleAlgorithm::initAlgorithm( 
const QVariantMap & )
 
   33  addParameter( 
new QgsProcessingParameterExpression( QStringLiteral( 
"FIELD" ), QObject::tr( 
"Categorize using expression" ), QVariant(), QStringLiteral( 
"INPUT" ) ) );
 
   36  addParameter( 
new QgsProcessingParameterBoolean( QStringLiteral( 
"CASE_SENSITIVE" ), QObject::tr( 
"Use case-sensitive match to symbol names" ), 
false ) );
 
   37  addParameter( 
new QgsProcessingParameterBoolean( QStringLiteral( 
"TOLERANT" ), QObject::tr( 
"Ignore non-alphanumeric characters while matching" ), 
false ) );
 
   41  auto failCategories = std::make_unique<QgsProcessingParameterFeatureSink>( QStringLiteral( 
"NON_MATCHING_CATEGORIES" ), QObject::tr( 
"Non-matching categories" ), 
Qgis::ProcessingSourceType::Vector, QVariant(), 
true, 
false );
 
   44  addParameter( failCategories.release() );
 
   46  auto failSymbols = std::make_unique<QgsProcessingParameterFeatureSink>( QStringLiteral( 
"NON_MATCHING_SYMBOLS" ), QObject::tr( 
"Non-matching symbol names" ), 
Qgis::ProcessingSourceType::Vector, QVariant(), 
true, 
false );
 
   48  addParameter( failSymbols.release() );
 
   58QString QgsCategorizeUsingStyleAlgorithm::name()
 const 
   60  return QStringLiteral( 
"categorizeusingstyle" );
 
   63QString QgsCategorizeUsingStyleAlgorithm::displayName()
 const 
   65  return QObject::tr( 
"Create categorized renderer from styles" );
 
   68QStringList QgsCategorizeUsingStyleAlgorithm::tags()
 const 
   70  return QObject::tr( 
"file,database,symbols,names,category,categories" ).split( 
',' );
 
   73QString QgsCategorizeUsingStyleAlgorithm::group()
 const 
   75  return QObject::tr( 
"Cartography" );
 
   78QString QgsCategorizeUsingStyleAlgorithm::groupId()
 const 
   80  return QStringLiteral( 
"cartography" );
 
   83QString QgsCategorizeUsingStyleAlgorithm::shortHelpString()
 const 
   85  return QObject::tr( 
"This algorithm sets a vector layer's renderer to a categorized renderer using matching symbols from a style database. If no " 
   86                      "style file is specified, symbols from the user's current style library are used instead.\n\n" 
   87                      "The specified expression (or field name) is used to create categories for the renderer. A category will be " 
   88                      "created for each unique value within the layer.\n\n" 
   89                      "Each category is individually matched to the symbols which exist within the specified QGIS XML style database. Whenever " 
   90                      "a matching symbol name is found, the category's symbol will be set to this matched symbol.\n\n" 
   91                      "The matching is case-insensitive by default, but can be made case-sensitive if required.\n\n" 
   92                      "Optionally, non-alphanumeric characters in both the category value and symbol name can be ignored " 
   93                      "while performing the match. This allows for greater tolerance when matching categories to symbols.\n\n" 
   94                      "If desired, tables can also be output containing lists of the categories which could not be matched " 
   95                      "to symbols, and symbols which were not matched to categories." 
   99QString QgsCategorizeUsingStyleAlgorithm::shortDescription()
 const 
  101  return QObject::tr( 
"Sets a vector layer's renderer to a categorized renderer using symbols from a style database." );
 
  104QgsCategorizeUsingStyleAlgorithm *QgsCategorizeUsingStyleAlgorithm::createInstance()
 const 
  106  return new QgsCategorizeUsingStyleAlgorithm();
 
  112    SetCategorizedRendererPostProcessor( std::unique_ptr<QgsCategorizedSymbolRenderer> renderer )
 
  113      : mRenderer( std::move( renderer ) )
 
  118      if ( 
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
 
  120        vl->setRenderer( mRenderer.release() );
 
  121        vl->triggerRepaint();
 
  126    std::unique_ptr<QgsCategorizedSymbolRenderer> mRenderer;
 
  133  QgsVectorLayer *layer = parameterAsVectorLayer( parameters, QStringLiteral( 
"INPUT" ), context );
 
  137  mField = parameterAsString( parameters, QStringLiteral( 
"FIELD" ), context );
 
  139  mLayerId = layer->
id();
 
  140  mLayerName = layer->
name();
 
  142  mLayerFields = layer->
fields();
 
  149  mExpression.prepare( &mExpressionContext );
 
  153  if ( !mExpression.needsGeometry() )
 
  163  const QString styleFile = parameterAsFile( parameters, QStringLiteral( 
"STYLE" ), context );
 
  164  const bool caseSensitive = parameterAsBoolean( parameters, QStringLiteral( 
"CASE_SENSITIVE" ), context );
 
  165  const bool tolerant = parameterAsBoolean( parameters, QStringLiteral( 
"TOLERANT" ), context );
 
  168  std::unique_ptr<QgsStyle> importedStyle;
 
  169  if ( !styleFile.isEmpty() )
 
  171    importedStyle = std::make_unique<QgsStyle>();
 
  172    if ( !importedStyle->importXml( styleFile ) )
 
  174      throw QgsProcessingException( QObject::tr( 
"An error occurred while reading style file: %1" ).arg( importedStyle->errorString() ) );
 
  176    style = importedStyle.get();
 
  184  nonMatchingCategoryFields.
append( 
QgsField( QStringLiteral( 
"category" ), QMetaType::Type::QString ) );
 
  185  QString nonMatchingCategoriesDest;
 
  186  std::unique_ptr<QgsFeatureSink> nonMatchingCategoriesSink( parameterAsSink( parameters, QStringLiteral( 
"NON_MATCHING_CATEGORIES" ), context, nonMatchingCategoriesDest, nonMatchingCategoryFields, 
Qgis::WkbType::NoGeometry ) );
 
  187  if ( !nonMatchingCategoriesSink && parameters.contains( QStringLiteral( 
"NON_MATCHING_CATEGORIES" ) ) && parameters.value( QStringLiteral( 
"NON_MATCHING_CATEGORIES" ) ).isValid() )
 
  188    throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( 
"NON_MATCHING_CATEGORIES" ) ) );
 
  191  nonMatchingSymbolFields.
append( 
QgsField( QStringLiteral( 
"name" ), QMetaType::Type::QString ) );
 
  192  QString nonMatchingSymbolsDest;
 
  193  std::unique_ptr<QgsFeatureSink> nonMatchingSymbolsSink( parameterAsSink( parameters, QStringLiteral( 
"NON_MATCHING_SYMBOLS" ), context, nonMatchingSymbolsDest, nonMatchingSymbolFields, 
Qgis::WkbType::NoGeometry ) );
 
  194  if ( !nonMatchingSymbolsSink && parameters.contains( QStringLiteral( 
"NON_MATCHING_SYMBOLS" ) ) && parameters.value( QStringLiteral( 
"NON_MATCHING_SYMBOLS" ) ).isValid() )
 
  197  QSet<QVariant> uniqueVals;
 
  199  while ( mIterator.nextFeature( feature ) )
 
  201    mExpressionContext.setFeature( feature );
 
  202    QVariant value = mExpression.evaluate( &mExpressionContext );
 
  203    if ( uniqueVals.contains( value ) )
 
  208  QVariantList sortedUniqueVals = qgis::setToList( uniqueVals );
 
  209  std::sort( sortedUniqueVals.begin(), sortedUniqueVals.end() );
 
  212  cats.reserve( uniqueVals.count() );
 
  214  for ( 
const QVariant &val : std::as_const( sortedUniqueVals ) )
 
  219  mRenderer = std::make_unique<QgsCategorizedSymbolRenderer>( mField, cats );
 
  225  QVariantList unmatchedCategories;
 
  226  QStringList unmatchedSymbols;
 
  227  const int matched = mRenderer->matchToSymbols( style, type, unmatchedCategories, unmatchedSymbols, caseSensitive, tolerant );
 
  231    feedback->
pushInfo( QObject::tr( 
"Matched %n categories to symbols from file.", 
nullptr, matched ) );
 
  235    feedback->
reportError( QObject::tr( 
"No categories could be matched to symbols in file." ) );
 
  238  if ( !unmatchedCategories.empty() )
 
  240    feedback->
pushInfo( QObject::tr( 
"\n%n categories could not be matched:", 
nullptr, unmatchedCategories.count() ) );
 
  241    std::sort( unmatchedCategories.begin(), unmatchedCategories.end() );
 
  242    for ( 
const QVariant &cat : std::as_const( unmatchedCategories ) )
 
  244      feedback->
pushInfo( QStringLiteral( 
"∙ “%1”" ).arg( cat.toString() ) );
 
  245      if ( nonMatchingCategoriesSink )
 
  250          throw QgsProcessingException( writeFeatureError( nonMatchingCategoriesSink.get(), parameters, QStringLiteral( 
"NON_MATCHING_CATEGORIES" ) ) );
 
  255  if ( !unmatchedSymbols.empty() )
 
  257    feedback->
pushInfo( QObject::tr( 
"\n%n symbol(s) in style were not matched:", 
nullptr, unmatchedSymbols.count() ) );
 
  258    std::sort( unmatchedSymbols.begin(), unmatchedSymbols.end() );
 
  259    for ( 
const QString &name : std::as_const( unmatchedSymbols ) )
 
  261      feedback->
pushInfo( QStringLiteral( 
"∙ “%1”" ).arg( name ) );
 
  262      if ( nonMatchingSymbolsSink )
 
  267          throw QgsProcessingException( writeFeatureError( nonMatchingSymbolsSink.get(), parameters, QStringLiteral( 
"NON_MATCHING_SYMBOLS" ) ) );
 
  275  if ( nonMatchingCategoriesSink )
 
  276    nonMatchingCategoriesSink->finalize();
 
  277  if ( nonMatchingSymbolsSink )
 
  278    nonMatchingSymbolsSink->finalize();
 
  281  results.insert( QStringLiteral( 
"OUTPUT" ), mLayerId );
 
  282  if ( nonMatchingCategoriesSink )
 
  283    results.insert( QStringLiteral( 
"NON_MATCHING_CATEGORIES" ), nonMatchingCategoriesDest );
 
  284  if ( nonMatchingSymbolsSink )
 
  285    results.insert( QStringLiteral( 
"NON_MATCHING_SYMBOLS" ), nonMatchingSymbolsDest );
 
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
 
@ File
Parameter is a single file.
 
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
 
QFlags< ProcessingAlgorithmFlag > ProcessingAlgorithmFlags
Flags indicating how and when an algorithm operates and should be exposed to users.
 
@ NotAvailableInStandaloneTool
Algorithm should not be available from the standalone "qgis_process" tool. Used to flag algorithms wh...
 
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.
 
Handles parsing and evaluation of expressions (formerly called "search strings").
 
Wraps a request for features to a vector layer (or directly its vector data provider).
 
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
 
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
 
@ 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, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
 
Base class for all map layer types.
 
virtual Qgis::ProcessingAlgorithmFlags 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.
 
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...
 
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.
 
QgsProject * project() const
Returns the project in which the algorithm is being executed.
 
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.
 
A vector layer (with or without geometry) parameter for processing algorithms.
 
Represents an individual category (class) from a QgsCategorizedSymbolRenderer.
 
A database of saved style entities, including symbols, color ramps, text formats and others.
 
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
 
static QgsSymbol * defaultSymbol(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
 
Represents a vector layer which manages a vector based dataset.
 
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
 
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
 
QList< QgsRendererCategory > QgsCategoryList