Skip to content

Commit 92c3a88

Browse files
committedSep 9, 2020
[feature][vectortiles] Add checkbox for showing only visible rules
in the vector tiles labeling and renderer widgets Makes it much easier to locate troublesome rules or work with complex vector tile styling
1 parent c821288 commit 92c3a88

6 files changed

+215
-20
lines changed
 

‎src/gui/vectortile/qgsvectortilebasiclabelingwidget.cpp

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ QVariant QgsVectorTileBasicLabelingListModel::data( const QModelIndex &index, in
9696
return style.isEnabled() ? Qt::Checked : Qt::Unchecked;
9797
}
9898

99+
case MinZoom:
100+
return style.minZoomLevel();
101+
102+
case MaxZoom:
103+
return style.maxZoomLevel();
104+
99105
}
100106
return QVariant();
101107
}
@@ -308,11 +314,19 @@ QgsVectorTileBasicLabelingWidget::QgsVectorTileBasicLabelingWidget( QgsVectorTil
308314
{
309315
connect( mMapCanvas, &QgsMapCanvas::scaleChanged, this, [ = ]( double scale )
310316
{
311-
mLabelCurrentZoom->setText( tr( "Current zoom: %1" ).arg( QgsVectorTileUtils::scaleToZoomLevel( scale, 0, 99 ) ) );
317+
const int zoom = QgsVectorTileUtils::scaleToZoomLevel( scale, 0, 99 );
318+
mLabelCurrentZoom->setText( tr( "Current zoom: %1" ).arg( zoom ) );
319+
if ( mProxyModel )
320+
mProxyModel->setCurrentZoom( zoom );
312321
} );
313322
mLabelCurrentZoom->setText( tr( "Current zoom: %1" ).arg( QgsVectorTileUtils::scaleToZoomLevel( mMapCanvas->scale(), 0, 99 ) ) );
314323
}
315324

325+
connect( mCheckVisibleOnly, &QCheckBox::toggled, this, [ = ]( bool filter )
326+
{
327+
mProxyModel->setFilterVisible( filter );
328+
} );
329+
316330
setLayer( layer );
317331
}
318332

@@ -330,7 +344,14 @@ void QgsVectorTileBasicLabelingWidget::setLayer( QgsVectorTileLayer *layer )
330344
}
331345

332346
mModel = new QgsVectorTileBasicLabelingListModel( mLabeling.get(), viewStyles );
333-
viewStyles->setModel( mModel );
347+
mProxyModel = new QgsVectorTileBasicLabelingProxyModel( mModel, viewStyles );
348+
viewStyles->setModel( mProxyModel );
349+
350+
if ( mMapCanvas )
351+
{
352+
const int zoom = QgsVectorTileUtils::scaleToZoomLevel( mMapCanvas->scale(), 0, 99 );
353+
mProxyModel->setCurrentZoom( zoom );
354+
}
334355

335356
connect( mModel, &QAbstractItemModel::dataChanged, this, &QgsPanelWidget::widgetChanged );
336357
connect( mModel, &QAbstractItemModel::rowsInserted, this, &QgsPanelWidget::widgetChanged );
@@ -351,16 +372,17 @@ void QgsVectorTileBasicLabelingWidget::addStyle( QgsWkbTypes::GeometryType geomT
351372

352373
int rows = mModel->rowCount();
353374
mModel->insertStyle( rows, style );
354-
viewStyles->selectionModel()->setCurrentIndex( mModel->index( rows, 0 ), QItemSelectionModel::ClearAndSelect );
375+
viewStyles->selectionModel()->setCurrentIndex( mProxyModel->mapFromSource( mModel->index( rows, 0 ) ), QItemSelectionModel::ClearAndSelect );
355376
}
356377

357378
void QgsVectorTileBasicLabelingWidget::editStyle()
358379
{
359380
editStyleAtIndex( viewStyles->selectionModel()->currentIndex() );
360381
}
361382

