Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Better responsive to provider removal
  • Loading branch information
nyalldawson committed Jul 16, 2018
1 parent dab4f42 commit dc737bf
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 42 deletions.
Expand Up @@ -67,6 +67,12 @@ Returns a list of children belonging to the node.
%End


QgsProcessingToolboxModelNode *takeChild( QgsProcessingToolboxModelNode *node );
%Docstring
Removes the specified ``node`` from this node's children, and gives
ownership back to the caller.
%End

QgsProcessingToolboxModelGroupNode *getChildGroupNode( const QString &id );
%Docstring
Tries to find a child node belonging to this node, which corresponds to
Expand Down Expand Up @@ -115,6 +121,11 @@ specified ``provider``.
QgsProcessingProvider *provider();
%Docstring
Returns the provider associated with this node.
%End

QString providerId() const;
%Docstring
Returns the provider ID.
%End

};
Expand Down Expand Up @@ -258,6 +269,16 @@ a None if the index does not represent a provider.

.. seealso:: :py:func:`algorithmForIndex`

.. seealso:: :py:func:`indexForProvider`
%End

QString providerIdForIndex( const QModelIndex &index ) const;
%Docstring
Returns the provider ID which corresponds to a given ``index``, or
an empty string if the index does not represent a provider.

.. seealso:: :py:func:`algorithmForIndex`

.. seealso:: :py:func:`indexForProvider`
%End

Expand All @@ -278,9 +299,9 @@ Returns true if ``index`` corresponds to an algorithm.
.. seealso:: :py:func:`algorithmForIndex`
%End

QModelIndex indexForProvider( QgsProcessingProvider *provider ) const;
QModelIndex indexForProvider( const QString &providerId ) const;
%Docstring
Returns the index corresponding to the specified ``provider``.
Returns the index corresponding to the specified ``providerId``.

.. seealso:: :py:func:`providerForIndex`
%End
Expand Down
25 changes: 23 additions & 2 deletions python/gui/processing/qgsprocessingtoolboxmodel.sip.in
Expand Up @@ -67,6 +67,12 @@ Returns a list of children belonging to the node.
%End


QgsProcessingToolboxModelNode* takeChild( QgsProcessingToolboxModelNode* node );
%Docstring
Removes the specified ``node`` from this node's children, and gives
ownership back to the caller.
%End

QgsProcessingToolboxModelGroupNode *getChildGroupNode( const QString &id );
%Docstring
Tries to find a child node belonging to this node, which corresponds to
Expand Down Expand Up @@ -115,6 +121,11 @@ specified ``provider``.
QgsProcessingProvider *provider();
%Docstring
Returns the provider associated with this node.
%End

QString providerId() const;
%Docstring
Returns the provider ID.
%End

};
Expand Down Expand Up @@ -258,6 +269,16 @@ a None if the index does not represent a provider.

.. seealso:: :py:func:`algorithmForIndex`

.. seealso:: :py:func:`indexForProvider`
%End

QString providerIdForIndex( const QModelIndex &index ) const;
%Docstring
Returns the provider ID which corresponds to a given ``index``, or
an empty string if the index does not represent a provider.

.. seealso:: :py:func:`algorithmForIndex`

.. seealso:: :py:func:`indexForProvider`
%End

Expand All @@ -278,9 +299,9 @@ Returns true if ``index`` corresponds to an algorithm.
.. seealso:: :py:func:`algorithmForIndex`
%End

QModelIndex indexForProvider( QgsProcessingProvider *provider ) const;
QModelIndex indexForProvider(const QString &providerId ) const;
%Docstring
Returns the index corresponding to the specified ``provider``.
Returns the index corresponding to the specified ``providerId``.

.. seealso:: :py:func:`providerForIndex`
%End
Expand Down
83 changes: 65 additions & 18 deletions src/gui/processing/qgsprocessingtoolboxmodel.cpp
Expand Up @@ -31,6 +31,11 @@ QgsProcessingToolboxModelNode::~QgsProcessingToolboxModelNode()
deleteChildren();
}

QgsProcessingToolboxModelNode *QgsProcessingToolboxModelNode::takeChild( QgsProcessingToolboxModelNode *node )
{
return mChildren.takeAt( mChildren.indexOf( node ) );
}

