17#include "moc_qgsprocessingtoolboxmodel.cpp"
27#ifdef ENABLE_MODELTEST
37QgsProcessingToolboxModelNode::~QgsProcessingToolboxModelNode()
42QgsProcessingToolboxModelNode *QgsProcessingToolboxModelNode::takeChild( QgsProcessingToolboxModelNode *node )
44 return mChildren.takeAt( mChildren.indexOf( node ) );
47QgsProcessingToolboxModelGroupNode *QgsProcessingToolboxModelNode::getChildGroupNode(
const QString &groupId )
49 for ( QgsProcessingToolboxModelNode *node : std::as_const( mChildren ) )
51 if ( node->nodeType() == NodeType::Group )
53 QgsProcessingToolboxModelGroupNode *groupNode = qobject_cast<QgsProcessingToolboxModelGroupNode *>( node );
54 if ( groupNode && groupNode->id() == groupId )
61void QgsProcessingToolboxModelNode::addChildNode( QgsProcessingToolboxModelNode *node )
66 Q_ASSERT( !node->mParent );
69 mChildren.append( node );
72void QgsProcessingToolboxModelNode::deleteChildren()
74 qDeleteAll( mChildren );
82QgsProcessingToolboxModelProviderNode::QgsProcessingToolboxModelProviderNode(
QgsProcessingProvider *provider )
83 : mProviderId( provider->id() )
84 , mProvider( provider )
96QgsProcessingToolboxModelGroupNode::QgsProcessingToolboxModelGroupNode(
const QString &
id,
const QString &name )
115 : mParamType( paramType )
130 : QAbstractItemModel( parent )
131 , mRegistry( registry ? registry :
QgsApplication::processingRegistry() )
132 , mRecentLog( recentLog )
133 , mFavoriteManager( favoriteManager )
134 , mRootNode( std::make_unique<QgsProcessingToolboxModelGroupNode>( QString(), QString() ) )
139 connect( mRecentLog, &QgsProcessingRecentAlgorithmLog::changed,
this, [=] { repopulateRecentAlgorithms(); } );
141 if ( mFavoriteManager )
142 connect( mFavoriteManager, &QgsProcessingFavoriteAlgorithmManager::changed,
this, [=] { repopulateFavoriteAlgorithms(); } );
151void QgsProcessingToolboxModel::rebuild()
155 mRootNode->deleteChildren();
156 mRecentNode =
nullptr;
157 mFavoriteNode =
nullptr;
161 auto recentNode = std::make_unique<QgsProcessingToolboxModelRecentNode>();
163 mRecentNode = recentNode.get();
164 mRootNode->addChildNode( recentNode.release() );
165 repopulateRecentAlgorithms(
true );
168 if ( mFavoriteManager )
170 auto favoriteNode = std::make_unique<QgsProcessingToolboxModelFavoriteNode>();
172 mFavoriteNode = favoriteNode.get();
173 mRootNode->addChildNode( favoriteNode.release() );
174 repopulateFavoriteAlgorithms(
true );
180 auto groupNode = std::make_unique<QgsProcessingToolboxModelParameterGroupNode>();
185 return QString::localeAwareCompare( a->name(), b->name() ) < 0;
191 auto paramNode = std::make_unique<QgsProcessingToolboxModelParameterNode>( param );
192 groupNode->addChildNode( paramNode.release() );
195 mRootNode->addChildNode( groupNode.release() );
201 const QList<QgsProcessingProvider *> providers = mRegistry->providers();
204 addProvider( provider );
210void QgsProcessingToolboxModel::repopulateRecentAlgorithms(
bool resetting )
212 if ( !mRecentNode || !mRecentLog )
215 QModelIndex recentIndex =
index( 0, 0 );
216 const int prevCount =
rowCount( recentIndex );
217 if ( !resetting && prevCount > 0 )
219 beginRemoveRows( recentIndex, 0, prevCount - 1 );
220 mRecentNode->deleteChildren();
231 const QStringList recentAlgIds = mRecentLog->recentAlgorithmIds();
232 QList<const QgsProcessingAlgorithm *> recentAlgorithms;
233 recentAlgorithms.reserve( recentAlgIds.count() );
234 for (
const QString &
id : recentAlgIds )
241 if ( recentAlgorithms.empty() )
250 beginInsertRows( recentIndex, 0, recentAlgorithms.count() - 1 );
255 auto algorithmNode = std::make_unique<QgsProcessingToolboxModelAlgorithmNode>(
algorithm );
256 mRecentNode->addChildNode( algorithmNode.release() );
266void QgsProcessingToolboxModel::repopulateFavoriteAlgorithms(
bool resetting )
268 if ( !mFavoriteNode || !mFavoriteManager )
273 int idx = ( mRecentNode && mRecentLog ) ? 1 : 0;
275 QModelIndex favoriteIndex =
index( idx, 0 );
276 const int prevCount =
rowCount( favoriteIndex );
277 if ( !resetting && prevCount > 0 )
279 beginRemoveRows( favoriteIndex, 0, prevCount - 1 );
280 mFavoriteNode->deleteChildren();
291 const QStringList favoriteAlgIds = mFavoriteManager->favoriteAlgorithmIds();
292 QList<const QgsProcessingAlgorithm *> favoriteAlgorithms;
293 favoriteAlgorithms.reserve( favoriteAlgIds.count() );
294 for (
const QString &
id : favoriteAlgIds )
301 if ( favoriteAlgorithms.empty() )
310 beginInsertRows( favoriteIndex, 0, favoriteAlgorithms.count() - 1 );
315 auto algorithmNode = std::make_unique<QgsProcessingToolboxModelAlgorithmNode>(
algorithm );
316 mFavoriteNode->addChildNode( algorithmNode.release() );
328 if ( !
index.isValid() )
329 return mRootNode.get();
331 QObject *obj =
reinterpret_cast<QObject *
>(
index.internalPointer() );
332 return qobject_cast<QgsProcessingToolboxModelNode *>( obj );
337 if ( !node || !node->parent() )
338 return QModelIndex();
340 QModelIndex parentIndex =
node2index( node->parent() );
342 int row = node->parent()->children().indexOf( node );
343 Q_ASSERT( row >= 0 );
344 return index( row, 0, parentIndex );
354 QgsProcessingToolboxModelNode *parentNode =
nullptr;
355 if ( !isTopLevelProvider( provider->
id() ) )
357 auto node = std::make_unique<QgsProcessingToolboxModelProviderNode>( provider );
358 parentNode = node.get();
359 mRootNode->addChildNode( node.release() );
363 parentNode = mRootNode.get();
366 const QList<const QgsProcessingAlgorithm *> algorithms = provider->
algorithms();
369 auto algorithmNode = std::make_unique<QgsProcessingToolboxModelAlgorithmNode>(
algorithm );
372 if ( !groupId.isEmpty() )
375 QgsProcessingToolboxModelGroupNode *groupNode = parentNode->getChildGroupNode( groupId );
380 parentNode->addChildNode( groupNode );
382 groupNode->addChildNode( algorithmNode.release() );
388 parentNode->addChildNode( algorithmNode.release() );
393bool QgsProcessingToolboxModel::isTopLevelProvider(
const QString &providerId )
395 return providerId == QLatin1String(
"qgis" ) || providerId == QLatin1String(
"native" ) || providerId == QLatin1String(
"3d" ) || providerId == QLatin1String(
"pdal" );
400 return QStringLiteral(
"<p><b>%1</b></p>%2<p>%3</p>%4" ).arg(
algorithm->
displayName(), !
algorithm->
shortDescription().isEmpty() ? QStringLiteral(
"<p>%1</p>" ).arg(
algorithm->
shortDescription() ) : QString(), QObject::tr(
"Algorithm ID: ‘%1’" ).arg( QStringLiteral(
"<i>%1</i>" ).arg(
algorithm->id() ) ), (
algorithm->
flags() &
Qgis::ProcessingAlgorithmFlag::KnownIssues ) ? QStringLiteral(
"<b style=\"color:red\">%1</b>" ).arg( QObject::tr(
"Warning: Algorithm has known issues" ) ) : QString() );
405 if ( !
index.isValid() )
406 return Qt::ItemFlags();
408 return QAbstractItemModel::flags(
index );
413 if ( !
index.isValid() )
419 return static_cast<int>( node->nodeType() );
424 bool isRecentNode =
false;
426 isRecentNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeType::Recent;
428 bool isFavoriteNode =
false;
430 isFavoriteNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeType::Favorite;
432 bool isParameterGroupNode =
false;
434 isParameterGroupNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeType::ParameterGroup;
437 QgsProcessingToolboxModelGroupNode *groupNode = qobject_cast<QgsProcessingToolboxModelGroupNode *>(
index2node(
index ) );
443 case Qt::DisplayRole:
445 switch (
index.column() )
449 return provider->
name();
452 else if ( paramType )
453 return paramType->
name();
454 else if ( groupNode )
455 return groupNode->name();
456 else if ( isRecentNode )
457 return tr(
"Recently used" );
458 else if ( isFavoriteNode )
459 return tr(
"Favorites" );
460 else if ( isParameterGroupNode )
461 return tr(
"Input parameters" );
471 case Qt::ToolTipRole:
477 else if ( paramType )
479 else if ( groupNode )
480 return groupNode->name();
481 else if ( isParameterGroupNode )
482 return tr(
"Input parameters used in the modeler" );
487 case Qt::ForegroundRole:
490 return QBrush( QColor( Qt::red ) );
495 case Qt::DecorationRole:
497 switch (
index.column() )
502 return provider->
icon();
509 else if ( paramType )
511 else if ( isRecentNode )
513 else if ( isFavoriteNode )
515 else if ( isParameterGroupNode )
517 else if ( !
index.parent().isValid() )
531 switch (
index.column() )
547 switch (
index.column() )
552 return static_cast<int>( provider->
flags() );
567 switch (
index.column() )
583 switch (
index.column() )
599 switch (
index.column() )
615 switch (
index.column() )
630 switch (
index.column() )
635 return paramType->
id();
658 return n->children().count();
668 if ( !hasIndex( row, column,
parent ) )
669 return QModelIndex();
673 return QModelIndex();
675 return createIndex( row, column,
static_cast<QObject *
>( n->children().at( row ) ) );
680 if ( !child.isValid() )
681 return QModelIndex();
683 if ( QgsProcessingToolboxModelNode *n =
index2node( child ) )
690 return QModelIndex();
696 if ( indexes.isEmpty() )
702 QByteArray encodedData;
703 QDataStream stream( &encodedData, QIODevice::WriteOnly | QIODevice::Truncate );
705 auto mimeData = std::make_unique<QMimeData>();
711 mimeData->setData( QStringLiteral(
"application/x-vnd.qgis.qgis.algorithmid" ), encodedData );
716 QByteArray encodedData;
717 QDataStream stream( &encodedData, QIODevice::WriteOnly | QIODevice::Truncate );
719 auto mimeData = std::make_unique<QMimeData>();
723 stream << paramType->
id();
725 mimeData->setData( QStringLiteral(
"application/x-vnd.qgis.qgis.parametertypeid" ), encodedData );
734 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Provider )
737 return qobject_cast<QgsProcessingToolboxModelProviderNode *>( n )->provider();
743 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Provider )
746 return qobject_cast<QgsProcessingToolboxModelProviderNode *>( n )->providerId();
752 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Algorithm )
755 return qobject_cast<QgsProcessingToolboxModelAlgorithmNode *>( n )->algorithm();
761 return ( n && n->nodeType() == QgsProcessingToolboxModelNode::NodeType::Algorithm );
767 return ( n && n->nodeType() == QgsProcessingToolboxModelNode::NodeType::Parameter );
773 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeType::Parameter )
776 return qobject_cast<QgsProcessingToolboxModelParameterNode *>( n )->parameterType();
781 std::function<QModelIndex(
const QModelIndex &
parent,
const QString &providerId )> findIndex = [&](
const QModelIndex &
parent,
const QString &providerId ) -> QModelIndex {
786 if ( !currentProviderId.isEmpty() && currentProviderId == providerId )
789 QModelIndex checkChildren = findIndex( current, providerId );
790 if ( checkChildren.isValid() )
791 return checkChildren;
793 return QModelIndex();
796 return findIndex( QModelIndex(), providerId );
801 Q_ASSERT( parentNode );
803 QgsProcessingToolboxModelNode *grandParentNode = parentNode->parent();
804 if ( !grandParentNode )
805 return QModelIndex();
807 int row = grandParentNode->children().indexOf( parentNode );
808 Q_ASSERT( row >= 0 );
810 return createIndex( row, 0,
static_cast<QObject *
>( parentNode ) );
818 : QSortFilterProxyModel( parent )
821 setSourceModel( mModel );
822 setDynamicSortFilter(
true );
823 setSortLocaleAware(
true );
824 setFilterCaseSensitivity( Qt::CaseInsensitive );
849 mInPlaceLayer = layer;
856 mFilterString = filter;
862 QModelIndex sourceIndex = mModel->
index( sourceRow, 0, sourceParent );
869 if ( !mFilterString.trimmed().isEmpty() )
876 QStringList parentText;
877 QModelIndex parent = sourceIndex.parent();
878 while ( parent.isValid() )
880 const QStringList parentParts = sourceModel()->data( parent, Qt::DisplayRole ).toString().split(
' ' );
881 if ( !parentParts.empty() )
882 parentText.append( parentParts );
883 parent = parent.parent();
886 QStringList partsToSearch;
887 partsToSearch << sourceModel()->data( sourceIndex, Qt::DisplayRole ).toString().split(
' ' );
888 partsToSearch << algId << algName;
889 partsToSearch.append( algTags );
890 if ( !shortDesc.isEmpty() )
891 partsToSearch.append( shortDesc.split(
' ' ) );
892 partsToSearch.append( parentText );
894 const QStringList partsToMatch = mFilterString.trimmed().split(
' ' );
895 for (
const QString &part : partsToMatch )
898 for (
const QString &partToSearch : std::as_const( partsToSearch ) )
900 if ( partToSearch.contains( part, Qt::CaseInsensitive ) )
914 if ( !supportsInPlace )
926 return !isHiddenFromModeler;
931 return !isHiddenFromToolbox;
943 if ( !mFilterString.trimmed().isEmpty() )
945 QStringList partsToSearch;
946 partsToSearch << sourceModel()->data( sourceIndex, Qt::DisplayRole ).toString().split(
' ' );
949 const QStringList partsToMatch = mFilterString.trimmed().split(
' ' );
950 for (
const QString &part : partsToMatch )
953 for (
const QString &partToSearch : std::as_const( partsToSearch ) )
955 if ( partToSearch.contains( part, Qt::CaseInsensitive ) )
968 bool hasChildren =
false;
970 int count = sourceModel()->rowCount( sourceIndex );
971 for (
int i = 0; i < count; ++i )
988 if ( leftType == QgsProcessingToolboxModelNode::NodeType::Recent )
990 else if ( rightType == QgsProcessingToolboxModelNode::NodeType::Recent )
992 else if ( leftType == QgsProcessingToolboxModelNode::NodeType::Favorite )
994 else if ( rightType == QgsProcessingToolboxModelNode::NodeType::Favorite )
996 else if ( leftType != rightType )
998 if ( leftType == QgsProcessingToolboxModelNode::NodeType::Provider )
1000 else if ( rightType == QgsProcessingToolboxModelNode::NodeType::Provider )
1002 else if ( leftType == QgsProcessingToolboxModelNode::NodeType::Group )
1009 bool isRecentNode =
false;
1010 QModelIndex parent = left.parent();
1011 while ( parent.isValid() )
1015 isRecentNode =
true;
1018 parent = parent.parent();
1022 return left.row() < right.row();
1026 QString leftStr = sourceModel()->data( left ).toString();
1027 QString rightStr = sourceModel()->data( right ).toString();
1028 return QString::localeAwareCompare( leftStr, rightStr ) < 0;
1033 if ( role == Qt::ForegroundRole && !mFilterString.isEmpty() )
1035 QModelIndex sourceIndex = mapToSource( index );
1039 QBrush brush( qApp->palette().color( QPalette::Text ), Qt::SolidPattern );
1040 QColor fadedTextColor = brush.color();
1041 fadedTextColor.setAlpha( 100 );
1042 brush.setColor( fadedTextColor );
1046 return QSortFilterProxyModel::data( index, role );
Provides global constants and enumerations for use throughout the application.
@ 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 QIcon icon() const
Returns an icon for the algorithm.
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 QStringList tags() const
Returns a list of tags which relate to the algorithm, and are used to assist users in searching for s...
QgsProcessingProvider * provider() const
Returns the provider to which this algorithm belongs.
virtual bool supportInPlaceEdit(const QgsMapLayer *layer) const
Checks whether this algorithm supports in-place editing on the given layer Default implementation ret...
virtual QString name() const =0
Returns the algorithm name, used for identifying the algorithm.
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