362-
void QgsVectorTileBasicLabelingWidget::editStyleAtIndex( const QModelIndex &index )
383+
void QgsVectorTileBasicLabelingWidget::editStyleAtIndex( const QModelIndex &proxyIndex )
363384
{
385+
const QModelIndex index = mProxyModel->mapToSource( proxyIndex );
364386
if ( index.row() < 0 || index.row() >= mLabeling->styles().count() )
365387
return;
366388

@@ -400,7 +422,7 @@ void QgsVectorTileBasicLabelingWidget::editStyleAtIndex( const QModelIndex &inde
400422

401423
void QgsVectorTileBasicLabelingWidget::updateLabelingFromWidget()
402424
{
403-
int index = viewStyles->selectionModel()->currentIndex().row();
425+
int index = mProxyModel->mapToSource( viewStyles->selectionModel()->currentIndex() ).row();
404426
if ( index < 0 )
405427
return;
406428

@@ -415,12 +437,12 @@ void QgsVectorTileBasicLabelingWidget::updateLabelingFromWidget()
415437

416438
void QgsVectorTileBasicLabelingWidget::removeStyle()
417439
{
418-
QItemSelection sel = viewStyles->selectionModel()->selection();
419-
const auto constSel = sel;
420-
for ( const QItemSelectionRange &range : constSel )
440+
const QModelIndexList sel = viewStyles->selectionModel()->selectedIndexes();
441+
for ( const QModelIndex &proxyIndex : sel )
421442
{
422-
if ( range.isValid() )
423-
mModel->removeRows( range.top(), range.bottom() - range.top() + 1, range.parent() );
443+
const QModelIndex sourceIndex = mProxyModel->mapToSource( proxyIndex );
444+
if ( sourceIndex.isValid() )
445+
mModel->removeRow( sourceIndex.row() );
424446
}
425447
// make sure that the selection is gone
426448
viewStyles->selectionModel()->clear();
@@ -460,4 +482,41 @@ QgsPalLayerSettings QgsLabelingPanelWidget::labelSettings()
460482
return mLabelingGui->layerSettings();
461483
}
462484

485+
486+
QgsVectorTileBasicLabelingProxyModel::QgsVectorTileBasicLabelingProxyModel( QgsVectorTileBasicLabelingListModel *source, QObject *parent )
487+
: QSortFilterProxyModel( parent )
488+
{
489+
setSourceModel( source );
490+
setDynamicSortFilter( true );
491+
}
492+
493+
void QgsVectorTileBasicLabelingProxyModel::setCurrentZoom( int zoom )
494+
{
495+
mCurrentZoom = zoom;
496+
invalidateFilter();
497+
}
498+
499+
void QgsVectorTileBasicLabelingProxyModel::setFilterVisible( bool enabled )
500+
{
501+
mFilterVisible = enabled;
502+
invalidateFilter();
503+
}
504+
505+
bool QgsVectorTileBasicLabelingProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
506+
{
507+
if ( mCurrentZoom < 0 || !mFilterVisible )
508+
return true;
509+
510+
const int rowMinZoom = sourceModel()->data( sourceModel()->index( source_row, 0, source_parent ), QgsVectorTileBasicLabelingListModel::MinZoom ).toInt();
511+
const int rowMaxZoom = sourceModel()->data( sourceModel()->index( source_row, 0, source_parent ), QgsVectorTileBasicLabelingListModel::MaxZoom ).toInt();
512+
513+
if ( rowMinZoom >= 0 && rowMinZoom > mCurrentZoom )
514+
return false;
515+
516+
if ( rowMaxZoom >= 0 && rowMaxZoom < mCurrentZoom )
517+
return false;
518+
519+
return true;
520+
}
521+
463522
///@endcond

‎src/gui/vectortile/qgsvectortilebasiclabelingwidget.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "qgswkbtypes.h"
2424

2525
#include <memory>
26+
#include <QSortFilterProxyModel>
2627

2728
///@cond PRIVATE
2829
#define SIP_NO_FILE
@@ -32,6 +33,7 @@ class QgsVectorTileBasicLabelingListModel;
3233
class QgsVectorTileLayer;
3334
class QgsMapCanvas;
3435
class QgsMessageBar;
36+
class QgsVectorTileBasicLabelingProxyModel;
3537

3638
/**
3739
* \ingroup gui
@@ -65,6 +67,7 @@ class GUI_EXPORT QgsVectorTileBasicLabelingWidget : public QgsMapLayerConfigWidg
6567
QgsVectorTileLayer *mVTLayer = nullptr;
6668
std::unique_ptr<QgsVectorTileBasicLabeling> mLabeling;
6769
QgsVectorTileBasicLabelingListModel *mModel = nullptr;
70+
QgsVectorTileBasicLabelingProxyModel *mProxyModel = nullptr;
6871
QgsMapCanvas *mMapCanvas = nullptr;
6972
QgsMessageBar *mMessageBar = nullptr;
7073
};
@@ -103,6 +106,13 @@ class QgsVectorTileBasicLabelingListModel : public QAbstractListModel
103106
{
104107
Q_OBJECT
105108
public:
109+
110+
enum Role
111+
{
112+
MinZoom = Qt::UserRole + 1,
113+
MaxZoom,
114+
};
115+
106116
QgsVectorTileBasicLabelingListModel( QgsVectorTileBasicLabeling *r, QObject *parent = nullptr );
107117

108118
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
@@ -126,6 +136,24 @@ class QgsVectorTileBasicLabelingListModel : public QAbstractListModel
126136
QgsVectorTileBasicLabeling *mLabeling = nullptr;
127137
};
128138

139+
class QgsVectorTileBasicLabelingProxyModel : public QSortFilterProxyModel
140+
{
141+
Q_OBJECT
142+
public:
143+
QgsVectorTileBasicLabelingProxyModel( QgsVectorTileBasicLabelingListModel *source, QObject *parent = nullptr );
144+
145+
void setCurrentZoom( int zoom );
146+
void setFilterVisible( bool enabled );
147+
148+
bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const override;
149+
150+
private:
151+
152+
bool mFilterVisible = false;
153+
int mCurrentZoom = -1;
154+
};
155+
156+
129157
///@endcond
130158

131159
#endif // QGSVECTORTILEBASICLABELINGWIDGET_H

‎src/gui/vectortile/qgsvectortilebasicrendererwidget.cpp

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ QVariant QgsVectorTileBasicRendererListModel::data( const QModelIndex &index, in
111111
return style.isEnabled() ? Qt::Checked : Qt::Unchecked;
112112
}
113113

114+
case MinZoom:
115+
return style.minZoomLevel();
116+
117+
case MaxZoom:
118+
return style.maxZoomLevel();
119+
114120
}
115121
return QVariant();
116122
}
@@ -321,11 +327,19 @@ QgsVectorTileBasicRendererWidget::QgsVectorTileBasicRendererWidget( QgsVectorTil
321327
{
322328
connect( mMapCanvas, &QgsMapCanvas::scaleChanged, this, [ = ]( double scale )
323329
{
324-
mLabelCurrentZoom->setText( tr( "Current zoom: %1" ).arg( QgsVectorTileUtils::scaleToZoomLevel( scale, 0, 99 ) ) );
330+
const int zoom = QgsVectorTileUtils::scaleToZoomLevel( scale, 0, 99 );
331+
mLabelCurrentZoom->setText( tr( "Current zoom: %1" ).arg( zoom ) );
332+
if ( mProxyModel )
333+
mProxyModel->setCurrentZoom( zoom );
325334
} );
326335
mLabelCurrentZoom->setText( tr( "Current zoom: %1" ).arg( QgsVectorTileUtils::scaleToZoomLevel( mMapCanvas->scale(), 0, 99 ) ) );
327336
}
328337

338+
connect( mCheckVisibleOnly, &QCheckBox::toggled, this, [ = ]( bool filter )
339+
{
340+
mProxyModel->setFilterVisible( filter );
341+
} );
342+
329343
setLayer( layer );
330344
}
331345

@@ -343,7 +357,14 @@ void QgsVectorTileBasicRendererWidget::setLayer( QgsVectorTileLayer *layer )
343357
}
344358

345359
mModel = new QgsVectorTileBasicRendererListModel( mRenderer.get(), viewStyles );
346-
viewStyles->setModel( mModel );
360+
mProxyModel = new QgsVectorTileBasicRendererProxyModel( mModel, viewStyles );
361+
viewStyles->setModel( mProxyModel );
362+
363+
if ( mMapCanvas )
364+
{
365+
const int zoom = QgsVectorTileUtils::scaleToZoomLevel( mMapCanvas->scale(), 0, 99 );
366+
mProxyModel->setCurrentZoom( zoom );
367+
}
347368

348369
connect( mModel, &QAbstractItemModel::dataChanged, this, &QgsPanelWidget::widgetChanged );
349370
connect( mModel, &QAbstractItemModel::rowsInserted, this, &QgsPanelWidget::widgetChanged );
@@ -364,16 +385,17 @@ void QgsVectorTileBasicRendererWidget::addStyle( QgsWkbTypes::GeometryType geomT
364385

365386
int rows = mModel->rowCount();
366387
mModel->insertStyle( rows, style );
367-
viewStyles->selectionModel()->setCurrentIndex( mModel->index( rows, 0 ), QItemSelectionModel::ClearAndSelect );
388+
viewStyles->selectionModel()->setCurrentIndex( mProxyModel->mapFromSource( mModel->index( rows, 0 ) ), QItemSelectionModel::ClearAndSelect );
368389
}
369390

370391
void QgsVectorTileBasicRendererWidget::editStyle()
371392
{
372393
editStyleAtIndex( viewStyles->selectionModel()->currentIndex() );
373394
}
374395

375-
void QgsVectorTileBasicRendererWidget::editStyleAtIndex( const QModelIndex &index )
396+
void QgsVectorTileBasicRendererWidget::editStyleAtIndex( const QModelIndex &proxyIndex )
376397
{
398+
const QModelIndex index = mProxyModel->mapToSource( proxyIndex );
377399
if ( index.row() < 0 || index.row() >= mRenderer->styles().count() )
378400
return;
379401

@@ -417,7 +439,7 @@ void QgsVectorTileBasicRendererWidget::editStyleAtIndex( const QModelIndex &inde
417439

418440
void QgsVectorTileBasicRendererWidget::updateSymbolsFromWidget()
419441
{
420-
int index = viewStyles->selectionModel()->currentIndex().row();
442+
int index = mProxyModel->mapToSource( viewStyles->selectionModel()->currentIndex() ).row();
421443
if ( index < 0 )
422444
return;
423445

@@ -441,15 +463,53 @@ void QgsVectorTileBasicRendererWidget::cleanUpSymbolSelector( QgsPanelWidget *co
441463

442464
void QgsVectorTileBasicRendererWidget::removeStyle()
443465
{
444-
QItemSelection sel = viewStyles->selectionModel()->selection();
445-
const auto constSel = sel;
446-
for ( const QItemSelectionRange &range : constSel )
466+
const QModelIndexList sel = viewStyles->selectionModel()->selectedIndexes();
467+
for ( const QModelIndex &proxyIndex : sel )
447468
{
448-
if ( range.isValid() )
449-
mModel->removeRows( range.top(), range.bottom() - range.top() + 1, range.parent() );
469+
const QModelIndex sourceIndex = mProxyModel->mapToSource( proxyIndex );
470+
if ( sourceIndex.isValid() )
471+
mModel->removeRow( sourceIndex.row() );
450472
}
451473
// make sure that the selection is gone
452474
viewStyles->selectionModel()->clear();
453475
}
454476

477+
QgsVectorTileBasicRendererProxyModel::QgsVectorTileBasicRendererProxyModel( QgsVectorTileBasicRendererListModel *source, QObject *parent )
478+
: QSortFilterProxyModel( parent )
479+
{
480+
setSourceModel( source );
481+
setDynamicSortFilter( true );
482+
}
483+
484+
void QgsVectorTileBasicRendererProxyModel::setCurrentZoom( int zoom )
485+
{
486+
mCurrentZoom = zoom;
487+
invalidateFilter();
488+
}
489+
490+
void QgsVectorTileBasicRendererProxyModel::setFilterVisible( bool enabled )
491+
{
492+
mFilterVisible = enabled;
493+
invalidateFilter();
494+
}
495+
496+
bool QgsVectorTileBasicRendererProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
497+
{
498+
if ( mCurrentZoom < 0 || !mFilterVisible )
499+
return true;
500+
501+
const int rowMinZoom = sourceModel()->data( sourceModel()->index( source_row, 0, source_parent ), QgsVectorTileBasicRendererListModel::MinZoom ).toInt();
502+
const int rowMaxZoom = sourceModel()->data( sourceModel()->index( source_row, 0, source_parent ), QgsVectorTileBasicRendererListModel::MaxZoom ).toInt();
503+
504+
if ( rowMinZoom >= 0 && rowMinZoom > mCurrentZoom )
505+
return false;
506+
507+
if ( rowMaxZoom >= 0 && rowMaxZoom < mCurrentZoom )
508+
return false;
509+
510+
return true;
511+
}
512+
513+
514+
455515
///@endcond

‎src/gui/vectortile/qgsvectortilebasicrendererwidget.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "qgswkbtypes.h"
2424

2525
#include <memory>
26+
#include <QSortFilterProxyModel>
27+
2628

2729
///@cond PRIVATE
2830
#define SIP_NO_FILE
@@ -32,6 +34,7 @@ class QgsVectorTileBasicRendererListModel;
3234
class QgsVectorTileLayer;
3335
class QgsMapCanvas;
3436
class QgsMessageBar;
37+
class QgsVectorTileBasicRendererProxyModel;
3538

3639
/**
3740
* \ingroup gui
@@ -65,6 +68,7 @@ class GUI_EXPORT QgsVectorTileBasicRendererWidget : public QgsMapLayerConfigWidg
6568
QgsVectorTileLayer *mVTLayer = nullptr;
6669
std::unique_ptr<QgsVectorTileBasicRenderer> mRenderer;
6770
QgsVectorTileBasicRendererListModel *mModel = nullptr;
71+
QgsVectorTileBasicRendererProxyModel *mProxyModel = nullptr;
6872
QgsMapCanvas *mMapCanvas = nullptr;
6973
QgsMessageBar *mMessageBar = nullptr;
7074
};
@@ -76,6 +80,13 @@ class QgsVectorTileBasicRendererListModel : public QAbstractListModel
7680
{
7781
Q_OBJECT
7882
public:
83+
84+
enum Role
85+
{
86+
MinZoom = Qt::UserRole + 1,
87+
MaxZoom,
88+
};
89+
7990
QgsVectorTileBasicRendererListModel( QgsVectorTileBasicRenderer *r, QObject *parent = nullptr );
8091

8192
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
@@ -99,6 +110,23 @@ class QgsVectorTileBasicRendererListModel : public QAbstractListModel
99110
QgsVectorTileBasicRenderer *mRenderer = nullptr;
100111
};
101112

113+
class QgsVectorTileBasicRendererProxyModel : public QSortFilterProxyModel
114+
{
115+
Q_OBJECT
116+
public:
117+
QgsVectorTileBasicRendererProxyModel( QgsVectorTileBasicRendererListModel *source, QObject *parent = nullptr );
118+
119+
void setCurrentZoom( int zoom );
120+
void setFilterVisible( bool enabled );
121+
122+
bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const override;
123+
124+
private:
125+
126+
bool mFilterVisible = false;
127+
int mCurrentZoom = -1;
128+
};
129+
102130
///@endcond
103131

104132
#endif // QGSVECTORTILEBASICRENDERERWIDGET_H

‎src/ui/qgsvectortilebasiclabelingwidget.ui

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,16 @@
100100
</property>
101101
</widget>
102102
</item>
103+
<item>
104+
<widget class="QCheckBox" name="mCheckVisibleOnly">
105+
<property name="toolTip">
106+
<string>Hides any rules which are invisible because they fall outside the current map canvas zoom level</string>
107+
</property>
108+
<property name="text">
109+
<string>Visible rules only</string>
110+
</property>
111+
</widget>
112+
</item>
103113
</layout>
104114
</item>
105115
</layout>

‎src/ui/qgsvectortilebasicrendererwidget.ui

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,16 @@
100100
</property>
101101
</widget>
102102
</item>
103+
<item>
104+
<widget class="QCheckBox" name="mCheckVisibleOnly">
105+
<property name="toolTip">
106+
<string>Hides any rules which are invisible because they fall outside the current map canvas zoom level</string>
107+
</property>
108+
<property name="text">
109+
<string>Visible rules only</string>
110+
</property>
111+
</widget>
112+
</item>
103113
</layout>
104114
</item>
105115
</layout>

0 commit comments

Comments
 (0)
Please sign in to comment.