Skip to content

Commit

Permalink
Allow showing additional items in QgsMapLayerComboBox
Browse files Browse the repository at this point in the history
These may represent additional layers such as layers which
are not included in the map layer registry, or paths to
layers which have not yet been loaded into QGIS.
  • Loading branch information
nyalldawson committed Nov 16, 2016
1 parent ec49341 commit 9ee7873
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 11 deletions.
17 changes: 17 additions & 0 deletions python/core/qgsmaplayermodel.sip
Expand Up @@ -20,6 +20,7 @@ class QgsMapLayerModel : QAbstractItemModel
LayerIdRole, /*!< Stores the map layer ID */
LayerRole, /*!< Stores pointer to the map layer itself */
IsEmptyRole, //!< True if index corresponds to the empty (not set) value
IsAdditionalRole, //!< True if index corresponds to an additional (non map layer) item
};

/**
Expand Down Expand Up @@ -68,6 +69,22 @@ class QgsMapLayerModel : QAbstractItemModel
*/
bool showCrs() const;

/**
* Sets a list of additional (non map layer) items to include at the end of the model.
* These may represent additional layers such as layers which are not included in the map
* layer registry, or paths to layers which have not yet been loaded into QGIS.
* @see additionalItems()
* @note added in QGIS 3.0
*/
void setAdditionalItems( const QStringList& items );

/**
* Return the list of additional (non map layer) items included at the end of the model.
* @see setAdditionalItems()
* @note added in QGIS 3.0
*/
QStringList additionalItems() const;

/**
* @brief layersChecked returns the list of layers which are checked (or unchecked)
*/
Expand Down
16 changes: 16 additions & 0 deletions python/gui/qgsmaplayercombobox.sip
Expand Up @@ -56,6 +56,22 @@ class QgsMapLayerComboBox : QComboBox
*/
bool showCrs() const;

/**
* Sets a list of additional (non map layer) items to include at the end of the combobox.
* These may represent additional layers such as layers which are not included in the map
* layer registry, or paths to layers which have not yet been loaded into QGIS.
* @see additionalItems()
* @note added in QGIS 3.0
*/
void setAdditionalItems( const QStringList& items );

/**
* Return the list of additional (non map layer) items included at the end of the combo box.
* @see setAdditionalItems()
* @note added in QGIS 3.0
*/
QStringList additionalItems() const;

/** Returns the current layer selected in the combo box.
* @see layer
*/
Expand Down
58 changes: 48 additions & 10 deletions src/core/qgsmaplayermodel.cpp
Expand Up @@ -108,8 +108,37 @@ QModelIndex QgsMapLayerModel::indexFromLayer( QgsMapLayer *layer ) const
return index( r, 0 );
}

void QgsMapLayerModel::setAdditionalItems( const QStringList& items )
{
if ( items == mAdditionalItems )
return;

int offset = 0;
if ( mAllowEmpty )
offset++;

offset += mLayers.count();

//remove existing
if ( !mAdditionalItems.isEmpty() )
{
beginRemoveRows( QModelIndex(), offset, offset + mAdditionalItems.count() - 1 );
mAdditionalItems.clear();
endRemoveRows();
}

//add new
beginInsertRows( QModelIndex(), offset, offset + items.count() - 1 );
mAdditionalItems = items;
endInsertRows();
}

void QgsMapLayerModel::removeLayers( const QStringList& layerIds )
{
int offset = 0;
if ( mAllowEmpty )
offset++;

Q_FOREACH ( const QString& layerId, layerIds )
{
QModelIndex startIndex = index( 0, 0 );
Expand All @@ -119,7 +148,7 @@ void QgsMapLayerModel::removeLayers( const QStringList& layerIds )
QModelIndex index = list[0];
beginRemoveRows( QModelIndex(), index.row(), index.row() );
mLayersChecked.remove( layerId );
mLayers.removeAt( index.row() );
mLayers.removeAt( index.row() - offset );
endRemoveRows();
}
}
Expand Down Expand Up @@ -171,7 +200,7 @@ int QgsMapLayerModel::rowCount( const QModelIndex &parent ) const
if ( parent.isValid() )
return 0;

return ( mAllowEmpty ? 1 : 0 ) + mLayers.length();
return ( mAllowEmpty ? 1 : 0 ) + mLayers.length() + mAdditionalItems.count();
}

