Skip to content

Commit 9ee7873

Browse files
committed
Allow showing additional items in QgsMapLayerComboBox
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.
1 parent ec49341 commit 9ee7873

File tree

8 files changed

+212
-11
lines changed

8 files changed

+212
-11
lines changed

python/core/qgsmaplayermodel.sip

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class QgsMapLayerModel : QAbstractItemModel
2020
LayerIdRole, /*!< Stores the map layer ID */
2121
LayerRole, /*!< Stores pointer to the map layer itself */
2222
IsEmptyRole, //!< True if index corresponds to the empty (not set) value
23+
IsAdditionalRole, //!< True if index corresponds to an additional (non map layer) item
2324
};
2425

2526
/**
@@ -68,6 +69,22 @@ class QgsMapLayerModel : QAbstractItemModel
6869
*/
6970
bool showCrs() const;
7071

72+
/**
73+
* Sets a list of additional (non map layer) items to include at the end of the model.
74+
* These may represent additional layers such as layers which are not included in the map
75+
* layer registry, or paths to layers which have not yet been loaded into QGIS.
76+
* @see additionalItems()
77+
* @note added in QGIS 3.0
78+
*/
79+
void setAdditionalItems( const QStringList& items );
80+
81+
/**
82+
* Return the list of additional (non map layer) items included at the end of the model.
83+
* @see setAdditionalItems()
84+
* @note added in QGIS 3.0
85+
*/
86+
QStringList additionalItems() const;
87+
7188
/**
7289
* @brief layersChecked returns the list of layers which are checked (or unchecked)
7390
*/

python/gui/qgsmaplayercombobox.sip

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,22 @@ class QgsMapLayerComboBox : QComboBox
5656
*/
5757
bool showCrs() const;
5858

59+
/**
60+
* Sets a list of additional (non map layer) items to include at the end of the combobox.
61+
* These may represent additional layers such as layers which are not included in the map
62+
* layer registry, or paths to layers which have not yet been loaded into QGIS.
63+
* @see additionalItems()
64+
* @note added in QGIS 3.0
65+
*/
66+
void setAdditionalItems( const QStringList& items );
67+
68+
/**
69+
* Return the list of additional (non map layer) items included at the end of the combo box.
70+
* @see setAdditionalItems()
71+
* @note added in QGIS 3.0
72+
*/
73+
QStringList additionalItems() const;
74+
5975
/** Returns the current layer selected in the combo box.
6076
* @see layer
6177
*/

src/core/qgsmaplayermodel.cpp

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,37 @@ QModelIndex QgsMapLayerModel::indexFromLayer( QgsMapLayer *layer ) const
108108
return index( r, 0 );
109109
}
110110

111+
void QgsMapLayerModel::setAdditionalItems( const QStringList& items )
112+
{
113+
if ( items == mAdditionalItems )
114+
return;
115+
116+
int offset = 0;
117+
if ( mAllowEmpty )
118+
offset++;
119+
120+
offset += mLayers.count();
121+
122+
//remove existing
123+
if ( !mAdditionalItems.isEmpty() )
124+
{
125+
beginRemoveRows( QModelIndex(), offset, offset + mAdditionalItems.count() - 1 );
126+
mAdditionalItems.clear();
127+
endRemoveRows();
128+
}
129+
130+
//add new
131+
beginInsertRows( QModelIndex(), offset, offset + items.count() - 1 );
132+
mAdditionalItems = items;
133+
endInsertRows();
134+
}
135+
111136
void QgsMapLayerModel::removeLayers( const QStringList& layerIds )
112137
{
138+
int offset = 0;
139+
if ( mAllowEmpty )
140+
offset++;
141+
113142
Q_FOREACH ( const QString& layerId, layerIds )
114143
{
115144
QModelIndex startIndex = index( 0, 0 );
@@ -119,7 +148,7 @@ void QgsMapLayerModel::removeLayers( const QStringList& layerIds )
119148
QModelIndex index = list[0];
120149
beginRemoveRows( QModelIndex(), index.row(), index.row() );
121150
mLayersChecked.remove( layerId );
122-
mLayers.removeAt( index.row() );
151+
mLayers.removeAt( index.row() - offset );
123152
endRemoveRows();
124153
}
125154
}
@@ -171,7 +200,7 @@ int QgsMapLayerModel::rowCount( const QModelIndex &parent ) const
171200
if ( parent.isValid() )
172201
return 0;
173202

