29#include "moc_qgsprocessingtoolboxmodel.cpp"
31#ifdef ENABLE_MODELTEST
41QgsProcessingToolboxModelNode::~QgsProcessingToolboxModelNode()
46QgsProcessingToolboxModelNode *QgsProcessingToolboxModelNode::takeChild( QgsProcessingToolboxModelNode *node )
48 return mChildren.takeAt( mChildren.indexOf( node ) );
51QgsProcessingToolboxModelGroupNode *QgsProcessingToolboxModelNode::getChildGroupNode(
const QString &groupId )
53 for ( QgsProcessingToolboxModelNode *node : std::as_const( mChildren ) )
55 if ( node->nodeType() == NodeType::Group )
57 QgsProcessingToolboxModelGroupNode *groupNode = qobject_cast<QgsProcessingToolboxModelGroupNode *>( node );
58 if ( groupNode && groupNode->id() == groupId )
65void QgsProcessingToolboxModelNode::addChildNode( QgsProcessingToolboxModelNode *node )
70 Q_ASSERT( !node->mParent );
73 mChildren.append( node );
76void QgsProcessingToolboxModelNode::deleteChildren()
78 qDeleteAll( mChildren );
86QgsProcessingToolboxModelProviderNode::QgsProcessingToolboxModelProviderNode(
QgsProcessingProvider *provider )
87 : mProviderId( provider->id() )
88 , mProvider( provider )
100QgsProcessingToolboxModelGroupNode::QgsProcessingToolboxModelGroupNode(
const QString &
id,
const QString &name )
119 : mParamType( paramType )
134 : QAbstractItemModel(
parent )
135 , mRegistry( registry ? registry :
QgsApplication::processingRegistry() )
136 , mRecentLog( recentLog )
137 , mFavoriteManager( favoriteManager )
138 , mRootNode( std::make_unique<QgsProcessingToolboxModelGroupNode>( QString(), QString() ) )
143 connect( mRecentLog, &QgsProcessingRecentAlgorithmLog::changed,
this, [
this] { repopulateRecentAlgorithms(); } );
145 if ( mFavoriteManager )
146 connect( mFavoriteManager, &QgsProcessingFavoriteAlgorithmManager::changed,
this, [
this] { repopulateFavoriteAlgorithms(); } );
155void QgsProcessingToolboxModel::rebuild()
159 mRootNode->deleteChildren();
160 mRecentNode =
nullptr;
161 mFavoriteNode =
nullptr;
165 auto recentNode = std::make_unique<QgsProcessingToolboxModelRecentNode>();
167 mRecentNode = recentNode.get();
168 mRootNode->addChildNode( recentNode.release() );
169 repopulateRecentAlgorithms(
true );
172 if ( mFavoriteManager )
174 auto favoriteNode = std::make_unique<QgsProcessingToolboxModelFavoriteNode>();
176 mFavoriteNode = favoriteNode.get();
177 mRootNode->addChildNode( favoriteNode.release() );
178 repopulateFavoriteAlgorithms(
true );
184 auto groupNode = std::make_unique<QgsProcessingToolboxModelParameterGroupNode>();
188 std::sort( available.begin(), available.end(), [](
const QgsProcessingParameterType *a,
const QgsProcessingParameterType *b ) ->
bool {
189 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
191 for ( QgsProcessingParameterType *param : std::as_const( available ) )
195 auto paramNode = std::make_unique<QgsProcessingToolboxModelParameterNode>( param );
196 groupNode->addChildNode( paramNode.release() );
199 mRootNode->addChildNode( groupNode.release() );
205 const QList<QgsProcessingProvider *> providers = mRegistry->providers();
206 for ( QgsProcessingProvider *provider : providers )
208 addProvider( provider );
214void QgsProcessingToolboxModel::repopulateRecentAlgorithms(
bool resetting )
216 if ( !mRecentNode || !mRecentLog )
219 QModelIndex recentIndex =
index( 0, 0 );
220 const int prevCount =
rowCount( recentIndex );
221 if ( !resetting && prevCount > 0 )
223 beginRemoveRows( recentIndex, 0, prevCount - 1 );
224 mRecentNode->deleteChildren();
235 const QStringList recentAlgIds = mRecentLog->recentAlgorithmIds();
236 QList<const QgsProcessingAlgorithm *> recentAlgorithms;
237 recentAlgorithms.reserve( recentAlgIds.count() );
238 for (
const QString &
id : recentAlgIds )
240 const QgsProcessingAlgorithm *
algorithm = mRegistry->algorithmById(
id );
245 if ( recentAlgorithms.empty() )
254 beginInsertRows( recentIndex, 0, recentAlgorithms.count() - 1 );
257 for (
const QgsProcessingAlgorithm *
algorithm : std::as_const( recentAlgorithms ) )
259 auto algorithmNode = std::make_unique<QgsProcessingToolboxModelAlgorithmNode>(
algorithm );
260 mRecentNode->addChildNode( algorithmNode.release() );
270void QgsProcessingToolboxModel::repopulateFavoriteAlgorithms(
bool resetting )
272 if ( !mFavoriteNode || !mFavoriteManager )
277 int idx = ( mRecentNode && mRecentLog ) ? 1 : 0;
279 QModelIndex favoriteIndex =
index( idx, 0 );
280 const int prevCount =
rowCount( favoriteIndex );
281 if ( !resetting && prevCount > 0 )
283 beginRemoveRows( favoriteIndex, 0, prevCount - 1 );
284 mFavoriteNode->deleteChildren();
295 const QStringList favoriteAlgIds = mFavoriteManager->favoriteAlgorithmIds();
296 QList<const QgsProcessingAlgorithm *> favoriteAlgorithms;
297 favoriteAlgorithms.reserve( favoriteAlgIds.count() );
298 for (
const QString &
id : favoriteAlgIds )
300 const QgsProcessingAlgorithm *
algorithm = mRegistry->algorithmById(
id );
305 if ( favoriteAlgorithms.empty() )
314 beginInsertRows( favoriteIndex, 0, favoriteAlgorithms.count() - 1 );
317 for (
const QgsProcessingAlgorithm *
algorithm : std::as_const( favoriteAlgorithms ) )
319 auto algorithmNode = std::make_unique<QgsProcessingToolboxModelAlgorithmNode>(
algorithm );
320 mFavoriteNode->addChildNode( algorithmNode.release() );
332 if ( !
index.isValid() )
333 return mRootNode.get();
335 QObject *obj =
reinterpret_cast<QObject *
>(
index.internalPointer() );
336 return qobject_cast<QgsProcessingToolboxModelNode *>( obj );
341 if ( !node || !node->parent() )
342 return QModelIndex();
344 QModelIndex parentIndex =
node2index( node->parent() );
346 int row = node->parent()->children().indexOf( node );
347 Q_ASSERT( row >= 0 );
348 return index( row, 0, parentIndex );
358 QgsProcessingToolboxModelNode *parentNode =
nullptr;
359 if ( !isTopLevelProvider( provider->
id() ) )
361 auto node = std::make_unique<QgsProcessingToolboxModelProviderNode>( provider );
362 parentNode = node.get();
363 mRootNode->addChildNode( node.release() );
367 parentNode = mRootNode.get();
370 const QList<const QgsProcessingAlgorithm *> algorithms = provider->
algorithms();
371 for (
const QgsProcessingAlgorithm *
algorithm : algorithms )
373 auto algorithmNode = std::make_unique<QgsProcessingToolboxModelAlgorithmNode>(
algorithm );
376 if ( !groupId.isEmpty() )
379 QgsProcessingToolboxModelGroupNode *groupNode = parentNode->getChildGroupNode( groupId );
384 parentNode->addChildNode( groupNode );
386 groupNode->addChildNode( algorithmNode.release() );
392 parentNode->addChildNode( algorithmNode.release() );
397bool QgsProcessingToolboxModel::isTopLevelProvider(
const QString &providerId )
399 return providerId == QLatin1String(
"qgis" ) || providerId == QLatin1String(
"native" ) || providerId == QLatin1String(
"3d" ) || providerId == QLatin1String(
"pdal" );
409 if ( !
index.isValid() )
410 return Qt::ItemFlags();
412 return QAbstractItemModel::flags(
index );
417 if ( !
index.isValid() )
423 return static_cast<int>( node->nodeType() );
428 bool isRecentNode =
false;
430 isRecentNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeType::Recent;
432 bool isFavoriteNode =
false;
434 isFavoriteNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeType::Favorite;
436 bool isParameterGroupNode =
false;
438 isParameterGroupNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeType::ParameterGroup;
441 QgsProcessingToolboxModelGroupNode *groupNode = qobject_cast<QgsProcessingToolboxModelGroupNode *>(
index2node(
index ) );
447 case Qt::DisplayRole:
449 switch (
index.column() )
453 return provider->
name();
456 else if ( paramType )
457 return paramType->
name();
458 else if ( groupNode )
459 return groupNode->name();
460 else if ( isRecentNode )
461 return tr(
"Recently used" );
462 else if ( isFavoriteNode )
463 return tr(
"Favorites" );
464 else if ( isParameterGroupNode )
465 return tr(
"Input parameters" );
475 case Qt::ToolTipRole:
481 else if ( paramType )
483 else if ( groupNode )
484 return groupNode->name();
485 else if ( isParameterGroupNode )
486 return tr(
"Input parameters used in the modeler" );
491 case Qt::ForegroundRole:
494 return QBrush( QColor( Qt::red ) );
499 case Qt::DecorationRole:
501 switch (
index.column() )
506 return provider->
icon();
513 else if ( paramType )
515 else if ( isRecentNode )
517 else if ( isFavoriteNode )
519 else if ( isParameterGroupNode )
521 else if ( !
index.parent().isValid() )
535 switch (
index.column() )
540 return static_cast<int>(
algorithm->flags() );
551 switch (
index.column() )
556 return static_cast<int>( provider->
flags() );
571 switch (
index.column() )
587 switch (
index.column() )
603 switch (
index.column() )
619 switch (
index.column() )
634 switch (
index.column() )
639 return paramType->
id();
662 return n->children().count();
672 if ( !hasIndex( row, column,
parent ) )
673 return QModelIndex();
677 return QModelIndex();
679 return createIndex( row, column,
static_cast<QObject *
>( n->children().at( row ) ) );
684 if ( !child.isValid() )
685 return QModelIndex();
687 if ( QgsProcessingToolboxModelNode *n =
index2node( child ) )
694 return QModelIndex();
700 if ( indexes.isEmpty() )
706 QByteArray encodedData;
707 QDataStream stream( &encodedData, QIODevice::WriteOnly | QIODevice::Truncate );
709 auto mimeData = std::make_unique<QMimeData>();
715 mimeData->setData( QStringLiteral(
"application/x-vnd.qgis.qgis.algorithmid" ), encodedData );
720 QByteArray encodedData;
721 QDataStream stream( &encodedData, QIODevice::WriteOnly | QIODevice::Truncate );
723 auto mimeData = std::make_unique<QMimeData>();
727 stream << paramType->
id();
729 mimeData->setData( QStringLiteral(
"application/x-vnd.qgis.qgis.parametertypeid" ), encodedData );
738 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Provider )
741 return qobject_cast<QgsProcessingToolboxModelProviderNode *>( n )->provider();
747 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Provider )
750 return qobject_cast<QgsProcessingToolboxModelProviderNode *>( n )->providerId();
756 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Algorithm )
759 return qobject_cast<QgsProcessingToolboxModelAlgorithmNode *>( n )->algorithm();
765 return ( n && n->nodeType() == QgsProcessingToolboxModelNode::NodeType::Algorithm );
771 return ( n && n->nodeType() == QgsProcessingToolboxModelNode::NodeType::Parameter );
777 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Parameter )
780 return qobject_cast<QgsProcessingToolboxModelParameterNode *>( n )->parameterType();
785 std::function<QModelIndex(
const QModelIndex &
parent,
const QString &providerId )> findIndex = [&](
const QModelIndex &
parent,
const QString &providerId ) -> QModelIndex {
790 if ( !currentProviderId.isEmpty() && currentProviderId == providerId )
793 QModelIndex checkChildren = findIndex( current, providerId );
794 if ( checkChildren.isValid() )
795 return checkChildren;
797 return QModelIndex();
800 return findIndex( QModelIndex(), providerId );
805 Q_ASSERT( parentNode );
807 QgsProcessingToolboxModelNode *grandParentNode = parentNode->parent();
808 if ( !grandParentNode )
809 return QModelIndex();
811 int row = grandParentNode->children().indexOf( parentNode );
812 Q_ASSERT( row >= 0 );
814 return createIndex( row, 0,
static_cast<QObject *
>( parentNode ) );
822 : QSortFilterProxyModel( parent )
825 setSourceModel( mModel );
826 setDynamicSortFilter(
true );
827 setSortLocaleAware(
true );
828 setFilterCaseSensitivity( Qt::CaseInsensitive );
853 mInPlaceLayer = layer;
860 mFilterString = filter;
866 QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
867 if ( mModel->isAlgorithm( sourceIndex ) )
873 if ( !mFilterString.trimmed().isEmpty() )
880 QStringList parentText;
881 QModelIndex parent = sourceIndex.parent();
882 while ( parent.isValid() )
884 const QStringList parentParts = sourceModel()->data( parent, Qt::DisplayRole ).toString().split(
' ' );
885 if ( !parentParts.empty() )
886 parentText.append( parentParts );
887 parent = parent.parent();
890 QStringList partsToSearch;
891 partsToSearch << sourceModel()->data( sourceIndex, Qt::DisplayRole ).toString().split(
' ' );
892 partsToSearch << algId << algName;
893 partsToSearch.append( algTags );
894 if ( !shortDesc.isEmpty() )
895 partsToSearch.append( shortDesc.split(
' ' ) );
896 partsToSearch.append( parentText );
898 const QStringList partsToMatch = mFilterString.trimmed().split(
' ' );
899 for (
const QString &part : partsToMatch )
902 for (
const QString &partToSearch : std::as_const( partsToSearch ) )
904 if ( partToSearch.contains( part, Qt::CaseInsensitive ) )
918 if ( !supportsInPlace )
930 return !isHiddenFromModeler;
935 return !isHiddenFromToolbox;
939 if ( mModel->isParameter( sourceIndex ) )
947 if ( !mFilterString.trimmed().isEmpty() )
949 QStringList partsToSearch;
950 partsToSearch << sourceModel()->data( sourceIndex, Qt::DisplayRole ).toString().split(
' ' );
953 const QStringList partsToMatch = mFilterString.trimmed().split(
' ' );
954 for (
const QString &part : partsToMatch )
957 for (
const QString &partToSearch : std::as_const( partsToSearch ) )
959 if ( partToSearch.contains( part, Qt::CaseInsensitive ) )
972 bool hasChildren =
false;
974 int count = sourceModel()->rowCount( sourceIndex );
975 for (
int i = 0; i < count; ++i )
992 if ( leftType == QgsProcessingToolboxModelNode::NodeType::Recent )
994 else if ( rightType == QgsProcessingToolboxModelNode::NodeType::Recent )
996 else if ( leftType == QgsProcessingToolboxModelNode::NodeType::Favorite )
998 else if ( rightType == QgsProcessingToolboxModelNode::NodeType::Favorite )
1000 else if ( leftType != rightType )
1002 if ( leftType == QgsProcessingToolboxModelNode::NodeType::Provider )
1004 else if ( rightType == QgsProcessingToolboxModelNode::NodeType::Provider )
1006 else if ( leftType == QgsProcessingToolboxModelNode::NodeType::Group )
1013 bool isRecentNode =
false;
1014 QModelIndex parent = left.parent();
1015 while ( parent.isValid() )
1019 isRecentNode =
true;
1022 parent = parent.parent();
1026 return left.row() < right.row();
1030 QString leftStr = sourceModel()->data( left ).toString();
1031 QString rightStr = sourceModel()->data( right ).toString();
1032 return QString::localeAwareCompare( leftStr, rightStr ) < 0;
1037 if ( role == Qt::ForegroundRole && !mFilterString.isEmpty() )
1039 QModelIndex sourceIndex = mapToSource( index );
1043 QBrush brush( qApp->palette().color( QPalette::Text ), Qt::SolidPattern );
1044 QColor fadedTextColor = brush.color();
1045 fadedTextColor.setAlpha( 100 );
1046 brush.setColor( fadedTextColor );
1050 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.
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.
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.
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.
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.
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.
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