QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 
513  return QVariant();
514 }
515 
516 int QgsProcessingToolboxModel::rowCount( const QModelIndex &parent ) const
517 {
518  QgsProcessingToolboxModelNode *n = index2node( parent );
519  if ( !n )
520  return 0;
521 
522  return n->children().count();
523 }
524 
525 int QgsProcessingToolboxModel::columnCount( const QModelIndex & ) const
526 {
527  return 1;
528 }
529 
530 QModelIndex QgsProcessingToolboxModel::index( int row, int column, const QModelIndex &parent ) const
531 {
532  if ( !hasIndex( row, column, parent ) )
533  return QModelIndex();
534 
535  QgsProcessingToolboxModelNode *n = index2node( parent );
536  if ( !n )
537  return QModelIndex(); // have no children
538 
539  return createIndex( row, column, static_cast<QObject *>( n->children().at( row ) ) );
540 }
541 
542 QModelIndex QgsProcessingToolboxModel::parent( const QModelIndex &child ) const
543 {
544  if ( !child.isValid() )
545  return QModelIndex();
546 
547  if ( QgsProcessingToolboxModelNode *n = index2node( child ) )
548  {
549  return indexOfParentTreeNode( n->parent() ); // must not be null
550  }
551  else
552  {
553  Q_ASSERT( false ); // no other node types!
554  return QModelIndex();
555  }
556 }
557 
558 QMimeData *QgsProcessingToolboxModel::mimeData( const QModelIndexList &indexes ) const
559 {
560  if ( !indexes.isEmpty() && isAlgorithm( indexes.at( 0 ) ) )
561  {
562  QByteArray encodedData;
563  QDataStream stream( &encodedData, QIODevice::WriteOnly | QIODevice::Truncate );
564 
565  std::unique_ptr< QMimeData > mimeData = qgis::make_unique< QMimeData >();
566  const QgsProcessingAlgorithm *algorithm = algorithmForIndex( indexes.at( 0 ) );
567  if ( algorithm )
568  {
569  stream << algorithm->id();
570  }
571  mimeData->setData( QStringLiteral( "application/x-vnd.qgis.qgis.algorithmid" ), encodedData );
572  return mimeData.release();
573  }
574  return nullptr;
575 }
576 
578 {
579  QgsProcessingToolboxModelNode *n = index2node( index );
580  if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeProvider )
581  return nullptr;
582 
583  return qobject_cast< QgsProcessingToolboxModelProviderNode * >( n )->provider();
584 }
585 
586 QString QgsProcessingToolboxModel::providerIdForIndex( const QModelIndex &index ) const
587 {
588  QgsProcessingToolboxModelNode *n = index2node( index );
589  if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeProvider )
590  return nullptr;
591 
592  return qobject_cast< QgsProcessingToolboxModelProviderNode * >( n )->providerId();
593 }
594 
596 {
597  QgsProcessingToolboxModelNode *n = index2node( index );
598  if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeAlgorithm )
599  return nullptr;
600 
601  return qobject_cast< QgsProcessingToolboxModelAlgorithmNode * >( n )->algorithm();
602 }
603 
604 bool QgsProcessingToolboxModel::isAlgorithm( const QModelIndex &index ) const
605 {
606  QgsProcessingToolboxModelNode *n = index2node( index );
607  return ( n && n->nodeType() == QgsProcessingToolboxModelNode::NodeAlgorithm );
608 }
609 
610 QModelIndex QgsProcessingToolboxModel::indexForProvider( const QString &providerId ) const
611 {
612  std::function< QModelIndex( const QModelIndex &parent, const QString &providerId ) > findIndex = [&]( const QModelIndex & parent, const QString & providerId )->QModelIndex
613  {
614  for ( int row = 0; row < rowCount( parent ); ++row )
615  {
616  QModelIndex current = index( row, 0, parent );
617  const QString currentProviderId = providerIdForIndex( current );
618  if ( !currentProviderId.isEmpty() && currentProviderId == providerId )
619  return current;
620 
621  QModelIndex checkChildren = findIndex( current, providerId );
622  if ( checkChildren.isValid() )
623  return checkChildren;
624  }
625  return QModelIndex();
626  };
627 
628  return findIndex( QModelIndex(), providerId );
629 }
630 
631 QModelIndex QgsProcessingToolboxModel::indexOfParentTreeNode( QgsProcessingToolboxModelNode *parentNode ) const
632 {
633  Q_ASSERT( parentNode );
634 
635  QgsProcessingToolboxModelNode *grandParentNode = parentNode->parent();
636  if ( !grandParentNode )
637  return QModelIndex(); // root node -> invalid index
638 
639  int row = grandParentNode->children().indexOf( parentNode );
640  Q_ASSERT( row >= 0 );
641 
642  return createIndex( row, 0, static_cast<QObject *>( parentNode ) );
643 }
644 
645 //
646 // QgsProcessingToolboxProxyModel
647 //
648 
650  QgsProcessingRecentAlgorithmLog *recentLog )
651  : QSortFilterProxyModel( parent )
652  , mModel( new QgsProcessingToolboxModel( this, registry, recentLog ) )
653 {
654  setSourceModel( mModel );
655  setDynamicSortFilter( true );
656  setSortLocaleAware( true );
657  setFilterCaseSensitivity( Qt::CaseInsensitive );
658  sort( 0 );
659 
660  connect( mModel, &QgsProcessingToolboxModel::recentAlgorithmAdded, this, [ = ] { invalidateFilter(); } );
661 }
662 
664 {
665  return mModel;
666 }
667 
668 void QgsProcessingToolboxProxyModel::setFilters( QgsProcessingToolboxProxyModel::Filters filters )
669 {
670  mFilters = filters;
671  invalidateFilter();
672 }
673 
675 {
676  mInPlaceLayer = layer;
677  invalidateFilter();
678 }
679 
680 
682 {
683  mFilterString = filter;
684  invalidateFilter();
685 }
686 
687 bool QgsProcessingToolboxProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
688 {
689  QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
690  if ( mModel->isAlgorithm( sourceIndex ) )
691  {
692  const bool hasKnownIssues = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmFlags ).toInt() & QgsProcessingAlgorithm::FlagKnownIssues;
693  if ( hasKnownIssues && !( mFilters & FilterShowKnownIssues ) )
694  return false;
695 
696  if ( !mFilterString.trimmed().isEmpty() )
697  {
698  const QString algId = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmId ).toString();
699  const QString algName = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmName ).toString();
700  const QStringList algTags = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmTags ).toStringList();
701  const QString shortDesc = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmShortDescription ).toString();
702 
703  QStringList parentText;
704  QModelIndex parent = sourceIndex.parent();
705  while ( parent.isValid() )
706  {
707  const QStringList parentParts = sourceModel()->data( parent, Qt::DisplayRole ).toString().split( ' ' );
708  if ( !parentParts.empty() )
709  parentText.append( parentParts );
710  parent = parent.parent();
711  }
712 
713  const QStringList partsToMatch = mFilterString.trimmed().split( ' ' );
714 
715  QStringList partsToSearch = sourceModel()->data( sourceIndex, Qt::DisplayRole ).toString().split( ' ' );
716  partsToSearch << algId << algName;
717  partsToSearch.append( algTags );
718  if ( !shortDesc.isEmpty() )
719  partsToSearch.append( shortDesc.split( ' ' ) );
720  partsToSearch.append( parentText );
721 
722  for ( const QString &part : partsToMatch )
723  {
724  bool found = false;
725  for ( const QString &partToSearch : qgis::as_const( partsToSearch ) )
726  {
727  if ( partToSearch.contains( part, Qt::CaseInsensitive ) )
728  {
729  found = true;
730  break;
731  }
732  }
733  if ( !found )
734  return false; // couldn't find a match for this word, so hide algorithm
735  }
736  }
737 
738  if ( mFilters & FilterInPlace )
739  {
740  const bool supportsInPlace = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmFlags ).toInt() & QgsProcessingAlgorithm::FlagSupportsInPlaceEdits;
741  if ( !supportsInPlace )
742  return false;
743 
744  const QgsProcessingAlgorithm *alg = mModel->algorithmForIndex( sourceIndex );
745  if ( !( mInPlaceLayer && alg && alg->supportInPlaceEdit( mInPlaceLayer ) ) )
746  {
747  return false;
748  }
749  }
750  if ( mFilters & FilterModeler )
751  {
752  bool isHiddenFromModeler = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmFlags ).toInt() & QgsProcessingAlgorithm::FlagHideFromModeler;
753  return !isHiddenFromModeler;
754  }
755  if ( mFilters & FilterToolbox )
756  {
757  bool isHiddenFromToolbox = sourceModel()->data( sourceIndex, QgsProcessingToolboxModel::RoleAlgorithmFlags ).toInt() & QgsProcessingAlgorithm::FlagHideFromToolbox;
758  return !isHiddenFromToolbox;
759  }
760  return true;
761  }
762 
763  bool hasChildren = false;
764  // groups/providers are shown only if they have visible children
765  int count = sourceModel()->rowCount( sourceIndex );
766  for ( int i = 0; i < count; ++i )
767  {
768  if ( filterAcceptsRow( i, sourceIndex ) )
769  {
770  hasChildren = true;
771  break;
772  }
773  }
774 
775  return hasChildren;
776 }
777 
778 bool QgsProcessingToolboxProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
779 {
780  QgsProcessingToolboxModelNode::NodeType leftType = static_cast< QgsProcessingToolboxModelNode::NodeType >( sourceModel()->data( left, QgsProcessingToolboxModel::RoleNodeType ).toInt() );
781  QgsProcessingToolboxModelNode::NodeType rightType = static_cast< QgsProcessingToolboxModelNode::NodeType >( sourceModel()->data( right, QgsProcessingToolboxModel::RoleNodeType ).toInt() );
782 
783  if ( leftType == QgsProcessingToolboxModelNode::NodeRecent )
784  return true;
785  else if ( rightType == QgsProcessingToolboxModelNode::NodeRecent )
786  return false;
787  else if ( leftType != rightType )
788  {
789  if ( leftType == QgsProcessingToolboxModelNode::NodeProvider )
790  return false;
791  else if ( rightType == QgsProcessingToolboxModelNode::NodeProvider )
792  return true;
793  else if ( leftType == QgsProcessingToolboxModelNode::NodeGroup )
794  return false;
795  else
796  return true;
797  }
798 
799  // if node represents a recent algorithm, it's not sorted at all
800  bool isRecentNode = false;
801  QModelIndex parent = left.parent();
802  while ( parent.isValid() )
803  {
804  if ( mModel->data( parent, QgsProcessingToolboxModel::RoleNodeType ).toInt() == QgsProcessingToolboxModelNode::NodeRecent )
805  {
806  isRecentNode = true;
807  break;
808  }
809  parent = parent.parent();
810  }
811  if ( isRecentNode )
812  {
813  return left.row() < right.row();
814  }
815 
816 
817  // default mode is alphabetical order
818  QString leftStr = sourceModel()->data( left ).toString();
819  QString rightStr = sourceModel()->data( right ).toString();
820  return QString::localeAwareCompare( leftStr, rightStr ) < 0;
821 }
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.