31#include "moc_qgsprocessingtoolboxmodel.cpp"
33using namespace Qt::StringLiterals;
35#ifdef ENABLE_MODELTEST
45QgsProcessingToolboxModelNode::~QgsProcessingToolboxModelNode()
50QgsProcessingToolboxModelNode *QgsProcessingToolboxModelNode::takeChild( QgsProcessingToolboxModelNode *node )
52 return mChildren.takeAt( mChildren.indexOf( node ) );
55QgsProcessingToolboxModelGroupNode *QgsProcessingToolboxModelNode::getChildGroupNode(
const QString &groupId )
57 for ( QgsProcessingToolboxModelNode *node : std::as_const( mChildren ) )
59 if ( node->nodeType() == NodeType::Group )
61 QgsProcessingToolboxModelGroupNode *groupNode = qobject_cast<QgsProcessingToolboxModelGroupNode *>( node );
62 if ( groupNode && groupNode->id() == groupId )
69void QgsProcessingToolboxModelNode::addChildNode( QgsProcessingToolboxModelNode *node )
74 Q_ASSERT( !node->mParent );
77 mChildren.append( node );
80void QgsProcessingToolboxModelNode::deleteChildren()
82 qDeleteAll( mChildren );
90QgsProcessingToolboxModelProviderNode::QgsProcessingToolboxModelProviderNode(
QgsProcessingProvider *provider )
91 : mProviderId( provider->id() )
92 , mProvider( provider )
104QgsProcessingToolboxModelGroupNode::QgsProcessingToolboxModelGroupNode(
const QString &
id,
const QString &name )
123 : mParamType( paramType )
138 : QAbstractItemModel(
parent )
139 , mRegistry( registry ? registry :
QgsApplication::processingRegistry() )
140 , mRecentLog( recentLog )
141 , mFavoriteManager( favoriteManager )
142 , mRootNode( std::make_unique<QgsProcessingToolboxModelGroupNode>( QString(), QString() ) )
147 connect( mRecentLog, &QgsProcessingRecentAlgorithmLog::changed,
this, [
this] { repopulateRecentAlgorithms(); } );
149 if ( mFavoriteManager )
150 connect( mFavoriteManager, &QgsProcessingFavoriteAlgorithmManager::changed,
this, [
this] { repopulateFavoriteAlgorithms(); } );
159void QgsProcessingToolboxModel::rebuild()
163 mRootNode->deleteChildren();
164 mRecentNode =
nullptr;
165 mFavoriteNode =
nullptr;
169 auto recentNode = std::make_unique<QgsProcessingToolboxModelRecentNode>();
171 mRecentNode = recentNode.get();
172 mRootNode->addChildNode( recentNode.release() );
173 repopulateRecentAlgorithms(
true );
176 if ( mFavoriteManager )
178 auto favoriteNode = std::make_unique<QgsProcessingToolboxModelFavoriteNode>();
180 mFavoriteNode = favoriteNode.get();
181 mRootNode->addChildNode( favoriteNode.release() );
182 repopulateFavoriteAlgorithms(
true );
188 auto groupNode = std::make_unique<QgsProcessingToolboxModelParameterGroupNode>();
192 std::sort( available.begin(), available.end(), [](
const QgsProcessingParameterType *a,
const QgsProcessingParameterType *b ) ->
bool {
193 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
195 for ( QgsProcessingParameterType *param : std::as_const( available ) )
199 auto paramNode = std::make_unique<QgsProcessingToolboxModelParameterNode>( param );
200 groupNode->addChildNode( paramNode.release() );
203 mRootNode->addChildNode( groupNode.release() );
209 const QList<QgsProcessingProvider *> providers = mRegistry->providers();
210 for ( QgsProcessingProvider *provider : providers )
212 addProvider( provider );
218void QgsProcessingToolboxModel::repopulateRecentAlgorithms(
bool resetting )
220 if ( !mRecentNode || !mRecentLog )
223 QModelIndex recentIndex =
index( 0, 0 );
224 const int prevCount =
rowCount( recentIndex );
225 if ( !resetting && prevCount > 0 )
227 beginRemoveRows( recentIndex, 0, prevCount - 1 );
228 mRecentNode->deleteChildren();
239 const QStringList recentAlgIds = mRecentLog->recentAlgorithmIds();
240 QList<const QgsProcessingAlgorithm *> recentAlgorithms;
241 recentAlgorithms.reserve( recentAlgIds.count() );
242 for (
const QString &
id : recentAlgIds )
244 const QgsProcessingAlgorithm *
algorithm = mRegistry->algorithmById(
id );
249 if ( recentAlgorithms.empty() )
258 beginInsertRows( recentIndex, 0, recentAlgorithms.count() - 1 );
261 for (
const QgsProcessingAlgorithm *
algorithm : std::as_const( recentAlgorithms ) )
263 auto algorithmNode = std::make_unique<QgsProcessingToolboxModelAlgorithmNode>(
algorithm );
264 mRecentNode->addChildNode( algorithmNode.release() );
274void QgsProcessingToolboxModel::repopulateFavoriteAlgorithms(
bool resetting )
276 if ( !mFavoriteNode || !mFavoriteManager )
281 int idx = ( mRecentNode && mRecentLog ) ? 1 : 0;
283 QModelIndex favoriteIndex =
index( idx, 0 );
284 const int prevCount =
rowCount( favoriteIndex );
285 if ( !resetting && prevCount > 0 )
287 beginRemoveRows( favoriteIndex, 0, prevCount - 1 );
288 mFavoriteNode->deleteChildren();
299 const QStringList favoriteAlgIds = mFavoriteManager->favoriteAlgorithmIds();
300 QList<const QgsProcessingAlgorithm *> favoriteAlgorithms;
301 favoriteAlgorithms.reserve( favoriteAlgIds.count() );
302 for (
const QString &
id : favoriteAlgIds )
304 const QgsProcessingAlgorithm *
algorithm = mRegistry->algorithmById(
id );
309 if ( favoriteAlgorithms.empty() )
318 beginInsertRows( favoriteIndex, 0, favoriteAlgorithms.count() - 1 );
321 for (
const QgsProcessingAlgorithm *
algorithm : std::as_const( favoriteAlgorithms ) )
323 auto algorithmNode = std::make_unique<QgsProcessingToolboxModelAlgorithmNode>(
algorithm );
324 mFavoriteNode->addChildNode( algorithmNode.release() );
336 if ( !
index.isValid() )
337 return mRootNode.get();
339 QObject *obj =
reinterpret_cast<QObject *
>(
index.internalPointer() );
340 return qobject_cast<QgsProcessingToolboxModelNode *>( obj );
345 if ( !node || !node->parent() )
346 return QModelIndex();
348 QModelIndex parentIndex =
node2index( node->parent() );
350 int row = node->parent()->children().indexOf( node );
351 Q_ASSERT( row >= 0 );
352 return index( row, 0, parentIndex );
362 QgsProcessingToolboxModelNode *parentNode =
nullptr;
363 if ( !isTopLevelProvider( provider->
id() ) )
365 auto node = std::make_unique<QgsProcessingToolboxModelProviderNode>( provider );
366 parentNode = node.get();
367 mRootNode->addChildNode( node.release() );
371 parentNode = mRootNode.get();
374 const QList<const QgsProcessingAlgorithm *> algorithms = provider->
algorithms();
375 for (
const QgsProcessingAlgorithm *
algorithm : algorithms )
377 auto algorithmNode = std::make_unique<QgsProcessingToolboxModelAlgorithmNode>(
algorithm );
380 if ( !groupId.isEmpty() )
383 QgsProcessingToolboxModelGroupNode *groupNode = parentNode->getChildGroupNode( groupId );
388 parentNode->addChildNode( groupNode );
390 groupNode->addChildNode( algorithmNode.release() );
396 parentNode->addChildNode( algorithmNode.release() );
401bool QgsProcessingToolboxModel::isTopLevelProvider(
const QString &providerId )
403 return providerId ==
"qgis"_L1 || providerId ==
"native"_L1 || providerId ==
"3d"_L1 || providerId ==
"pdal"_L1;
408 return u
"<p><b>%1</b></p>%2<p>%3</p>%4"_s.arg(
411 QObject::tr(
"Algorithm ID: ‘%1’" ).arg( u
"<i>%1</i>"_s.arg(
algorithm->
id() ) ),
418 if ( !
index.isValid() )
419 return Qt::ItemFlags();
421 return QAbstractItemModel::flags(
index );
426 if ( !
index.isValid() )
432 return static_cast<int>( node->nodeType() );
437 bool isRecentNode =
false;
439 isRecentNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeType::Recent;
441 bool isFavoriteNode =
false;
443 isFavoriteNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeType::Favorite;
445 bool isParameterGroupNode =
false;
447 isParameterGroupNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeType::ParameterGroup;
450 QgsProcessingToolboxModelGroupNode *groupNode = qobject_cast<QgsProcessingToolboxModelGroupNode *>(
index2node(
index ) );
456 case Qt::DisplayRole:
458 switch (
index.column() )
462 return provider->
name();
465 else if ( paramType )
466 return paramType->
name();
467 else if ( groupNode )
468 return groupNode->name();
469 else if ( isRecentNode )
470 return tr(
"Recently used" );
471 else if ( isFavoriteNode )
472 return tr(
"Favorites" );
473 else if ( isParameterGroupNode )
474 return tr(
"Input parameters" );
484 case Qt::ToolTipRole:
490 else if ( paramType )
492 else if ( groupNode )
493 return groupNode->name();
494 else if ( isParameterGroupNode )
495 return tr(
"Input parameters used in the modeler" );
500 case Qt::ForegroundRole:
503 return QBrush( QColor( Qt::red ) );
508 case Qt::DecorationRole:
510 switch (
index.column() )
515 return provider->
icon();
522 else if ( paramType )
524 else if ( isRecentNode )
526 else if ( isFavoriteNode )
528 else if ( isParameterGroupNode )
530 else if ( !
index.parent().isValid() )
544 switch (
index.column() )
549 return static_cast<int>(
algorithm->flags() );
560 switch (
index.column() )
565 return static_cast<int>( provider->
flags() );
580 switch (
index.column() )
596 switch (
index.column() )
612 switch (
index.column() )
628 switch (
index.column() )
643 switch (
index.column() )
648 return paramType->
id();
671 return n->children().count();
681 if ( !hasIndex( row, column,
parent ) )
682 return QModelIndex();
686 return QModelIndex();
688 return createIndex( row, column,
static_cast<QObject *
>( n->children().at( row ) ) );
693 if ( !child.isValid() )
694 return QModelIndex();
696 if ( QgsProcessingToolboxModelNode *n =
index2node( child ) )
703 return QModelIndex();
709 if ( indexes.isEmpty() )
715 QByteArray encodedData;
716 QDataStream stream( &encodedData, QIODevice::WriteOnly | QIODevice::Truncate );
718 auto mimeData = std::make_unique<QMimeData>();
724 mimeData->setData( u
"application/x-vnd.qgis.qgis.algorithmid"_s, encodedData );
729 QByteArray encodedData;
730 QDataStream stream( &encodedData, QIODevice::WriteOnly | QIODevice::Truncate );
732 auto mimeData = std::make_unique<QMimeData>();
736 stream << paramType->
id();
738 mimeData->setData( u
"application/x-vnd.qgis.qgis.parametertypeid"_s, encodedData );
747 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Provider )
750 return qobject_cast<QgsProcessingToolboxModelProviderNode *>( n )->provider();
756 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Provider )
759 return qobject_cast<QgsProcessingToolboxModelProviderNode *>( n )->providerId();
765 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Algorithm )
768 return qobject_cast<QgsProcessingToolboxModelAlgorithmNode *>( n )->algorithm();
774 return ( n && n->nodeType() == QgsProcessingToolboxModelNode::NodeType::Algorithm );
780 return ( n && n->nodeType() == QgsProcessingToolboxModelNode::NodeType::Parameter );
786 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Parameter )
789 return qobject_cast<QgsProcessingToolboxModelParameterNode *>( n )->parameterType();
794 std::function<QModelIndex(
const QModelIndex &
parent,
const QString &providerId )> findIndex = [&](
const QModelIndex &
parent,
const QString &providerId ) -> QModelIndex {
799 if ( !currentProviderId.isEmpty() && currentProviderId == providerId )
802 QModelIndex checkChildren = findIndex( current, providerId );
803 if ( checkChildren.isValid() )
804 return checkChildren;
806 return QModelIndex();
809 return findIndex( QModelIndex(), providerId );
814 Q_ASSERT( parentNode );
816 QgsProcessingToolboxModelNode *grandParentNode = parentNode->parent();
817 if ( !grandParentNode )
818 return QModelIndex();
820 int row = grandParentNode->children().indexOf( parentNode );
821 Q_ASSERT( row >= 0 );
823 return createIndex( row, 0,
static_cast<QObject *
>( parentNode ) );
831 QObject *parent,
QgsProcessingRegistry *registry, QgsProcessingRecentAlgorithmLog *recentLog, QgsProcessingFavoriteAlgorithmManager *favoriteManager
833 : QSortFilterProxyModel( parent )
836 setSourceModel( mModel );
837 setDynamicSortFilter(
true );
838 setSortLocaleAware(
true );
839 setFilterCaseSensitivity( Qt::CaseInsensitive );
864 mInPlaceLayer = layer;
871 mFilterString = filter;
877 mFilterParameterDefinition.reset( parameterDefinition->
clone() );
878 mFilterOutputDefinition.reset();
885 mFilterParameterDefinition.reset();
886 mFilterOutputDefinition.reset( outputDefinition->
clone() );
894 QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
895 if ( mModel->isAlgorithm( sourceIndex ) )
902 if ( !mFilterString.trimmed().isEmpty() )
909 QStringList parentText;
910 QModelIndex parent = sourceIndex.parent();
911 while ( parent.isValid() )
913 const QStringList parentParts = sourceModel()->data( parent, Qt::DisplayRole ).toString().split(
' ' );
914 if ( !parentParts.empty() )
915 parentText.append( parentParts );
916 parent = parent.parent();
919 QStringList partsToSearch;
920 partsToSearch << sourceModel()->data( sourceIndex, Qt::DisplayRole ).toString().split(
' ' );
921 partsToSearch << algId << algName;
922 partsToSearch.append( algTags );
923 if ( !shortDesc.isEmpty() )
924 partsToSearch.append( shortDesc.split(
' ' ) );
925 partsToSearch.append( parentText );
927 const QStringList partsToMatch = mFilterString.trimmed().split(
' ' );
928 for (
const QString &part : partsToMatch )
931 for (
const QString &partToSearch : std::as_const( partsToSearch ) )
933 if ( partToSearch.contains( part, Qt::CaseInsensitive ) )
948 if ( !supportsInPlace )
961 if ( mFilterParameterDefinition )
964 const QList<const QgsProcessingOutputDefinition *> outputs = alg->
outputDefinitions();
982 if ( mFilterOutputDefinition )
996 if ( mFilterParameterDefinition )
1018 return !isHiddenFromModeler;
1024 return !isHiddenFromToolbox;
1028 if ( mModel->isParameter( sourceIndex ) )
1041 if ( !mFilterString.trimmed().isEmpty() )
1043 QStringList partsToSearch;
1044 partsToSearch << sourceModel()->data( sourceIndex, Qt::DisplayRole ).toString().split(
' ' );
1047 const QStringList partsToMatch = mFilterString.trimmed().split(
' ' );
1048 for (
const QString &part : partsToMatch )
1051 for (
const QString &partToSearch : std::as_const( partsToSearch ) )
1053 if ( partToSearch.contains( part, Qt::CaseInsensitive ) )
1066 if ( mFilterParameterDefinition )
1077 bool hasChildren =
false;
1079 int count = sourceModel()->rowCount( sourceIndex );
1080 for (
int i = 0; i < count; ++i )
1094 QgsProcessingToolboxModelNode::NodeType leftType =
static_cast<QgsProcessingToolboxModelNode::NodeType
>(
1097 QgsProcessingToolboxModelNode::NodeType rightType =
static_cast<QgsProcessingToolboxModelNode::NodeType
>(
1101 if ( leftType == QgsProcessingToolboxModelNode::NodeType::Recent )
1103 else if ( rightType == QgsProcessingToolboxModelNode::NodeType::Recent )
1105 else if ( leftType == QgsProcessingToolboxModelNode::NodeType::Favorite )
1107 else if ( rightType == QgsProcessingToolboxModelNode::NodeType::Favorite )
1109 else if ( leftType != rightType )
1111 if ( leftType == QgsProcessingToolboxModelNode::NodeType::Provider )
1113 else if ( rightType == QgsProcessingToolboxModelNode::NodeType::Provider )
1115 else if ( leftType == QgsProcessingToolboxModelNode::NodeType::Group )
1122 bool isRecentNode =
false;
1123 QModelIndex parent = left.parent();
1124 while ( parent.isValid() )
1128 isRecentNode =
true;
1131 parent = parent.parent();
1135 return left.row() < right.row();
1139 QString leftStr = sourceModel()->data( left ).toString();
1140 QString rightStr = sourceModel()->data( right ).toString();
1141 return QString::localeAwareCompare( leftStr, rightStr ) < 0;
1146 if ( role == Qt::ForegroundRole && !mFilterString.isEmpty() )
1148 QModelIndex sourceIndex = mapToSource( index );
1152 QBrush brush( qApp->palette().color( QPalette::Text ), Qt::SolidPattern );
1153 QColor fadedTextColor = brush.color();
1154 fadedTextColor.setAlpha( 100 );
1155 brush.setColor( fadedTextColor );
1159 return QSortFilterProxyModel::data( index, role );
@ ExposeToModeler
Is this parameter available in the modeler. Is set to on by default.
@ DeemphasiseSearchResults
Algorithms should be de-emphasised in the search results when searching for algorithms....
@ HideFromToolbox
Algorithm should be hidden from the toolbox.
@ SupportsInPlaceEdits
Algorithm supports in-place editing.
@ HideFromModeler
Algorithm should be hidden from the modeler.
@ KnownIssues
Algorithm has known issues.
@ Hidden
Parameter is hidden and should not be shown to users.
Extends QApplication to provide access to QGIS specific resources such as theme paths,...
static QgsProcessingRegistry * processingRegistry()
Returns the application's processing registry, used for managing processing providers,...
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Abstract base class for processing algorithms.
QgsProcessingOutputDefinitions outputDefinitions() const
Returns an ordered list of output definitions utilized by the algorithm.
virtual QString group() const
Returns the name of the group this algorithm belongs to.
virtual QString groupId() const
Returns the unique ID of the group this algorithm belongs to.
virtual QString shortDescription() const
Returns an optional translated short description of the algorithm.
QgsProcessingParameterDefinitions parameterDefinitions() const
Returns an ordered list of parameter definitions utilized by the algorithm.
QString id() const
Returns the unique ID for the algorithm, which is a combination of the algorithm provider's ID and th...
virtual QString displayName() const =0
Returns the translated algorithm name, which should be used for any user-visible display of the algor...
virtual bool supportInPlaceEdit(const QgsMapLayer *layer) const
Checks whether this algorithm supports in-place editing on the given layer Default implementation ret...
Qgis::ProcessingAlgorithmFlags flags() const override
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
Base class for the definition of processing outputs.
virtual QgsProcessingOutputDefinition * clone() const =0
Creates a clone of the output definition.
Base class for the definition of processing parameters.
virtual QgsProcessingParameterDefinition * clone() const =0
Creates a clone of the parameter definition.
Makes metadata of processing parameters available.
virtual QString name() const =0
A human readable and translatable short name for this parameter type.
virtual QString description() const =0
A human readable and translatable description for this parameter type.
virtual QString id() const =0
A static id for this type which will be used for storing this parameter type.
virtual QStringList acceptedParameterTypes() const =0
Returns a list of compatible Processing parameter types for inputs for this parameter type.
Abstract base class for processing providers.
virtual QIcon icon() const
Returns an icon for the provider.
virtual Qgis::ProcessingProviderFlags flags() const
Returns the flags indicating how and when the provider operates and should be exposed to users.
virtual QString name() const =0
Returns the provider name, which is used to describe the provider within the GUI.
void algorithmsLoaded()
Emitted when the provider has loaded (or refreshed) its list of available algorithms.
virtual QString id() const =0
Returns the unique provider id, used for identifying the provider.
virtual QString longName() const
Returns the longer version of the provider name, which can include extra details such as version numb...
QList< const QgsProcessingAlgorithm * > algorithms() const
Returns a list of algorithms supplied by this provider.
Registry for various processing components, including providers, algorithms and various parameters an...
void parameterTypeAdded(QgsProcessingParameterType *type)
Emitted when a new parameter type has been added to the registry.
void parameterTypeRemoved(QgsProcessingParameterType *type)
Emitted when a parameter type has been removed from the registry and is about to be deleted.
QgsProcessingParameterType * parameterType(const QString &id) const
Returns the parameter type registered for id.
void providerAdded(const QString &id)
Emitted when a provider has been added to the registry.
QList< QgsProcessingParameterType * > parameterTypes() const
Returns a list with all known parameter types.
void providerRemoved(const QString &id)
Emitted when a provider is removed from the registry.
Represents a vector layer which manages a vector based dataset.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call