QGIS API Documentation 3.31.0-Master (d2b117a3c8)
qgsprocessingtoolboxmodel.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingtoolboxmodel.cpp
3 -------------------------------
4 begin : May 2018
5 copyright : (C) 2018 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17#include "qgsapplication.h"
18#include "qgsvectorlayer.h"
21#include <functional>
22#include <QPalette>
23#include <QMimeData>
24
25#ifdef ENABLE_MODELTEST
26#include "modeltest.h"
27#endif
28
30
31//
32// QgsProcessingToolboxModelNode
33//
34
35QgsProcessingToolboxModelNode::~QgsProcessingToolboxModelNode()
36{
37 deleteChildren();
38}
39
40QgsProcessingToolboxModelNode *QgsProcessingToolboxModelNode::takeChild( QgsProcessingToolboxModelNode *node )
41{
42 return mChildren.takeAt( mChildren.indexOf( node ) );
43}
44
45QgsProcessingToolboxModelGroupNode *QgsProcessingToolboxModelNode::getChildGroupNode( const QString &groupId )
46{
47 for ( QgsProcessingToolboxModelNode *node : std::as_const( mChildren ) )
48 {
49 if ( node->nodeType() == NodeGroup )
50 {
51 QgsProcessingToolboxModelGroupNode *groupNode = qobject_cast< QgsProcessingToolboxModelGroupNode * >( node );
52 if ( groupNode && groupNode->id() == groupId )
53 return groupNode;
54 }
55 }
56 return nullptr;
57}
58
59void QgsProcessingToolboxModelNode::addChildNode( QgsProcessingToolboxModelNode *node )
60{
61 if ( !node )
62 return;
63
64 Q_ASSERT( !node->mParent );
65 node->mParent = this;
66
67 mChildren.append( node );
68}
69
70void QgsProcessingToolboxModelNode::deleteChildren()
71{
72 qDeleteAll( mChildren );
73 mChildren.clear();
74}
75
76//
77// QgsProcessingToolboxModelProviderNode
78//
79
80QgsProcessingToolboxModelProviderNode::QgsProcessingToolboxModelProviderNode( QgsProcessingProvider *provider )
81 : mProviderId( provider->id() )
82 , mProvider( provider )
83{}
84
85QgsProcessingProvider *QgsProcessingToolboxModelProviderNode::provider()
86{
87 return mProvider;
88}
89
90//
91// QgsProcessingToolboxModelGroupNode
92//
93
94QgsProcessingToolboxModelGroupNode::QgsProcessingToolboxModelGroupNode( const QString &id, const QString &name )
95 : mId( id )
96 , mName( name )
97{}
98
99//
100// QgsProcessingToolboxModelAlgorithmNode
101//
102
103QgsProcessingToolboxModelAlgorithmNode::QgsProcessingToolboxModelAlgorithmNode( const QgsProcessingAlgorithm *algorithm )
104 : mAlgorithm( algorithm )
105{}
106
108{
109 return mAlgorithm;
110}
111
113
114//
115// QgsProcessingToolboxModel
116//
117
118QgsProcessingToolboxModel::QgsProcessingToolboxModel( QObject *parent, QgsProcessingRegistry *registry, QgsProcessingRecentAlgorithmLog *recentLog )
119 : QAbstractItemModel( parent )
120 , mRegistry( registry ? registry : QgsApplication::processingRegistry() )
121 , mRecentLog( recentLog )
122 , mRootNode( std::make_unique< QgsProcessingToolboxModelGroupNode >( QString(), QString() ) )
123{
124 rebuild();
125
126 if ( mRecentLog )
127 connect( mRecentLog, &QgsProcessingRecentAlgorithmLog::changed, this, [ = ] { repopulateRecentAlgorithms(); } );
128
129 connect( mRegistry, &QgsProcessingRegistry::providerAdded, this, &QgsProcessingToolboxModel::rebuild );
130 connect( mRegistry, &QgsProcessingRegistry::providerRemoved, this, &QgsProcessingToolboxModel::providerRemoved );
131}
132
133void QgsProcessingToolboxModel::rebuild()
134{
135 beginResetModel();
136
137 mRootNode->deleteChildren();
138 mRecentNode = nullptr;
139
140 if ( mRecentLog )
141 {
142 std::unique_ptr< QgsProcessingToolboxModelRecentNode > recentNode = std::make_unique< QgsProcessingToolboxModelRecentNode >();
143 mRecentNode = recentNode.get();
144 mRootNode->addChildNode( recentNode.release() );
145 repopulateRecentAlgorithms( true );
146 }
147
148 if ( mRegistry )
149 {
150 const QList< QgsProcessingProvider * > providers = mRegistry->providers();
151 for ( QgsProcessingProvider *provider : providers )
152 {
153 addProvider( provider );
154 }
155 }
156 endResetModel();
157}
158
159void QgsProcessingToolboxModel::repopulateRecentAlgorithms( bool resetting )
160{
161 if ( !mRecentNode || !mRecentLog )
162 return;
163
164 QModelIndex recentIndex = index( 0, 0 );
165 const int prevCount = rowCount( recentIndex );
166 if ( !resetting && prevCount > 0 )
167 {
168 beginRemoveRows( recentIndex, 0, prevCount - 1 );
169 mRecentNode->deleteChildren();
170 endRemoveRows();
171 }
172
173 if ( !mRegistry )
174 {
175 if ( !resetting )
177 return;
178 }
179
180 const QStringList recentAlgIds = mRecentLog->recentAlgorithmIds();
181 QList< const QgsProcessingAlgorithm * > recentAlgorithms;
182 recentAlgorithms.reserve( recentAlgIds.count() );
183 for ( const QString &id : recentAlgIds )
184 {
185 const QgsProcessingAlgorithm *algorithm = mRegistry->algorithmById( id );
186 if ( algorithm )
187 recentAlgorithms << algorithm;
188 }
189
190 if ( recentAlgorithms.empty() )
191 {
192 if ( !resetting )
194 return;
195 }
196
197 if ( !resetting )
198 {
199 beginInsertRows( recentIndex, 0, recentAlgorithms.count() - 1 );
200 }
201
202 for ( const QgsProcessingAlgorithm *algorithm : std::as_const( recentAlgorithms ) )
203 {
204 std::unique_ptr< QgsProcessingToolboxModelAlgorithmNode > algorithmNode = std::make_unique< QgsProcessingToolboxModelAlgorithmNode >( algorithm );
205 mRecentNode->addChildNode( algorithmNode.release() );
206 }
207
208 if ( !resetting )
209 {
210 endInsertRows();
212 }
213}
214
215void QgsProcessingToolboxModel::providerAdded( const QString &id )
216{
217 if ( !mRegistry )
218 return;
219
220 QgsProcessingProvider *provider = mRegistry->providerById( id );
221 if ( !provider )
222 return;
223
224 if ( !isTopLevelProvider( id ) )
225 {
226 int previousRowCount = rowCount();
227 beginInsertRows( QModelIndex(), previousRowCount, previousRowCount );
228 addProvider( provider );
229 endInsertRows();
230 }
231 else
232 {
233 // native providers use top level groups - that's too hard for us to
234 // work out exactly what's going to change, so just reset the model
235 beginResetModel();
236 addProvider( provider );
237 endResetModel();
238 }
239}
240
241void QgsProcessingToolboxModel::providerRemoved( const QString & )
242{
243 // native providers use top level groups - so we can't
244 // work out what to remove. Just rebuild the whole model instead.
245 rebuild();
246}
247
248QgsProcessingToolboxModelNode *QgsProcessingToolboxModel::index2node( const QModelIndex &index ) const
249{
250 if ( !index.isValid() )
251 return mRootNode.get();
252
253 QObject *obj = reinterpret_cast<QObject *>( index.internalPointer() );
254 return qobject_cast<QgsProcessingToolboxModelNode *>( obj );
255}
256
257QModelIndex QgsProcessingToolboxModel::node2index( QgsProcessingToolboxModelNode *node ) const
258{
259 if ( !node || !node->parent() )
260 return QModelIndex(); // this is the only root item -> invalid index
261
262 QModelIndex parentIndex = node2index( node->parent() );
263
264 int row = node->parent()->children().indexOf( node );
265 Q_ASSERT( row >= 0 );
266 return index( row, 0, parentIndex );
267}
268
269void QgsProcessingToolboxModel::addProvider( QgsProcessingProvider *provider )
270{
271 if ( !provider )
272 return;
273
274 connect( provider, &QgsProcessingProvider::algorithmsLoaded, this, &QgsProcessingToolboxModel::rebuild, Qt::UniqueConnection );
275
276 QgsProcessingToolboxModelNode *parentNode = nullptr;
277 if ( !isTopLevelProvider( provider->id() ) )
278 {
279 std::unique_ptr< QgsProcessingToolboxModelProviderNode > node = std::make_unique< QgsProcessingToolboxModelProviderNode >( provider );
280 parentNode = node.get();
281 mRootNode->addChildNode( node.release() );
282 }
283 else
284 {
285 parentNode = mRootNode.get();
286 }
287
288 const QList< const QgsProcessingAlgorithm * > algorithms = provider->algorithms();
289 for ( const QgsProcessingAlgorithm *algorithm : algorithms )
290 {
291 std::unique_ptr< QgsProcessingToolboxModelAlgorithmNode > algorithmNode = std::make_unique< QgsProcessingToolboxModelAlgorithmNode >( algorithm );
292
293 const QString groupId = algorithm->groupId();
294 if ( !groupId.isEmpty() )
295 {
296 QgsProcessingToolboxModelGroupNode *groupNode = parentNode->getChildGroupNode( groupId );
297 if ( !groupNode )
298 {
299 groupNode = new QgsProcessingToolboxModelGroupNode( algorithm->groupId(), algorithm->group() );
300 parentNode->addChildNode( groupNode );
301 }
302 groupNode->addChildNode( algorithmNode.release() );
303 }
304 else
305 {
306 // "top level" algorithm - no group
307 parentNode->addChildNode( algorithmNode.release() );
308 }
309 }
310}
311
312bool QgsProcessingToolboxModel::isTopLevelProvider( const QString &providerId )
313{
314 return providerId == QLatin1String( "qgis" ) ||
315 providerId == QLatin1String( "native" ) ||
316 providerId == QLatin1String( "3d" ) ||
317 providerId == QLatin1String( "pdal" );
318}
319
320QString QgsProcessingToolboxModel::toolTipForAlgorithm( const QgsProcessingAlgorithm *algorithm )
321{
322 return QStringLiteral( "<p><b>%1</b></p>%2<p>%3</p>%4" ).arg(
324 !algorithm->shortDescription().isEmpty() ? QStringLiteral( "<p>%1</p>" ).arg( algorithm->shortDescription() ) : QString(),
325 QObject::tr( "Algorithm ID: ‘%1’" ).arg( QStringLiteral( "<i>%1</i>" ).arg( algorithm->id() ) ),
326 ( algorithm->flags() & QgsProcessingAlgorithm::FlagKnownIssues ) ? QStringLiteral( "<b style=\"color:red\">%1</b>" ).arg( QObject::tr( "Warning: Algorithm has known issues" ) ) : QString()
327 );
328}
329
330Qt::ItemFlags QgsProcessingToolboxModel::flags( const QModelIndex &index ) const
331{
332 if ( !index.isValid() )
333 return Qt::ItemFlags();
334
335 return QAbstractItemModel::flags( index );
336}
337
338QVariant QgsProcessingToolboxModel::data( const QModelIndex &index, int role ) const
339{
340 if ( !index.isValid() )
341 return QVariant();
342
343 if ( role == RoleNodeType )
344 {
345 if ( QgsProcessingToolboxModelNode *node = index2node( index ) )
346 return node->nodeType();
347 else
348 return QVariant();
349 }
350
351 bool isRecentNode = false;
352 if ( QgsProcessingToolboxModelNode *node = index2node( index ) )
353 isRecentNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeRecent;
354
356 QgsProcessingToolboxModelGroupNode *groupNode = qobject_cast< QgsProcessingToolboxModelGroupNode * >( index2node( index ) );
358
359 switch ( role )
360 {
361 case Qt::DisplayRole:
362 {
363 switch ( index.column() )
364 {
365 case 0:
366 if ( provider )
367 return provider->name();
368 else if ( algorithm )
369 return algorithm->displayName();
370 else if ( groupNode )
371 return groupNode->name();
372 else if ( isRecentNode )
373 return tr( "Recently used" );
374 else
375 return QVariant();
376
377 default:
378 return QVariant();
379 }
380 break;
381 }
382
383 case Qt::ToolTipRole:
384 {
385 if ( provider )
386 return provider->longName();
387 else if ( algorithm )
388 return toolTipForAlgorithm( algorithm );
389 else if ( groupNode )
390 return groupNode->name();
391 else
392 return QVariant();
393 }
394
395 case Qt::ForegroundRole:
396 {
398 return QBrush( QColor( Qt::red ) );
399 else
400 return QVariant();
401 }
402
403 case Qt::DecorationRole:
404 {
405 switch ( index.column() )
406 {
407 case 0:
408 {
409 if ( provider )
410 return provider->icon();
411 else if ( algorithm )
412 {
414 return QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
415 return algorithm->icon();
416 }
417 else if ( isRecentNode )
418 return QgsApplication::getThemeIcon( QStringLiteral( "/mIconHistory.svg" ) );
419 else if ( !index.parent().isValid() )
420 // top level groups get the QGIS icon
421 return QgsApplication::getThemeIcon( QStringLiteral( "/providerQgis.svg" ) );
422 else
423 return QVariant();
424 }
425
426 default:
427 return QVariant();
428 }
429 break;
430 }
431
433 switch ( index.column() )
434 {
435 case 0:
436 {
437 if ( algorithm )
438 return static_cast< int >( algorithm->flags() );
439 else
440 return QVariant();
441 }
442
443 default:
444 return QVariant();
445 }
446 break;
447
449 switch ( index.column() )
450 {
451 case 0:
452 {
453 if ( provider )
454 return static_cast< int >( provider->flags() );
455 else if ( algorithm && algorithm->provider() )
456 return static_cast< int >( algorithm->provider()->flags() );
457 else if ( index.parent().data( RoleProviderFlags ).isValid() ) // group node
458 return static_cast< int >( index.parent().data( RoleProviderFlags ).toInt() );
459 else
460 return QVariant();
461 }
462
463 default:
464 return QVariant();
465 }
466 break;
467
468 case RoleAlgorithmId:
469 switch ( index.column() )
470 {
471 case 0:
472 {
473 if ( algorithm )
474 return algorithm->id();
475 else
476 return QVariant();
477 }
478
479 default:
480 return QVariant();
481 }
482 break;
483
485 switch ( index.column() )
486 {
487 case 0:
488 {
489 if ( algorithm )
490 return algorithm->name();
491 else
492 return QVariant();
493 }
494
495 default:
496 return QVariant();
497 }
498 break;
499
501 switch ( index.column() )
502 {
503 case 0:
504 {
505 if ( algorithm )
506 return algorithm->tags();
507 else
508 return QVariant();
509 }
510
511 default:
512 return QVariant();
513 }
514 break;
515
517 switch ( index.column() )
518 {
519 case 0:
520 {
521 if ( algorithm )
522 return algorithm->shortDescription();
523 else
524 return QVariant();
525 }
526
527 default:
528 return QVariant();
529 }
530 break;
531
532 default:
533 return QVariant();
534 }
535#ifndef _MSC_VER // avoid warning
536 return QVariant();
537#endif
538}
539
540int QgsProcessingToolboxModel::rowCount( const QModelIndex &parent ) const
541{
542 QgsProcessingToolboxModelNode *n = index2node( parent );
543 if ( !n )
544 return 0;
545
546 return n->children().count();
547}
548
549int QgsProcessingToolboxModel::columnCount( const QModelIndex & ) const
550{
551 return 1;
552}
553
554QModelIndex QgsProcessingToolboxModel::index( int row, int column, const QModelIndex &parent ) const
555{
556 if ( !hasIndex( row, column, parent ) )
557 return QModelIndex();
558
559 QgsProcessingToolboxModelNode *n = index2node( parent );
560 if ( !n )
561 return QModelIndex(); // have no children
562
563 return createIndex( row, column, static_cast<QObject *>( n->children().at( row ) ) );
564}
565
566QModelIndex QgsProcessingToolboxModel::parent( const QModelIndex &child ) const
567{
568 if ( !child.isValid() )
569 return QModelIndex();
570
571 if ( QgsProcessingToolboxModelNode *n = index2node( child ) )
572 {
573 return indexOfParentTreeNode( n->parent() ); // must not be null
574 }
575 else
576 {
577 Q_ASSERT( false ); // no other node types!
578 return QModelIndex();
579 }
580}
581
582QMimeData *QgsProcessingToolboxModel::mimeData( const QModelIndexList &indexes ) const
583{
584 if ( !indexes.isEmpty() && isAlgorithm( indexes.at( 0 ) ) )
585 {
586 QByteArray encodedData;
587 QDataStream stream( &encodedData, QIODevice::WriteOnly | QIODevice::Truncate );
588
589 std::unique_ptr< QMimeData > mimeData = std::make_unique< QMimeData >();
590 const QgsProcessingAlgorithm *algorithm = algorithmForIndex( indexes.at( 0 ) );
591 if ( algorithm )
592 {
593 stream << algorithm->id();
594 }
595 mimeData->setData( QStringLiteral( "application/x-vnd.qgis.qgis.algorithmid" ), encodedData );
596 return mimeData.release();
597 }
598 return nullptr;
599}
600
602{
603 QgsProcessingToolboxModelNode *n = index2node( index );
604 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeProvider )
605 return nullptr;
606
607 return qobject_cast< QgsProcessingToolboxModelProviderNode * >( n )->provider();
608}
609
610QString QgsProcessingToolboxModel::providerIdForIndex( const QModelIndex &index ) const
611{
612 QgsProcessingToolboxModelNode *n = index2node( index );
613 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeProvider )
614 return nullptr;
615
616 return qobject_cast< QgsProcessingToolboxModelProviderNode * >( n )->providerId();
617}
618
620{
621 QgsProcessingToolboxModelNode *n = index2node( index );
622 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeAlgorithm )
623 return nullptr;
624
625 return qobject_cast< QgsProcessingToolboxModelAlgorithmNode * >( n )->algorithm();
626}
627
628bool QgsProcessingToolboxModel::isAlgorithm( const QModelIndex &index ) const
629{
630 QgsProcessingToolboxModelNode *n = index2node( index );
631 return ( n && n->nodeType() == QgsProcessingToolboxModelNode::NodeAlgorithm );
632}
633
634QModelIndex QgsProcessingToolboxModel::indexForProvider( const QString &providerId ) const
635{
636 std::function< QModelIndex( const QModelIndex &parent, const QString &providerId ) > findIndex = [&]( const QModelIndex & parent, const QString & providerId )->QModelIndex
637 {
638 for ( int row = 0; row < rowCount( parent ); ++row )
639 {
640 QModelIndex current = index( row, 0, parent );
641 const QString currentProviderId = providerIdForIndex( current );
642 if ( !currentProviderId.isEmpty() && currentProviderId == providerId )
643 return current;
644
645 QModelIndex checkChildren = findIndex( current, providerId );
646 if ( checkChildren.isValid() )
647 return checkChildren;
648 }
649 return QModelIndex();
650 };
651
652 return findIndex( QModelIndex(), providerId );
653}
654
655QModelIndex QgsProcessingToolboxModel::indexOfParentTreeNode( QgsProcessingToolboxModelNode *parentNode ) const
656{
657 Q_ASSERT( parentNode );
658
659 QgsProcessingToolboxModelNode *grandParentNode = parentNode->parent();
660 if ( !grandParentNode )
661 return QModelIndex(); // root node -> invalid index
662
663 int row = grandParentNode->children().indexOf( parentNode );
664 Q_ASSERT( row >= 0 );
665
666 return createIndex( row, 0, static_cast<QObject *>( parentNode ) );
667}
668
669//
670// QgsProcessingToolboxProxyModel
671//
672
674 QgsProcessingRecentAlgorithmLog *recentLog )
675 : QSortFilterProxyModel( parent )
676 , mModel( new QgsProcessingToolboxModel( this, registry, recentLog ) )
677{
678 setSourceModel( mModel );
679 setDynamicSortFilter( true );
680 setSortLocaleAware( true );
681 setFilterCaseSensitivity( Qt::CaseInsensitive );
682 sort( 0 );
683
684 connect( mModel, &QgsProcessingToolboxModel::recentAlgorithmAdded, this, [ = ] { invalidateFilter(); } );
685}
686
688{
689 return mModel;
690}
691
693{
694 return mModel;
695}
696
697void QgsProcessingToolboxProxyModel::setFilters( QgsProcessingToolboxProxyModel::Filters filters )
698{
699 mFilters = filters;
700 invalidateFilter();
701}
702
704{
705 mInPlaceLayer = layer;
706 invalidateFilter();
707}
708
709
711{
712 mFilterString = filter;
713 invalidateFilter();
714}
715
716bool QgsProcessingToolboxProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
717{
718 QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
719 if ( mModel->isAlgorithm( sourceIndex ) )
720 {
721 const bool hasKnownIssues = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmFlags ).toInt() & QgsProcessingAlgorithm::FlagKnownIssues;
722 if ( hasKnownIssues && !( mFilters & FilterShowKnownIssues ) )
723 return false;
724
725 if ( !mFilterString.trimmed().isEmpty() )
726 {
727 const QString algId = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmId ).toString();
728 const QString algName = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmName ).toString();
729 const QStringList algTags = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmTags ).toStringList();
730 const QString shortDesc = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmShortDescription ).toString();
731
732 QStringList parentText;
733 QModelIndex parent = sourceIndex.parent();
734 while ( parent.isValid() )
735 {
736 const QStringList parentParts = sourceModel()->data( parent, Qt::DisplayRole ).toString().split( ' ' );
737 if ( !parentParts.empty() )
738 parentText.append( parentParts );
739 parent = parent.parent();
740 }
741
742 const QStringList partsToMatch = mFilterString.trimmed().split( ' ' );
743
744 QStringList partsToSearch = sourceModel()->data( sourceIndex, Qt::DisplayRole ).toString().split( ' ' );
745 partsToSearch << algId << algName;
746 partsToSearch.append( algTags );
747 if ( !shortDesc.isEmpty() )
748 partsToSearch.append( shortDesc.split( ' ' ) );
749 partsToSearch.append( parentText );
750
751 for ( const QString &part : partsToMatch )
752 {
753 bool found = false;
754 for ( const QString &partToSearch : std::as_const( partsToSearch ) )
755 {
756 if ( partToSearch.contains( part, Qt::CaseInsensitive ) )
757 {
758 found = true;
759 break;
760 }
761 }
762 if ( !found )
763 return false; // couldn't find a match for this word, so hide algorithm
764 }
765 }
766
767 if ( mFilters & FilterInPlace )
768 {
769 const bool supportsInPlace = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmFlags ).toInt() & QgsProcessingAlgorithm::FlagSupportsInPlaceEdits;
770 if ( !supportsInPlace )
771 return false;
772
773 const QgsProcessingAlgorithm *alg = mModel->algorithmForIndex( sourceIndex );
774 if ( !( mInPlaceLayer && alg && alg->supportInPlaceEdit( mInPlaceLayer ) ) )
775 {
776 return false;
777 }
778 }
779 if ( mFilters & FilterModeler )
780 {
781 bool isHiddenFromModeler = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmFlags ).toInt() & QgsProcessingAlgorithm::FlagHideFromModeler;
782 return !isHiddenFromModeler;
783 }
784 if ( mFilters & FilterToolbox )
785 {
786 bool isHiddenFromToolbox = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmFlags ).toInt() & QgsProcessingAlgorithm::FlagHideFromToolbox;
787 return !isHiddenFromToolbox;
788 }
789 return true;
790 }
791
792 bool hasChildren = false;
793 // groups/providers are shown only if they have visible children
794 int count = sourceModel()->rowCount( sourceIndex );
795 for ( int i = 0; i < count; ++i )
796 {
797 if ( filterAcceptsRow( i, sourceIndex ) )
798 {
799 hasChildren = true;
800 break;
801 }
802 }
803
804 return hasChildren;
805}
806
807bool QgsProcessingToolboxProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
808{
809 QgsProcessingToolboxModelNode::NodeType leftType = static_cast< QgsProcessingToolboxModelNode::NodeType >( sourceModel()->data( left, QgsProcessingToolboxModel::RoleNodeType ).toInt() );
810 QgsProcessingToolboxModelNode::NodeType rightType = static_cast< QgsProcessingToolboxModelNode::NodeType >( sourceModel()->data( right, QgsProcessingToolboxModel::RoleNodeType ).toInt() );
811
812 if ( leftType == QgsProcessingToolboxModelNode::NodeRecent )
813 return true;
814 else if ( rightType == QgsProcessingToolboxModelNode::NodeRecent )
815 return false;
816 else if ( leftType != rightType )
817 {
818 if ( leftType == QgsProcessingToolboxModelNode::NodeProvider )
819 return false;
820 else if ( rightType == QgsProcessingToolboxModelNode::NodeProvider )
821 return true;
822 else if ( leftType == QgsProcessingToolboxModelNode::NodeGroup )
823 return false;
824 else
825 return true;
826 }
827
828 // if node represents a recent algorithm, it's not sorted at all
829 bool isRecentNode = false;
830 QModelIndex parent = left.parent();
831 while ( parent.isValid() )
832 {
833 if ( mModel->data( parent, QgsProcessingToolboxModel::RoleNodeType ).toInt() == QgsProcessingToolboxModelNode::NodeRecent )
834 {
835 isRecentNode = true;
836 break;
837 }
838 parent = parent.parent();
839 }
840 if ( isRecentNode )
841 {
842 return left.row() < right.row();
843 }
844
845
846 // default mode is alphabetical order
847 QString leftStr = sourceModel()->data( left ).toString();
848 QString rightStr = sourceModel()->data( right ).toString();
849 return QString::localeAwareCompare( leftStr, rightStr ) < 0;
850}
851
852QVariant QgsProcessingToolboxProxyModel::data( const QModelIndex &index, int role ) const
853{
854 if ( role == Qt::ForegroundRole && !mFilterString.isEmpty() )
855 {
856 QModelIndex sourceIndex = mapToSource( index );
857 const QVariant flags = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleProviderFlags );
858 if ( flags.isValid() && flags.toInt() & QgsProcessingProvider::FlagDeemphasiseSearchResults )
859 {
860 QBrush brush( qApp->palette().color( QPalette::Text ), Qt::SolidPattern );
861 QColor fadedTextColor = brush.color();
862 fadedTextColor.setAlpha( 100 );
863 brush.setColor( fadedTextColor );
864 return brush;
865 }
866 }
867 return QSortFilterProxyModel::data( index, role );
868}
Extends QApplication to provide access to QGIS specific resources such as theme paths,...
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...
@ FlagSupportsInPlaceEdits
Algorithm supports in-place editing.
@ FlagKnownIssues
Algorithm has known issues.
@ FlagHideFromToolbox
Algorithm should be hidden from the toolbox.
@ FlagHideFromModeler
Algorithm should be hidden from the modeler.
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.
QgsProcessingAlgorithm::Flags flags() const override
Returns the flags indicating how and when the algorithm operates and should be exposed to users.
Abstract base class for processing providers.
virtual QIcon icon() const
Returns an icon for the provider.
virtual QString name() const =0
Returns the provider name, which is used to describe the provider within the GUI.
@ FlagDeemphasiseSearchResults
Algorithms should be de-emphasised in the search results when searching for algorithms....
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...
virtual Flags flags() const
Returns the flags indicating how and when the provider operates and should be exposed to users.
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 providerAdded(const QString &id)
Emitted when a provider has been added to the registry.
void providerRemoved(const QString &id)
Emitted when a provider is removed from the registry.
A model for providers and algorithms shown within the Processing toolbox.
int columnCount(const QModelIndex &=QModelIndex()) const override
QgsProcessingToolboxModel(QObject *parent=nullptr, QgsProcessingRegistry *registry=nullptr, QgsProcessingRecentAlgorithmLog *recentLog=nullptr)
Constructor for QgsProcessingToolboxModel, with the given parent object.
QModelIndex indexForProvider(const QString &providerId) const
Returns the index corresponding to the specified providerId.
QModelIndex node2index(QgsProcessingToolboxModelNode *node) const
Returns the model index corresponding to the given node.
QModelIndex indexOfParentTreeNode(QgsProcessingToolboxModelNode *parentNode) const
Returns the index corresponding to the parent of a given node.
Qt::ItemFlags flags(const QModelIndex &index) const override
QString providerIdForIndex(const QModelIndex &index) const
Returns the provider ID which corresponds to a given index, or an empty string if the index does not ...
QgsProcessingToolboxModelNode * index2node(const QModelIndex &index) const
Returns the model node corresponding to the given index.
bool isAlgorithm(const QModelIndex &index) const
Returns true if index corresponds to an algorithm.
void recentAlgorithmAdded()
Emitted whenever recent algorithms are added to the model.
QgsProcessingProvider * providerForIndex(const QModelIndex &index) const
Returns the provider which corresponds to a given index, or nullptr if the index does not represent a...
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QModelIndex parent(const QModelIndex &index) const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
const QgsProcessingAlgorithm * algorithmForIndex(const QModelIndex &index) const
Returns the algorithm which corresponds to a given index, or nullptr if the index does not represent ...
QMimeData * mimeData(const QModelIndexList &indexes) const override
@ RoleProviderFlags
Returns the node's provider flags.
@ RoleAlgorithmShortDescription
Short algorithm description, for algorithm nodes.
@ RoleAlgorithmTags
List of algorithm tags, for algorithm nodes.
@ RoleAlgorithmId
Algorithm ID, for algorithm nodes.
@ RoleAlgorithmFlags
Returns the node's algorithm flags, for algorithm nodes.
@ RoleNodeType
Corresponds to the node's type.
@ RoleAlgorithmName
Untranslated algorithm name, for algorithm nodes.
Filters filters() const
Returns any filters that affect how toolbox content is filtered.
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
void setFilters(QgsProcessingToolboxProxyModel::Filters filters)
Set filters that affect how toolbox content is filtered.
void setFilterString(const QString &filter)
Sets a filter string, such that only algorithms matching the specified string will be shown.
@ FilterToolbox
Filters out any algorithms and content which should not be shown in the toolbox.
@ FilterShowKnownIssues
Show algorithms with known issues (hidden by default)
@ FilterModeler
Filters out any algorithms and content which should not be shown in the modeler.
@ FilterInPlace
Only show algorithms which support in-place edits.
void setInPlaceLayer(QgsVectorLayer *layer)
Sets the vector layer for in-place algorithm filter.
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
QgsProcessingToolboxModel * toolboxModel()
Returns the underlying source Processing toolbox model.
QgsProcessingToolboxProxyModel(QObject *parent=nullptr, QgsProcessingRegistry *registry=nullptr, QgsProcessingRecentAlgorithmLog *recentLog=nullptr)
Constructor for QgsProcessingToolboxProxyModel, with the given parent object.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Represents a vector layer which manages a vector based data sets.
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