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