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