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;
413 if ( !
index.isValid() )
414 return Qt::ItemFlags();
416 return QAbstractItemModel::flags(
index );
421 if ( !
index.isValid() )
427 return static_cast<int>( node->nodeType() );
432 bool isRecentNode =
false;
434 isRecentNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeType::Recent;
436 bool isFavoriteNode =
false;
438 isFavoriteNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeType::Favorite;
440 bool isParameterGroupNode =
false;
442 isParameterGroupNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeType::ParameterGroup;
445 QgsProcessingToolboxModelGroupNode *groupNode = qobject_cast<QgsProcessingToolboxModelGroupNode *>(
index2node(
index ) );
451 case Qt::DisplayRole:
453 switch (
index.column() )
457 return provider->
name();
460 else if ( paramType )
461 return paramType->
name();
462 else if ( groupNode )
463 return groupNode->name();
464 else if ( isRecentNode )
465 return tr(
"Recently used" );
466 else if ( isFavoriteNode )
467 return tr(
"Favorites" );
468 else if ( isParameterGroupNode )
469 return tr(
"Input parameters" );
479 case Qt::ToolTipRole:
485 else if ( paramType )
487 else if ( groupNode )
488 return groupNode->name();
489 else if ( isParameterGroupNode )
490 return tr(
"Input parameters used in the modeler" );
495 case Qt::ForegroundRole:
498 return QBrush( QColor( Qt::red ) );
503 case Qt::DecorationRole:
505 switch (
index.column() )
510 return provider->
icon();
517 else if ( paramType )
519 else if ( isRecentNode )
521 else if ( isFavoriteNode )
523 else if ( isParameterGroupNode )
525 else if ( !
index.parent().isValid() )
539 switch (
index.column() )
544 return static_cast<int>(
algorithm->flags() );
555 switch (
index.column() )
560 return static_cast<int>( provider->
flags() );
575 switch (
index.column() )
591 switch (
index.column() )
607 switch (
index.column() )
623 switch (
index.column() )
638 switch (
index.column() )
643 return paramType->
id();
666 return n->children().count();
676 if ( !hasIndex( row, column,
parent ) )
677 return QModelIndex();
681 return QModelIndex();
683 return createIndex( row, column,
static_cast<QObject *
>( n->children().at( row ) ) );
688 if ( !child.isValid() )
689 return QModelIndex();
691 if ( QgsProcessingToolboxModelNode *n =
index2node( child ) )
698 return QModelIndex();
704 if ( indexes.isEmpty() )
710 QByteArray encodedData;
711 QDataStream stream( &encodedData, QIODevice::WriteOnly | QIODevice::Truncate );
713 auto mimeData = std::make_unique<QMimeData>();
719 mimeData->setData( u
"application/x-vnd.qgis.qgis.algorithmid"_s, encodedData );
724 QByteArray encodedData;
725 QDataStream stream( &encodedData, QIODevice::WriteOnly | QIODevice::Truncate );
727 auto mimeData = std::make_unique<QMimeData>();
731 stream << paramType->
id();
733 mimeData->setData( u
"application/x-vnd.qgis.qgis.parametertypeid"_s, encodedData );
742 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Provider )
745 return qobject_cast<QgsProcessingToolboxModelProviderNode *>( n )->provider();
751 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Provider )
754 return qobject_cast<QgsProcessingToolboxModelProviderNode *>( n )->providerId();
760 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Algorithm )
763 return qobject_cast<QgsProcessingToolboxModelAlgorithmNode *>( n )->algorithm();
769 return ( n && n->nodeType() == QgsProcessingToolboxModelNode::NodeType::Algorithm );
775 return ( n && n->nodeType() == QgsProcessingToolboxModelNode::NodeType::Parameter );
781 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Parameter )
784 return qobject_cast<QgsProcessingToolboxModelParameterNode *>( n )->parameterType();
789 std::function<QModelIndex(
const QModelIndex &
parent,
const QString &providerId )> findIndex = [&](
const QModelIndex &
parent,
const QString &providerId ) -> QModelIndex {
794 if ( !currentProviderId.isEmpty() && currentProviderId == providerId )
797 QModelIndex checkChildren = findIndex( current, providerId );
798 if ( checkChildren.isValid() )
799 return checkChildren;
801 return QModelIndex();
804 return findIndex( QModelIndex(), providerId );
809 Q_ASSERT( parentNode );
811 QgsProcessingToolboxModelNode *grandParentNode = parentNode->parent();
812 if ( !grandParentNode )
813 return QModelIndex();
815 int row = grandParentNode->children().indexOf( parentNode );
816 Q_ASSERT( row >= 0 );
818 return createIndex( row, 0,
static_cast<QObject *
>( parentNode ) );
826 : QSortFilterProxyModel( parent )
829 setSourceModel( mModel );
830 setDynamicSortFilter(
true );
831 setSortLocaleAware(
true );
832 setFilterCaseSensitivity( Qt::CaseInsensitive );
857 mInPlaceLayer = layer;
864 mFilterString = filter;
870 QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
871 if ( mModel->isAlgorithm( sourceIndex ) )
877 if ( !mFilterString.trimmed().isEmpty() )
884 QStringList parentText;
885 QModelIndex parent = sourceIndex.parent();
886 while ( parent.isValid() )
888 const QStringList parentParts = sourceModel()->data( parent, Qt::DisplayRole ).toString().split(
' ' );
889 if ( !parentParts.empty() )
890 parentText.append( parentParts );
891 parent = parent.parent();
894 QStringList partsToSearch;
895 partsToSearch << sourceModel()->data( sourceIndex, Qt::DisplayRole ).toString().split(
' ' );
896 partsToSearch << algId << algName;
897 partsToSearch.append( algTags );
898 if ( !shortDesc.isEmpty() )
899 partsToSearch.append( shortDesc.split(
' ' ) );
900 partsToSearch.append( parentText );
902 const QStringList partsToMatch = mFilterString.trimmed().split(
' ' );
903 for (
const QString &part : partsToMatch )
907 for (
const QString &partToSearch : std::as_const( partsToSearch ) )
923 if ( !supportsInPlace )
935 return !isHiddenFromModeler;
940 return !isHiddenFromToolbox;
944 if ( mModel->isParameter( sourceIndex ) )
952 if ( !mFilterString.trimmed().isEmpty() )
954 QStringList partsToSearch;
955 partsToSearch << sourceModel()->data( sourceIndex, Qt::DisplayRole ).toString().split(
' ' );
958 const QStringList partsToMatch = mFilterString.trimmed().split(
' ' );
959 for (
const QString &part : partsToMatch )
963 for (
const QString &partToSearch : std::as_const( partsToSearch ) )
978 bool hasChildren =
false;
980 int count = sourceModel()->rowCount( sourceIndex );
981 for (
int i = 0; i < count; ++i )
998 if ( leftType == QgsProcessingToolboxModelNode::NodeType::Recent )
1000 else if ( rightType == QgsProcessingToolboxModelNode::NodeType::Recent )
1002 else if ( leftType == QgsProcessingToolboxModelNode::NodeType::Favorite )
1004 else if ( rightType == QgsProcessingToolboxModelNode::NodeType::Favorite )
1006 else if ( leftType != rightType )
1008 if ( leftType == QgsProcessingToolboxModelNode::NodeType::Provider )
1010 else if ( rightType == QgsProcessingToolboxModelNode::NodeType::Provider )
1012 else if ( leftType == QgsProcessingToolboxModelNode::NodeType::Group )
1019 bool isRecentNode =
false;
1020 QModelIndex parent = left.parent();
1021 while ( parent.isValid() )
1025 isRecentNode =
true;
1028 parent = parent.parent();
1032 return left.row() < right.row();
1036 QString leftStr = sourceModel()->data( left ).toString();
1037 QString rightStr = sourceModel()->data( right ).toString();
1038 return QString::localeAwareCompare( leftStr, rightStr ) < 0;
1043 if ( role == Qt::ForegroundRole && !mFilterString.isEmpty() )
1045 QModelIndex sourceIndex = mapToSource( index );
1049 QBrush brush( qApp->palette().color( QPalette::Text ), Qt::SolidPattern );
1050 QColor fadedTextColor = brush.color();
1051 fadedTextColor.setAlpha( 100 );
1052 brush.setColor( fadedTextColor );
1056 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.
static QString unaccent(const QString &input)
Removes accents and other diacritical marks from a string, replacing accented characters with their u...
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