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 */ LayerIdRole, /*!< Stores the map layer ID */
LayerRole, /*!< Stores pointer to the map layer itself */ LayerRole, /*!< Stores pointer to the map layer itself */
IsEmptyRole, //!< True if index corresponds to the empty (not set) value 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; 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) * @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; 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. /** Returns the current layer selected in the combo box.
* @see layer * @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 ); 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 ) void QgsMapLayerModel::removeLayers( const QStringList& layerIds )
{ {
int offset = 0;
if ( mAllowEmpty )
offset++;

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


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


int QgsMapLayerModel::columnCount( const QModelIndex &parent ) const 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 QVariant QgsMapLayerModel::data( const QModelIndex &index, int role ) const
{ {
bool isEmpty = index.row() == 0 && mAllowEmpty;

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


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

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


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

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


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


QgsMapLayer* layer = static_cast<QgsMapLayer*>( index.internalPointer() ); 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 ( role == LayerRole )
{ {
if ( isEmpty ) if ( isEmpty || additionalIndex >= 0 )
return QVariant(); return QVariant();


return QVariant::fromValue<QgsMapLayer*>( static_cast<QgsMapLayer*>( index.internalPointer() ) ); 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 ) if ( role == IsEmptyRole )
return isEmpty; return isEmpty;


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

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


QgsMapLayer* layer = static_cast<QgsMapLayer*>( index.internalPointer() ); 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 ( role == Qt::DecorationRole )
{ {
if ( isEmpty ) if ( isEmpty || additionalIndex >= 0 )
return QVariant(); return QVariant();


QgsMapLayer* layer = static_cast<QgsMapLayer*>( index.internalPointer() ); 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; bool isEmpty = index.row() == 0 && mAllowEmpty;
int additionalIndex = index.row() - ( mAllowEmpty ? 1 : 0 ) - mLayers.count();


Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
if ( mItemCheckable && !isEmpty ) if ( mItemCheckable && !isEmpty && additionalIndex < 0 )
{ {
flags |= Qt::ItemIsUserCheckable; 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 QgsMapLayerModel::setData( const QModelIndex &index, const QVariant &value, int role )
{ {
bool isEmpty = index.row() == 0 && mAllowEmpty; 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() ); QgsMapLayer* layer = static_cast<QgsMapLayer*>( index.internalPointer() );
mLayersChecked[layer->id()] = ( Qt::CheckState )value.toInt(); 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 allowEmptyLayer READ allowEmptyLayer WRITE setAllowEmptyLayer )
Q_PROPERTY( bool showCrs READ showCrs WRITE setShowCrs ) Q_PROPERTY( bool showCrs READ showCrs WRITE setShowCrs )
Q_PROPERTY( bool itemsCheckable READ itemsCheckable WRITE setItemsCheckable ) Q_PROPERTY( bool itemsCheckable READ itemsCheckable WRITE setItemsCheckable )
Q_PROPERTY( QStringList additionalItems READ additionalItems WRITE setAdditionalItems )


public: public:


Expand All @@ -45,6 +46,7 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel
LayerIdRole = Qt::UserRole + 1, //!< Stores the map layer ID LayerIdRole = Qt::UserRole + 1, //!< Stores the map layer ID
LayerRole, //!< Stores pointer to the map layer itself LayerRole, //!< Stores pointer to the map layer itself
IsEmptyRole, //!< True if index corresponds to the empty (not set) value 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; 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: protected slots:
void removeLayers( const QStringList& layerIds ); void removeLayers( const QStringList& layerIds );
void addLayers( const QList<QgsMapLayer*>& layers ); void addLayers( const QList<QgsMapLayer*>& layers );
Expand Down Expand Up @@ -138,6 +156,7 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel


bool mAllowEmpty; bool mAllowEmpty;
bool mShowCrs; bool mShowCrs;
QStringList mAdditionalItems;
}; };


#endif // QGSMAPLAYERMODEL_H #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 ); 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; return true;


QgsMapLayer* layer = static_cast<QgsMapLayer*>( index.internalPointer() ); 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() ) else if ( sourceModel()->data( right, QgsMapLayerModel::IsEmptyRole ).toBool() )
return false; 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 // default mode is alphabetical order
QString leftStr = sourceModel()->data( left ).toString(); QString leftStr = sourceModel()->data( left ).toString();
QString rightStr = sourceModel()->data( right ).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(); 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 ) void QgsMapLayerComboBox::setLayer( QgsMapLayer *layer )
{ {
if ( !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; 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. /** Returns the current layer selected in the combo box.
* @see layer * @see layer
*/ */
Expand Down

0 comments on commit 9ee7873

Please sign in to comment.