QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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}
318
319QString QgsProcessingToolboxModel::toolTipForAlgorithm( const QgsProcessingAlgorithm *algorithm )
320{
321 return QStringLiteral( "<p><b>%1</b></p>%2<p>%3</p>%4" ).arg(
323 !algorithm->shortDescription().isEmpty() ? QStringLiteral( "<p>%1</p>" ).arg( algorithm->shortDescription() ) : QString(),
324 QObject::tr( "Algorithm ID: ‘%1’" ).arg( QStringLiteral( "<i>%1</i>" ).arg( algorithm->id() ) ),
325 ( algorithm->flags() & QgsProcessingAlgorithm::FlagKnownIssues ) ? QStringLiteral( "<b style=\"color:red\">%1</b>" ).arg( QObject::tr( "Warning: Algorithm has known issues" ) ) : QString()
326 );
327}
328
329Qt::ItemFlags QgsProcessingToolboxModel::flags( const QModelIndex &index ) const
330{
331 if ( !index.isValid() )
332 return Qt::ItemFlags();
333
334 return QAbstractItemModel::flags( index );
335}
336
337QVariant QgsProcessingToolboxModel::data( const QModelIndex &index, int role ) const
338{
339 if ( !index.isValid() )
340 return QVariant();
341
342 if ( role == RoleNodeType )
343 {
344 if ( QgsProcessingToolboxModelNode *node = index2node( index ) )
345 return node->nodeType();
346 else
347 return QVariant();
348 }
349
350 bool isRecentNode = false;
351 if ( QgsProcessingToolboxModelNode *node = index2node( index ) )
352 isRecentNode = node->nodeType() == QgsProcessingToolboxModelNode::NodeRecent;
353
355 QgsProcessingToolboxModelGroupNode *groupNode = qobject_cast< QgsProcessingToolboxModelGroupNode * >( index2node( index ) );
357
358 switch ( role )
359 {
360 case Qt::DisplayRole:
361 {
362 switch ( index.column() )
363 {
364 case 0:
365 if ( provider )
366 return provider->name();
367 else if ( algorithm )
368 return algorithm->displayName();
369 else if ( groupNode )
370 return groupNode->name();
371 else if ( isRecentNode )
372 return tr( "Recently used" );
373 else
374 return QVariant();
375
376 default:
377 return QVariant();
378 }
379 break;
380 }
381
382 case Qt::ToolTipRole:
383 {
384 if ( provider )
385 return provider->longName();
386 else if ( algorithm )
387 return toolTipForAlgorithm( algorithm );
388 else if ( groupNode )
389 return groupNode->name();
390 else
391 return QVariant();
392 }
393
394 case Qt::ForegroundRole:
395 {
397 return QBrush( QColor( Qt::red ) );
398 else
399 return QVariant();
400 }
401
402 case Qt::DecorationRole:
403 {
404 switch ( index.column() )
405 {
406 case 0:
407 {
408 if ( provider )
409 return provider->icon();
410 else if ( algorithm )
411 {
413 return QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
414 return algorithm->icon();
415 }
416 else if ( isRecentNode )
417 return QgsApplication::getThemeIcon( QStringLiteral( "/mIconHistory.svg" ) );
418 else if ( !index.parent().isValid() )
419 // top level groups get the QGIS icon
420 return QgsApplication::getThemeIcon( QStringLiteral( "/providerQgis.svg" ) );
421 else
422 return QVariant();
423 }
424
425 default:
426 return QVariant();
427 }
428 break;
429 }
430
432 switch ( index.column() )
433 {
434 case 0:
435 {
436 if ( algorithm )
437 return static_cast< int >( algorithm->flags() );
438 else
439 return QVariant();
440 }
441
442 default:
443 return QVariant();
444 }
445 break;
446
448 switch ( index.column() )
449 {
450 case 0:
451 {
452 if ( provider )
453 return static_cast< int >( provider->flags() );
454 else if ( algorithm && algorithm->provider() )
455 return static_cast< int >( algorithm->provider()->flags() );
456 else if ( index.parent().data( RoleProviderFlags ).isValid() ) // group node
457 return static_cast< int >( index.parent().data( RoleProviderFlags ).toInt() );
458 else
459 return QVariant();
460 }
461
462 default:
463 return QVariant();
464 }
465 break;
466
467 case RoleAlgorithmId:
468 switch ( index.column() )
469 {
470 case 0:
471 {
472 if ( algorithm )
473 return algorithm->id();
474 else
475 return QVariant();
476 }
477
478 default:
479 return QVariant();
480 }
481 break;
482
484 switch ( index.column() )
485 {
486 case 0:
487 {
488 if ( algorithm )
489 return algorithm->name();
490 else
491 return QVariant();
492 }
493
494 default:
495 return QVariant();
496 }
497 break;
498
500 switch ( index.column() )
501 {
502 case 0:
503 {
504 if ( algorithm )
505 return algorithm->tags();
506 else
507 return QVariant();
508 }
509
510 default:
511 return QVariant();
512 }
513 break;
514
516 switch ( index.column() )
517 {
518 case 0:
519 {
520 if ( algorithm )
521 return algorithm->shortDescription();
522 else
523 return QVariant();
524 }
525
526 default:
527 return QVariant();
528 }
529 break;
530
531 default:
532 return QVariant();
533 }
534#ifndef _MSC_VER // avoid warning
535 return QVariant();
536#endif
537}
538
539int QgsProcessingToolboxModel::rowCount( const QModelIndex &parent ) const
540{
541 QgsProcessingToolboxModelNode *n = index2node( parent );
542 if ( !n )
543 return 0;
544
545 return n->children().count();
546}
547
548int QgsProcessingToolboxModel::columnCount( const QModelIndex & ) const
549{
550 return 1;
551}
552
553QModelIndex QgsProcessingToolboxModel::index( int row, int column, const QModelIndex &parent ) const
554{
555 if ( !hasIndex( row, column, parent ) )
556 return QModelIndex();
557
558 QgsProcessingToolboxModelNode *n = index2node( parent );
559 if ( !n )
560 return QModelIndex(); // have no children
561
562 return createIndex( row, column, static_cast<QObject *>( n->children().at( row ) ) );
563}
564
565QModelIndex QgsProcessingToolboxModel::parent( const QModelIndex &child ) const
566{
567 if ( !child.isValid() )
568 return QModelIndex();
569
570 if ( QgsProcessingToolboxModelNode *n = index2node( child ) )
571 {
572 return indexOfParentTreeNode( n->parent() ); // must not be null
573 }
574 else
575 {
576 Q_ASSERT( false ); // no other node types!
577 return QModelIndex();
578 }
579}
580
581QMimeData *QgsProcessingToolboxModel::mimeData( const QModelIndexList &indexes ) const
582{
583 if ( !indexes.isEmpty() && isAlgorithm( indexes.at( 0 ) ) )
584 {
585 QByteArray encodedData;
586 QDataStream stream( &encodedData, QIODevice::WriteOnly | QIODevice::Truncate );
587
588 std::unique_ptr< QMimeData > mimeData = std::make_unique< QMimeData >();
589 const QgsProcessingAlgorithm *algorithm = algorithmForIndex( indexes.at( 0 ) );
590 if ( algorithm )
591 {
592 stream << algorithm->id();
593 }
594 mimeData->setData( QStringLiteral( "application/x-vnd.qgis.qgis.algorithmid" ), encodedData );
595 return mimeData.release();
596 }
597 return nullptr;
598}
599
601{
602 QgsProcessingToolboxModelNode *n = index2node( index );
603 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeProvider )
604 return nullptr;
605
606 return qobject_cast< QgsProcessingToolboxModelProviderNode * >( n )->provider();
607}
608
609QString QgsProcessingToolboxModel::providerIdForIndex( const QModelIndex &index ) const
610{
611 QgsProcessingToolboxModelNode *n = index2node( index );
612 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeProvider )
613 return nullptr;
614
615 return qobject_cast< QgsProcessingToolboxModelProviderNode * >( n )->providerId();
616}
617
619{
620 QgsProcessingToolboxModelNode *n = index2node( index );
621 if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeAlgorithm )
622 return nullptr;
623
624 return qobject_cast< QgsProcessingToolboxModelAlgorithmNode * >( n )->algorithm();
625}
626
627bool QgsProcessingToolboxModel::isAlgorithm( const QModelIndex &index ) const
628{
629 QgsProcessingToolboxModelNode *n = index2node( index );
630 return ( n && n->nodeType() == QgsProcessingToolboxModelNode::NodeAlgorithm );
631}
632
633QModelIndex QgsProcessingToolboxModel::indexForProvider( const QString &providerId ) const
634{
635 std::function< QModelIndex( const QModelIndex &parent, const QString &providerId ) > findIndex = [&]( const QModelIndex & parent, const QString & providerId )->QModelIndex
636 {
637 for ( int row = 0; row < rowCount( parent ); ++row )
638 {
639 QModelIndex current = index( row, 0, parent );
640 const QString currentProviderId = providerIdForIndex( current );
641 if ( !currentProviderId.isEmpty() && currentProviderId == providerId )
642 return current;
643
644 QModelIndex checkChildren = findIndex( current, providerId );
645 if ( checkChildren.isValid() )
646 return checkChildren;
647 }
648 return QModelIndex();
649 };
650
651 return findIndex( QModelIndex(), providerId );
652}
653
654QModelIndex QgsProcessingToolboxModel::indexOfParentTreeNode( QgsProcessingToolboxModelNode *parentNode ) const
655{
656 Q_ASSERT( parentNode );
657
658 QgsProcessingToolboxModelNode *grandParentNode = parentNode->parent();
659 if ( !grandParentNode )
660 return QModelIndex(); // root node -> invalid index
661
662 int row = grandParentNode->children().indexOf( parentNode );
663 Q_ASSERT( row >= 0 );
664
665 return createIndex( row, 0, static_cast<QObject *>( parentNode ) );
666}
667
668//
669// QgsProcessingToolboxProxyModel
670//
671
673 QgsProcessingRecentAlgorithmLog *recentLog )
674 : QSortFilterProxyModel( parent )
675 , mModel( new QgsProcessingToolboxModel( this, registry, recentLog ) )
676{
677 setSourceModel( mModel );
678 setDynamicSortFilter( true );
679 setSortLocaleAware( true );
680 setFilterCaseSensitivity( Qt::CaseInsensitive );
681 sort( 0 );
682
683 connect( mModel, &QgsProcessingToolboxModel::recentAlgorithmAdded, this, [ = ] { invalidateFilter(); } );
684}
685
687{
688 return mModel;
689}
690
692{
693 return mModel;
694}
695
696void QgsProcessingToolboxProxyModel::setFilters( QgsProcessingToolboxProxyModel::Filters filters )
697{
698 mFilters = filters;
699 invalidateFilter();
700}
701
703{
704 mInPlaceLayer = layer;
705 invalidateFilter();
706}
707
708
710{
711 mFilterString = filter;
712 invalidateFilter();
713}
714
715bool QgsProcessingToolboxProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
716{
717 QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
718 if ( mModel->isAlgorithm( sourceIndex ) )
719 {
720 const bool hasKnownIssues = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmFlags ).toInt() & QgsProcessingAlgorithm::FlagKnownIssues;
721 if ( hasKnownIssues && !( mFilters & FilterShowKnownIssues ) )
722 return false;
723
724 if ( !mFilterString.trimmed().isEmpty() )
725 {
726 const QString algId = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmId ).toString();
727 const QString algName = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmName ).toString();
728 const QStringList algTags = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmTags ).toStringList();
729 const QString shortDesc = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmShortDescription ).toString();
730
731 QStringList parentText;
732 QModelIndex parent = sourceIndex.parent();
733 while ( parent.isValid() )
734 {
735 const QStringList parentParts = sourceModel()->data( parent, Qt::DisplayRole ).toString().split( ' ' );
736 if ( !parentParts.empty() )
737 parentText.append( parentParts );
738 parent = parent.parent();
739 }
740
741 const QStringList partsToMatch = mFilterString.trimmed().split( ' ' );
742
743 QStringList partsToSearch = sourceModel()->data( sourceIndex, Qt::DisplayRole ).toString().split( ' ' );
744 partsToSearch << algId << algName;
745 partsToSearch.append( algTags );
746 if ( !shortDesc.isEmpty() )
747 partsToSearch.append( shortDesc.split( ' ' ) );
748 partsToSearch.append( parentText );
749
750 for ( const QString &part : partsToMatch )
751 {
752 bool found = false;
753 for ( const QString &partToSearch : std::as_const( partsToSearch ) )
754 {
755 if ( partToSearch.contains( part, Qt::CaseInsensitive ) )
756 {
757 found = true;
758 break;
759 }
760 }
761 if ( !found )
762 return false; // couldn't find a match for this word, so hide algorithm
763 }
764 }
765
766 if ( mFilters & FilterInPlace )
767 {
768 const bool supportsInPlace = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmFlags ).toInt() & QgsProcessingAlgorithm::FlagSupportsInPlaceEdits;
769 if ( !supportsInPlace )
770 return false;
771
772 const QgsProcessingAlgorithm *alg = mModel->algorithmForIndex( sourceIndex );
773 if ( !( mInPlaceLayer && alg && alg->supportInPlaceEdit( mInPlaceLayer ) ) )
774 {
775 return false;
776 }
777 }
778 if ( mFilters & FilterModeler )
779 {
780 bool isHiddenFromModeler = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmFlags ).toInt() & QgsProcessingAlgorithm::FlagHideFromModeler;
781 return !isHiddenFromModeler;
782 }
783 if ( mFilters & FilterToolbox )
784 {
785 bool isHiddenFromToolbox = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmFlags ).toInt() & QgsProcessingAlgorithm::FlagHideFromToolbox;
786 return !isHiddenFromToolbox;
787 }
788 return true;
789 }
790
791 bool hasChildren = false;
792 // groups/providers are shown only if they have visible children
793 int count = sourceModel()->rowCount( sourceIndex );
794 for ( int i = 0; i < count; ++i )
795 {
796 if ( filterAcceptsRow( i, sourceIndex ) )
797 {
798 hasChildren = true;
799 break;
800 }
801 }
802
803 return hasChildren;
804}
805
806bool QgsProcessingToolboxProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
807{
808 QgsProcessingToolboxModelNode::NodeType leftType = static_cast< QgsProcessingToolboxModelNode::NodeType >( sourceModel()->data( left, QgsProcessingToolboxModel::RoleNodeType ).toInt() );
809 QgsProcessingToolboxModelNode::NodeType rightType = static_cast< QgsProcessingToolboxModelNode::NodeType >( sourceModel()->data( right, QgsProcessingToolboxModel::RoleNodeType ).toInt() );
810
811 if ( leftType == QgsProcessingToolboxModelNode::NodeRecent )
812 return true;
813 else if ( rightType == QgsProcessingToolboxModelNode::NodeRecent )
814 return false;
815 else if ( leftType != rightType )
816 {
817 if ( leftType == QgsProcessingToolboxModelNode::NodeProvider )
818 return false;
819 else if ( rightType == QgsProcessingToolboxModelNode::NodeProvider )
820 return true;
821 else if ( leftType == QgsProcessingToolboxModelNode::NodeGroup )
822 return false;
823 else
824 return true;
825 }
826
827 // if node represents a recent algorithm, it's not sorted at all
828 bool isRecentNode = false;
829 QModelIndex parent = left.parent();
830 while ( parent.isValid() )
831 {
832 if ( mModel->data( parent, QgsProcessingToolboxModel::RoleNodeType ).toInt() == QgsProcessingToolboxModelNode::NodeRecent )
833 {
834 isRecentNode = true;
835 break;
836 }
837 parent = parent.parent();
838 }
839 if ( isRecentNode )
840 {
841 return left.row() < right.row();
842 }
843
844
845 // default mode is alphabetical order
846 QString leftStr = sourceModel()->data( left ).toString();
847 QString rightStr = sourceModel()->data( right ).toString();
848 return QString::localeAwareCompare( leftStr, rightStr ) < 0;
849}
850
851QVariant QgsProcessingToolboxProxyModel::data( const QModelIndex &index, int role ) const
852{
853 if ( role == Qt::ForegroundRole && !mFilterString.isEmpty() )
854 {
855 QModelIndex sourceIndex = mapToSource( index );
856 const QVariant flags = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleProviderFlags );
857 if ( flags.isValid() && flags.toInt() & QgsProcessingProvider::FlagDeemphasiseSearchResults )
858 {
859 QBrush brush( qApp->palette().color( QPalette::Text ), Qt::SolidPattern );
860 QColor fadedTextColor = brush.color();
861 fadedTextColor.setAlpha( 100 );
862 brush.setColor( fadedTextColor );
863 return brush;
864 }
865 }
866 return QSortFilterProxyModel::data( index, role );
867}
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