QgsProcessingToolboxModelGroupNode *QgsProcessingToolboxModelNode::getChildGroupNode( const QString &groupId )
{
for ( QgsProcessingToolboxModelNode *node : qgis::as_const( mChildren ) )
Expand Down Expand Up @@ -67,7 +72,8 @@ void QgsProcessingToolboxModelNode::deleteChildren()
//

QgsProcessingToolboxModelProviderNode::QgsProcessingToolboxModelProviderNode( QgsProcessingProvider *provider )
: mProvider( provider )
: mProviderId( provider->id() )
, mProvider( provider )
{}

QgsProcessingProvider *QgsProcessingToolboxModelProviderNode::provider()
Expand Down Expand Up @@ -109,7 +115,7 @@ QgsProcessingToolboxModel::QgsProcessingToolboxModel( QObject *parent, QgsProces
rebuild();

connect( mRegistry, &QgsProcessingRegistry::providerAdded, this, &QgsProcessingToolboxModel::providerAdded );
connect( mRegistry, &QgsProcessingRegistry::providerRemoved, this, &QgsProcessingToolboxModel::rebuild );
connect( mRegistry, &QgsProcessingRegistry::providerRemoved, this, &QgsProcessingToolboxModel::providerRemoved );
}

void QgsProcessingToolboxModel::rebuild()
Expand All @@ -132,9 +138,44 @@ void QgsProcessingToolboxModel::providerAdded( const QString &id )
if ( !provider )
return;

beginResetModel();
addProvider( provider );
endResetModel();
if ( !isTopLevelProvider( id ) )
{
int previousRowCount = rowCount();
beginInsertRows( QModelIndex(), previousRowCount + 1, previousRowCount + 1 );
addProvider( provider );
endInsertRows();
}
else
{
//native providers use top level groups - that's too hard for us to
//work out exactly what's going to change, so just reset the model
beginResetModel();
addProvider( provider );
endResetModel();
}
}

void QgsProcessingToolboxModel::providerRemoved( const QString &id )
{
if ( isTopLevelProvider( id ) )
{
// native providers use top level groups - so we can't
// work out what to remove. Just rebuild the whole model instead.
rebuild();
}
else
{
// can't retrieve the provider - it's been deleted!
// so find node by id
QModelIndex index = indexForProvider( id );
QgsProcessingToolboxModelNode *node = index2node( index );
if ( !node )
return;

beginRemoveRows( QModelIndex(), index.row(), index.row() );
delete mRootNode->takeChild( node );
endRemoveRows();
}
}

QgsProcessingToolboxModelNode *QgsProcessingToolboxModel::index2node( const QModelIndex &index ) const
Expand Down Expand Up @@ -163,7 +204,7 @@ void QgsProcessingToolboxModel::addProvider( QgsProcessingProvider *provider )
connect( provider, &QgsProcessingProvider::algorithmsLoaded, this, &QgsProcessingToolboxModel::rebuild, Qt::UniqueConnection );

QgsProcessingToolboxModelNode *parentNode = nullptr;
if ( !isTopLevelProvider( provider ) )
if ( !isTopLevelProvider( provider->id() ) )
{
std::unique_ptr< QgsProcessingToolboxModelProviderNode > node = qgis::make_unique< QgsProcessingToolboxModelProviderNode >( provider );
parentNode = node.get();
Expand Down Expand Up @@ -198,11 +239,11 @@ void QgsProcessingToolboxModel::addProvider( QgsProcessingProvider *provider )
}
}

bool QgsProcessingToolboxModel::isTopLevelProvider( QgsProcessingProvider *provider )
bool QgsProcessingToolboxModel::isTopLevelProvider( const QString &providerId )
{
return provider->id() == QLatin1String( "qgis" ) ||
provider->id() == QLatin1String( "native" ) ||
provider->id() == QLatin1String( "3d" );
return providerId == QLatin1String( "qgis" ) ||
providerId == QLatin1String( "native" ) ||
providerId == QLatin1String( "3d" );
}

QString QgsProcessingToolboxModel::toolTipForAlgorithm( const QgsProcessingAlgorithm *algorithm )
Expand Down Expand Up @@ -368,6 +409,15 @@ QgsProcessingProvider *QgsProcessingToolboxModel::providerForIndex( const QModel
return qobject_cast< QgsProcessingToolboxModelProviderNode * >( n )->provider();
}

QString QgsProcessingToolboxModel::providerIdForIndex( const QModelIndex &index ) const
{
QgsProcessingToolboxModelNode *n = index2node( index );
if ( !n || n->nodeType() != QgsProcessingToolboxModelNode::NodeProvider )
return nullptr;

return qobject_cast< QgsProcessingToolboxModelProviderNode * >( n )->providerId();
}

const QgsProcessingAlgorithm *QgsProcessingToolboxModel::algorithmForIndex( const QModelIndex &index ) const
{
QgsProcessingToolboxModelNode *n = index2node( index );
Expand All @@ -383,27 +433,24 @@ bool QgsProcessingToolboxModel::isAlgorithm( const QModelIndex &index ) const
return ( n && n->nodeType() == QgsProcessingToolboxModelNode::NodeAlgorithm );
}