174-
return ( mAllowEmpty ? 1 : 0 ) + mLayers.length();
203+
return ( mAllowEmpty ? 1 : 0 ) + mLayers.length() + mAdditionalItems.count();
175204
}
176205

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

184213
QVariant QgsMapLayerModel::data( const QModelIndex &index, int role ) const
185214
{
186-
bool isEmpty = index.row() == 0 && mAllowEmpty;
187-
188215
if ( !index.isValid() )
189216
return QVariant();
190217

218+
bool isEmpty = index.row() == 0 && mAllowEmpty;
219+
int additionalIndex = index.row() - ( mAllowEmpty ? 1 : 0 ) - mLayers.count();
220+
191221
if ( role == Qt::DisplayRole )
192222
{
193223
if ( index.row() == 0 && mAllowEmpty )
194224
return QVariant();
195225

226+
if ( additionalIndex >= 0 )
227+
return mAdditionalItems.at( additionalIndex );
228+
196229
QgsMapLayer* layer = static_cast<QgsMapLayer*>( index.internalPointer() );
197230
if ( !layer )
198231
return QVariant();
@@ -209,7 +242,7 @@ QVariant QgsMapLayerModel::data( const QModelIndex &index, int role ) const
209242

210243
if ( role == LayerIdRole )
211244
{
212-
if ( isEmpty )
245+
if ( isEmpty || additionalIndex >= 0 )
213246
return QVariant();
214247

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

219252
if ( role == LayerRole )
220253
{
221-
if ( isEmpty )
254+
if ( isEmpty || additionalIndex >= 0 )
222255
return QVariant();
223256

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

263+
if ( role == IsAdditionalRole )
264+
return additionalIndex >= 0;
265+
230266
if ( role == Qt::CheckStateRole && mItemCheckable )
231267
{
232-
if ( isEmpty )
268+
if ( isEmpty || additionalIndex >= 0 )
233269
return QVariant();
234270

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

239275
if ( role == Qt::DecorationRole )
240276
{
241-
if ( isEmpty )
277+
if ( isEmpty || additionalIndex >= 0 )
242278
return QVariant();
243279

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

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

319356
Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
320-
if ( mItemCheckable && !isEmpty )
357+
if ( mItemCheckable && !isEmpty && additionalIndex < 0 )
321358
{
322359
flags |= Qt::ItemIsUserCheckable;
323360
}
@@ -328,8 +365,9 @@ Qt::ItemFlags QgsMapLayerModel::flags( const QModelIndex &index ) const
328365
bool QgsMapLayerModel::setData( const QModelIndex &index, const QVariant &value, int role )
329366
{
330367
bool isEmpty = index.row() == 0 && mAllowEmpty;
368+
int additionalIndex = index.row() - ( mAllowEmpty ? 1 : 0 ) - mLayers.count();
331369

332-
if ( role == Qt::CheckStateRole && !isEmpty )
370+
if ( role == Qt::CheckStateRole && !isEmpty && additionalIndex < 0 )
333371
{
334372
QgsMapLayer* layer = static_cast<QgsMapLayer*>( index.internalPointer() );
335373
mLayersChecked[layer->id()] = ( Qt::CheckState )value.toInt();

src/core/qgsmaplayermodel.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel
3636
Q_PROPERTY( bool allowEmptyLayer READ allowEmptyLayer WRITE setAllowEmptyLayer )
3737
Q_PROPERTY( bool showCrs READ showCrs WRITE setShowCrs )
3838
Q_PROPERTY( bool itemsCheckable READ itemsCheckable WRITE setItemsCheckable )
39+
Q_PROPERTY( QStringList additionalItems READ additionalItems WRITE setAdditionalItems )
3940

4041
public:
4142

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

5052
/**
@@ -107,6 +109,22 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel
107109
*/
108110
QModelIndex indexFromLayer( QgsMapLayer* layer ) const;
109111

112+
/**
113+
* Sets a list of additional (non map layer) items to include at the end of the model.
114+
* These may represent additional layers such as layers which are not included in the map
115+
* layer registry, or paths to layers which have not yet been loaded into QGIS.
116+
* @see additionalItems()
117+
* @note added in QGIS 3.0
118+
*/
119+
void setAdditionalItems( const QStringList& items );
120+
121+
/**
122+
* Return the list of additional (non map layer) items included at the end of the model.
123+
* @see setAdditionalItems()
124+
* @note added in QGIS 3.0
125+
*/
126+
QStringList additionalItems() const { return mAdditionalItems; }
127+
110128
protected slots:
111129
void removeLayers( const QStringList& layerIds );
112130
void addLayers( const QList<QgsMapLayer*>& layers );
@@ -138,6 +156,7 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel
138156

139157
bool mAllowEmpty;
140158
bool mShowCrs;
159+
QStringList mAdditionalItems;
141160
};
142161

143162
#endif // QGSMAPLAYERMODEL_H

src/core/qgsmaplayerproxymodel.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ bool QgsMapLayerProxyModel::filterAcceptsRow( int source_row, const QModelIndex
7878

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

81-
if ( sourceModel()->data( index, QgsMapLayerModel::IsEmptyRole ).toBool() )
81+
if ( sourceModel()->data( index, QgsMapLayerModel::IsEmptyRole ).toBool()
82+
|| sourceModel()->data( index, QgsMapLayerModel::IsAdditionalRole ).toBool() )
8283
return true;
8384

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

137+
// additional rows are always last
138+
bool leftAdditional = sourceModel()->data( left, QgsMapLayerModel::IsAdditionalRole ).toBool();
139+
bool rightAdditional = sourceModel()->data( right, QgsMapLayerModel::IsAdditionalRole ).toBool();
140+
141+
if ( leftAdditional && !rightAdditional )
142+
return false;
143+
else if ( rightAdditional && !leftAdditional )
144+
return true;
145+
136146
// default mode is alphabetical order
137147
QString leftStr = sourceModel()->data( left ).toString();
138148
QString rightStr = sourceModel()->data( right ).toString();

src/gui/qgsmaplayercombobox.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ bool QgsMapLayerComboBox::showCrs() const
4848
return mProxyModel->sourceLayerModel()->showCrs();
4949
}
5050

51+
void QgsMapLayerComboBox::setAdditionalItems( const QStringList& items )
52+
{
53+
mProxyModel->sourceLayerModel()->setAdditionalItems( items );
54+
}
55+
56+
QStringList QgsMapLayerComboBox::additionalItems() const
57+
{
58+
return mProxyModel->sourceLayerModel()->additionalItems();
59+
}
60+
5161
void QgsMapLayerComboBox::setLayer( QgsMapLayer *layer )
5262
{
5363
if ( !layer )

src/gui/qgsmaplayercombobox.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,22 @@ class GUI_EXPORT QgsMapLayerComboBox : public QComboBox
8383
*/
8484
bool showCrs() const;
8585

86+
/**
87+
* Sets a list of additional (non map layer) items to include at the end of the combobox.
88+
* These may represent additional layers such as layers which are not included in the map
89+
* layer registry, or paths to layers which have not yet been loaded into QGIS.
90+
* @see additionalItems()
91+
* @note added in QGIS 3.0
92+
*/
93+
void setAdditionalItems( const QStringList& items );
94+
95+
/**
96+
* Return the list of additional (non map layer) items included at the end of the combo box.
97+
* @see setAdditionalItems()
98+
* @note added in QGIS 3.0
99+
*/
100+
QStringList additionalItems() const;
101+
86102
/** Returns the current layer selected in the combo box.
87103
* @see layer
88104
*/

0 commit comments

Comments
 (0)