int QgsMapLayerModel::columnCount( const QModelIndex &parent ) const
Expand All @@ -183,16 +212,20 @@ int QgsMapLayerModel::columnCount( const QModelIndex &parent ) const

QVariant QgsMapLayerModel::data( const QModelIndex &index, int role ) const
{
bool isEmpty = index.row() == 0 && mAllowEmpty;

if ( !index.isValid() )
return QVariant();

bool isEmpty = index.row() == 0 && mAllowEmpty;
int additionalIndex = index.row() - ( mAllowEmpty ? 1 : 0 ) - mLayers.count();

if ( role == Qt::DisplayRole )
{
if ( index.row() == 0 && mAllowEmpty )
return QVariant();

if ( additionalIndex >= 0 )
return mAdditionalItems.at( additionalIndex );

QgsMapLayer* layer = static_cast<QgsMapLayer*>( index.internalPointer() );
if ( !layer )
return QVariant();
Expand All @@ -209,7 +242,7 @@ QVariant QgsMapLayerModel::data( const QModelIndex &index, int role ) const

if ( role == LayerIdRole )
{
if ( isEmpty )
if ( isEmpty || additionalIndex >= 0 )
return QVariant();

QgsMapLayer* layer = static_cast<QgsMapLayer*>( index.internalPointer() );
Expand All @@ -218,7 +251,7 @@ QVariant QgsMapLayerModel::data( const QModelIndex &index, int role ) const

if ( role == LayerRole )
{
if ( isEmpty )
if ( isEmpty || additionalIndex >= 0 )
return QVariant();

return QVariant::fromValue<QgsMapLayer*>( static_cast<QgsMapLayer*>( index.internalPointer() ) );
Expand All @@ -227,9 +260,12 @@ QVariant QgsMapLayerModel::data( const QModelIndex &index, int role ) const
if ( role == IsEmptyRole )
return isEmpty;

if ( role == IsAdditionalRole )
return additionalIndex >= 0;

if ( role == Qt::CheckStateRole && mItemCheckable )
{
if ( isEmpty )
if ( isEmpty || additionalIndex >= 0 )
return QVariant();

QgsMapLayer* layer = static_cast<QgsMapLayer*>( index.internalPointer() );
Expand All @@ -238,7 +274,7 @@ QVariant QgsMapLayerModel::data( const QModelIndex &index, int role ) const

if ( role == Qt::DecorationRole )
{
if ( isEmpty )
if ( isEmpty || additionalIndex >= 0 )
return QVariant();

QgsMapLayer* layer = static_cast<QgsMapLayer*>( index.internalPointer() );
Expand Down Expand Up @@ -315,9 +351,10 @@ Qt::ItemFlags QgsMapLayerModel::flags( const QModelIndex &index ) const
}

bool isEmpty = index.row() == 0 && mAllowEmpty;
int additionalIndex = index.row() - ( mAllowEmpty ? 1 : 0 ) - mLayers.count();

Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
if ( mItemCheckable && !isEmpty )
if ( mItemCheckable && !isEmpty && additionalIndex < 0 )
{
flags |= Qt::ItemIsUserCheckable;
}
Expand All @@ -328,8 +365,9 @@ Qt::ItemFlags QgsMapLayerModel::flags( const QModelIndex &index ) const
bool QgsMapLayerModel::setData( const QModelIndex &index, const QVariant &value, int role )
{
bool isEmpty = index.row() == 0 && mAllowEmpty;
int additionalIndex = index.row() - ( mAllowEmpty ? 1 : 0 ) - mLayers.count();

if ( role == Qt::CheckStateRole && !isEmpty )
if ( role == Qt::CheckStateRole && !isEmpty && additionalIndex < 0 )
{
QgsMapLayer* layer = static_cast<QgsMapLayer*>( index.internalPointer() );
mLayersChecked[layer->id()] = ( Qt::CheckState )value.toInt();
Expand Down
19 changes: 19 additions & 0 deletions src/core/qgsmaplayermodel.h
Expand Up @@ -36,6 +36,7 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel
Q_PROPERTY( bool allowEmptyLayer READ allowEmptyLayer WRITE setAllowEmptyLayer )
Q_PROPERTY( bool showCrs READ showCrs WRITE setShowCrs )
Q_PROPERTY( bool itemsCheckable READ itemsCheckable WRITE setItemsCheckable )
Q_PROPERTY( QStringList additionalItems READ additionalItems WRITE setAdditionalItems )

public:

Expand All @@ -45,6 +46,7 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel
LayerIdRole = Qt::UserRole + 1, //!< Stores the map layer ID
LayerRole, //!< Stores pointer to the map layer itself
IsEmptyRole, //!< True if index corresponds to the empty (not set) value
IsAdditionalRole, //!< True if index corresponds to an additional (non map layer) item
};

/**
Expand Down Expand Up @@ -107,6 +109,22 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel
*/
QModelIndex indexFromLayer( QgsMapLayer* layer ) const;

/**
* Sets a list of additional (non map layer) items to include at the end of the model.
* These may represent additional layers such as layers which are not included in the map
* layer registry, or paths to layers which have not yet been loaded into QGIS.
* @see additionalItems()
* @note added in QGIS 3.0
*/
void setAdditionalItems( const QStringList& items );

/**
* Return the list of additional (non map layer) items included at the end of the model.
* @see setAdditionalItems()
* @note added in QGIS 3.0
*/
QStringList additionalItems() const { return mAdditionalItems; }

protected slots:
void removeLayers( const QStringList& layerIds );
void addLayers( const QList<QgsMapLayer*>& layers );
Expand Down Expand Up @@ -138,6 +156,7 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel

bool mAllowEmpty;
bool mShowCrs;
QStringList mAdditionalItems;
};

#endif // QGSMAPLAYERMODEL_H
12 changes: 11 additions & 1 deletion src/core/qgsmaplayerproxymodel.cpp
Expand Up @@ -78,7 +78,8 @@ bool QgsMapLayerProxyModel::filterAcceptsRow( int source_row, const QModelIndex

QModelIndex index = sourceModel()->index( source_row, 0, source_parent );

if ( sourceModel()->data( index, QgsMapLayerModel::IsEmptyRole ).toBool() )
if ( sourceModel()->data( index, QgsMapLayerModel::IsEmptyRole ).toBool()
|| sourceModel()->data( index, QgsMapLayerModel::IsAdditionalRole ).toBool() )
return true;

QgsMapLayer* layer = static_cast<QgsMapLayer*>( index.internalPointer() );
Expand Down Expand Up @@ -133,6 +134,15 @@ bool QgsMapLayerProxyModel::lessThan( const QModelIndex &left, const QModelIndex
else if ( sourceModel()->data( right, QgsMapLayerModel::IsEmptyRole ).toBool() )
return false;

// additional rows are always last
bool leftAdditional = sourceModel()->data( left, QgsMapLayerModel::IsAdditionalRole ).toBool();
bool rightAdditional = sourceModel()->data( right, QgsMapLayerModel::IsAdditionalRole ).toBool();

if ( leftAdditional && !rightAdditional )
return false;
else if ( rightAdditional && !leftAdditional )
return true;

// default mode is alphabetical order
QString leftStr = sourceModel()->data( left ).toString();
QString rightStr = sourceModel()->data( right ).toString();
Expand Down
10 changes: 10 additions & 0 deletions src/gui/qgsmaplayercombobox.cpp
Expand Up @@ -48,6 +48,16 @@ bool QgsMapLayerComboBox::showCrs() const
return mProxyModel->sourceLayerModel()->showCrs();
}

void QgsMapLayerComboBox::setAdditionalItems( const QStringList& items )
{
mProxyModel->sourceLayerModel()->setAdditionalItems( items );
}

QStringList QgsMapLayerComboBox::additionalItems() const
{
return mProxyModel->sourceLayerModel()->additionalItems();
}

void QgsMapLayerComboBox::setLayer( QgsMapLayer *layer )
{
if ( !layer )
Expand Down
16 changes: 16 additions & 0 deletions src/gui/qgsmaplayercombobox.h
Expand Up @@ -83,6 +83,22 @@ class GUI_EXPORT QgsMapLayerComboBox : public QComboBox
*/
bool showCrs() const;

/**
* Sets a list of additional (non map layer) items to include at the end of the combobox.
* These may represent additional layers such as layers which are not included in the map
* layer registry, or paths to layers which have not yet been loaded into QGIS.
* @see additionalItems()
* @note added in QGIS 3.0
*/
void setAdditionalItems( const QStringList& items );

/**
* Return the list of additional (non map layer) items included at the end of the combo box.
* @see setAdditionalItems()
* @note added in QGIS 3.0
*/
QStringList additionalItems() const;

/** Returns the current layer selected in the combo box.
* @see layer
*/
Expand Down

0 comments on commit 9ee7873

Please sign in to comment.