QModelIndex QgsProcessingToolboxModel::indexForProvider( QgsProcessingProvider *provider ) const
QModelIndex QgsProcessingToolboxModel::indexForProvider( const QString &providerId ) const
{
if ( !provider )
return QModelIndex();

std::function< QModelIndex( const QModelIndex &parent, QgsProcessingProvider *provider ) > findIndex = [&]( const QModelIndex & parent, QgsProcessingProvider * provider )->QModelIndex
std::function< QModelIndex( const QModelIndex &parent, const QString &providerId ) > findIndex = [&]( const QModelIndex & parent, const QString & providerId )->QModelIndex
{
for ( int row = 0; row < rowCount( parent ); ++row )
{
QModelIndex current = index( row, 0, parent );
if ( providerForIndex( current ) == provider )
if ( providerIdForIndex( current ) == providerId )
return current;

QModelIndex checkChildren = findIndex( current, provider );
QModelIndex checkChildren = findIndex( current, providerId );
if ( checkChildren.isValid() )
return checkChildren;
}
return QModelIndex();
};

return findIndex( QModelIndex(), provider );
return findIndex( QModelIndex(), providerId );
}

QModelIndex QgsProcessingToolboxModel::indexOfParentTreeNode( QgsProcessingToolboxModelNode *parentNode ) const
Expand Down
30 changes: 26 additions & 4 deletions src/gui/processing/qgsprocessingtoolboxmodel.h
Expand Up @@ -89,6 +89,12 @@ class GUI_EXPORT QgsProcessingToolboxModelNode : public QObject
*/
QList<QgsProcessingToolboxModelNode *> children() const { return mChildren; } SIP_SKIP

/**
* Removes the specified \a node from this node's children, and gives
* ownership back to the caller.
*/
QgsProcessingToolboxModelNode *takeChild( QgsProcessingToolboxModelNode *node );

/**
* Tries to find a child node belonging to this node, which corresponds to
* a group node with the given group \a id. Returns nullptr if no matching
Expand Down Expand Up @@ -140,8 +146,14 @@ class GUI_EXPORT QgsProcessingToolboxModelProviderNode : public QgsProcessingToo
*/
QgsProcessingProvider *provider();

/**
* Returns the provider ID.
*/
QString providerId() const { return mProviderId; }

private:

QString mProviderId;
QgsProcessingProvider *mProvider = nullptr;

};
Expand Down Expand Up @@ -278,6 +290,15 @@ class GUI_EXPORT QgsProcessingToolboxModel : public QAbstractItemModel
*/
QgsProcessingProvider *providerForIndex( const QModelIndex &index ) const;

/**
* Returns the provider ID which corresponds to a given \a index, or
* an empty string if the index does not represent a provider.
*
* \see algorithmForIndex()
* \see indexForProvider()
*/
QString providerIdForIndex( const QModelIndex &index ) const;

/**
* Returns the algorithm which corresponds to a given \a index, or
* a nullptr if the index does not represent an algorithm.
Expand All @@ -295,10 +316,10 @@ class GUI_EXPORT QgsProcessingToolboxModel : public QAbstractItemModel
bool isAlgorithm( const QModelIndex &index ) const;

/**
* Returns the index corresponding to the specified \a provider.
* Returns the index corresponding to the specified \a providerId.
* \see providerForIndex()
*/
QModelIndex indexForProvider( QgsProcessingProvider *provider ) const;
QModelIndex indexForProvider( const QString &providerId ) const;

/**
* Returns the index corresponding to the parent of a given node.
Expand All @@ -309,6 +330,7 @@ class GUI_EXPORT QgsProcessingToolboxModel : public QAbstractItemModel

void rebuild();
void providerAdded( const QString &id );
void providerRemoved( const QString &id );

private:

Expand All @@ -319,10 +341,10 @@ class GUI_EXPORT QgsProcessingToolboxModel : public QAbstractItemModel
void addProvider( QgsProcessingProvider *provider );

/**
* Returns true if \a provider is a "top-level" provider, which shows
* Returns true if \a providerId is a "top-level" provider, which shows
* groups directly under the root node and not under a provider child node.
*/
static bool isTopLevelProvider( QgsProcessingProvider *provider );
static bool isTopLevelProvider( const QString &providerId );

/**
* Returns a formatted tooltip for an \a algorithm.
Expand Down

0 comments on commit dc737bf

Please sign in to comment.