Skip to content

Commit

Permalink
Add support for identify tool for vector tile layers
Browse files Browse the repository at this point in the history
Also:
- enables saving/loading of layer definition files (.qlr) with vector tile layers.
- makes fields of vector tile layers sorted so they are easier to navigate
  • Loading branch information
wonder-sk committed Apr 15, 2020
1 parent 76872fb commit 59c1ac3
Show file tree
Hide file tree
Showing 11 changed files with 333 additions and 12 deletions.
1 change: 1 addition & 0 deletions python/gui/auto_generated/qgsmaptoolidentify.sip.in
Expand Up @@ -40,6 +40,7 @@ after selecting a point, performs the identification:
VectorLayer,
RasterLayer,
MeshLayer,
VectorTileLayer,
AllLayers
};
typedef QFlags<QgsMapToolIdentify::Type> LayerType;
Expand Down
60 changes: 59 additions & 1 deletion src/app/qgisapp.cpp
Expand Up @@ -14292,7 +14292,65 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer *layer )
break;

case QgsMapLayerType::VectorTileLayer:
// TODO
mActionLocalHistogramStretch->setEnabled( false );
mActionFullHistogramStretch->setEnabled( false );
mActionLocalCumulativeCutStretch->setEnabled( false );
mActionFullCumulativeCutStretch->setEnabled( false );
mActionIncreaseBrightness->setEnabled( false );
mActionDecreaseBrightness->setEnabled( false );
mActionIncreaseContrast->setEnabled( false );
mActionDecreaseContrast->setEnabled( false );
mActionLayerSubsetString->setEnabled( false );
mActionFeatureAction->setEnabled( false );
mActionSelectFeatures->setEnabled( false );
mActionSelectPolygon->setEnabled( false );
mActionSelectFreehand->setEnabled( false );
mActionSelectRadius->setEnabled( false );
mActionZoomActualSize->setEnabled( false );
mActionZoomToLayer->setEnabled( true );
mActionZoomToSelected->setEnabled( false );
mActionOpenTable->setEnabled( false );
mActionSelectAll->setEnabled( false );
mActionReselect->setEnabled( false );
mActionInvertSelection->setEnabled( false );
mActionSelectByExpression->setEnabled( false );
mActionSelectByForm->setEnabled( false );
mActionOpenFieldCalc->setEnabled( false );
mActionToggleEditing->setEnabled( false );
mActionToggleEditing->setChecked( false );
mActionSaveLayerEdits->setEnabled( false );
mUndoDock->widget()->setEnabled( false );
mActionUndo->setEnabled( false );
mActionRedo->setEnabled( false );
mActionSaveLayerDefinition->setEnabled( true );
mActionLayerSaveAs->setEnabled( false );
mActionAddFeature->setEnabled( false );
mActionCircularStringCurvePoint->setEnabled( false );
mActionCircularStringRadius->setEnabled( false );
mActionDeleteSelected->setEnabled( false );
mActionAddRing->setEnabled( false );
mActionFillRing->setEnabled( false );
mActionAddPart->setEnabled( false );
mActionVertexTool->setEnabled( false );
mActionVertexToolActiveLayer->setEnabled( false );
mActionMoveFeature->setEnabled( false );
mActionMoveFeatureCopy->setEnabled( false );
mActionRotateFeature->setEnabled( false );
mActionOffsetCurve->setEnabled( false );
mActionCopyFeatures->setEnabled( false );
mActionCutFeatures->setEnabled( false );
mActionPasteFeatures->setEnabled( false );
mActionRotatePointSymbols->setEnabled( false );
mActionOffsetPointSymbol->setEnabled( false );
mActionDeletePart->setEnabled( false );
mActionDeleteRing->setEnabled( false );
mActionSimplifyFeature->setEnabled( false );
mActionReshapeFeatures->setEnabled( false );
mActionSplitFeatures->setEnabled( false );
mActionSplitParts->setEnabled( false );
mActionLabeling->setEnabled( false );
mActionDiagramProperties->setEnabled( false );
mActionIdentify->setEnabled( true );
break;

case QgsMapLayerType::PluginLayer:
Expand Down
119 changes: 112 additions & 7 deletions src/app/qgsidentifyresultsdialog.cpp
Expand Up @@ -71,6 +71,7 @@
#include "qgsrasterlayer.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsvectortilelayer.h"
#include "qgswebview.h"
#include "qgswebframe.h"
#include "qgsstringutils.h"
Expand Down Expand Up @@ -500,7 +501,7 @@ void QgsIdentifyResultsDialog::addFeature( const QgsMapToolIdentify::IdentifyRes
break;

case QgsMapLayerType::VectorTileLayer:
// TODO
addFeature( qobject_cast<QgsVectorTileLayer *>( result.mLayer ), result.mLabel, result.mFields, result.mFeature, result.mDerivedAttributes );
break;

case QgsMapLayerType::PluginLayer:
Expand Down Expand Up @@ -1108,6 +1109,92 @@ void QgsIdentifyResultsDialog::addFeature( QgsMeshLayer *layer,
}
}

void QgsIdentifyResultsDialog::addFeature( QgsVectorTileLayer *layer,
const QString &label,
const QgsFields &fields,
const QgsFeature &f,
const QMap< QString, QString > &derivedAttributes )
{
QTreeWidgetItem *layItem = layerItem( layer );

if ( !layItem )
{
layItem = new QTreeWidgetItem( QStringList() << layer->name() );
layItem->setData( 0, Qt::UserRole, QVariant::fromValue( qobject_cast<QObject *>( layer ) ) );
lstResults->addTopLevelItem( layItem );
QFont boldFont;
boldFont.setBold( true );
layItem->setFont( 0, boldFont );

connect( layer, &QObject::destroyed, this, &QgsIdentifyResultsDialog::layerDestroyed );
connect( layer, &QgsMapLayer::crsChanged, this, &QgsIdentifyResultsDialog::layerDestroyed );
}

QgsIdentifyResultsFeatureItem *featItem = new QgsIdentifyResultsFeatureItem( fields, f, layer->crs() );
featItem->setText( 0, label );
featItem->setToolTip( 0, label );

featItem->setData( 0, Qt::UserRole, FID_TO_STRING( f.id() ) );
layItem->addChild( featItem );
layItem->setFirstColumnSpanned( true );

QString countSuffix = layItem->childCount() > 1
? QStringLiteral( " [%1]" ).arg( layItem->childCount() )
: QString();
layItem->setText( 0, QStringLiteral( "%1 %2" ).arg( layer->name(), countSuffix ) );

if ( derivedAttributes.size() >= 0 )
{
QgsTreeWidgetItem *derivedItem = new QgsTreeWidgetItem( QStringList() << tr( "(Derived)" ) );
derivedItem->setData( 0, Qt::UserRole, "derived" );
derivedItem->setAlwaysOnTopPriority( 0 );
featItem->addChild( derivedItem );

for ( QMap< QString, QString>::const_iterator it = derivedAttributes.begin(); it != derivedAttributes.end(); ++it )
{
derivedItem->addChild( new QTreeWidgetItem( QStringList() << it.key() << it.value() ) );
}
}

QgsAttributes attrs = f.attributes();
for ( int i = 0; i < attrs.count(); ++i )
{
if ( i >= fields.count() )
break;

if ( attrs.at( i ).isNull() || !attrs.at( i ).isValid() )
continue; // skip attributes that are not present (there can be many of them)

QString value = fields.at( i ).displayString( attrs.at( i ) );
QgsTreeWidgetItem *attrItem = new QgsTreeWidgetItem( QStringList() << QString::number( i ) << value );
featItem->addChild( attrItem );

attrItem->setData( 0, Qt::DisplayRole, fields.at( i ).name() );
attrItem->setData( 0, Qt::UserRole, fields.at( i ).name() );
attrItem->setData( 0, Qt::UserRole + 1, i );

attrItem->setData( 1, Qt::UserRole, value );
attrItem->setSortData( 1, value );
attrItem->setToolTip( 1, value );
bool foundLinks = false;
QString links = QgsStringUtils::insertLinks( value, &foundLinks );
if ( foundLinks )
{
QLabel *valueLabel = new QLabel( links );
valueLabel->setOpenExternalLinks( true );
attrItem->setData( 1, Qt::DisplayRole, QString() );
attrItem->treeWidget()->setItemWidget( attrItem, 1, valueLabel );
}
else
{
attrItem->setData( 1, Qt::DisplayRole, value );
attrItem->treeWidget()->setItemWidget( attrItem, 1, nullptr );
}
}

highlightFeature( featItem );
}

void QgsIdentifyResultsDialog::editingToggled()
{
QTreeWidgetItem *layItem = layerItem( sender() );
Expand Down Expand Up @@ -1236,7 +1323,8 @@ void QgsIdentifyResultsDialog::contextMenuEvent( QContextMenuEvent *event )
QgsMapLayer *layer = vectorLayer( item );
QgsVectorLayer *vlayer = vectorLayer( item );
QgsRasterLayer *rlayer = rasterLayer( item );
if ( !vlayer && !rlayer )
QgsVectorTileLayer *vtlayer = vectorTileLayer( item );
if ( !vlayer && !rlayer && !vtlayer )
{
QgsDebugMsg( QStringLiteral( "Item does not belong to a layer." ) );
return;
Expand All @@ -1262,7 +1350,10 @@ void QgsIdentifyResultsDialog::contextMenuEvent( QContextMenuEvent *event )
{
mActionPopup->addAction( tr( "Zoom to Feature" ), this, &QgsIdentifyResultsDialog::zoomToFeature );
mActionPopup->addAction( tr( "Copy Feature" ), this, &QgsIdentifyResultsDialog::copyFeature );
mActionPopup->addAction( tr( "Toggle Feature Selection" ), this, &QgsIdentifyResultsDialog::toggleFeatureSelection );
if ( vlayer )
{
mActionPopup->addAction( tr( "Toggle Feature Selection" ), this, &QgsIdentifyResultsDialog::toggleFeatureSelection );
}
}

mActionPopup->addAction( tr( "Copy Attribute Value" ), this, &QgsIdentifyResultsDialog::copyAttributeValue );
Expand Down Expand Up @@ -1596,6 +1687,14 @@ QgsMeshLayer *QgsIdentifyResultsDialog::meshLayer( QTreeWidgetItem *item )
return qobject_cast<QgsMeshLayer *>( item->data( 0, Qt::UserRole ).value<QObject *>() );
}

QgsVectorTileLayer *QgsIdentifyResultsDialog::vectorTileLayer( QTreeWidgetItem *item )
{
item = layerItem( item );
if ( !item )
return nullptr;
return qobject_cast<QgsVectorTileLayer *>( item->data( 0, Qt::UserRole ).value<QObject *>() );
}

QTreeWidgetItem *QgsIdentifyResultsDialog::retrieveAttributes( QTreeWidgetItem *item, QgsAttributeMap &attributes, int &idx )
{
QTreeWidgetItem *featItem = featureItem( item );
Expand Down Expand Up @@ -1824,8 +1923,10 @@ void QgsIdentifyResultsDialog::highlightFeature( QTreeWidgetItem *item )
QgsMapLayer *layer = nullptr;
QgsVectorLayer *vlayer = vectorLayer( item );
QgsRasterLayer *rlayer = rasterLayer( item );
QgsVectorTileLayer *vtlayer = vectorTileLayer( item );

layer = vlayer ? static_cast<QgsMapLayer *>( vlayer ) : static_cast<QgsMapLayer *>( rlayer );
layer = layer ? layer : vtlayer;

if ( !layer ) return;

Expand Down Expand Up @@ -1861,14 +1962,17 @@ void QgsIdentifyResultsDialog::zoomToFeature()

QgsVectorLayer *vlayer = vectorLayer( item );
QgsRasterLayer *rlayer = rasterLayer( item );
if ( !vlayer && !rlayer )
QgsVectorTileLayer *vtlayer = vectorTileLayer( item );
if ( !vlayer && !rlayer && !vtlayer )
return;

QgsMapLayer *layer = nullptr;
if ( vlayer )
layer = vlayer;
else
else if ( rlayer )
layer = rlayer;
else
layer = vtlayer;

QgsIdentifyResultsFeatureItem *featItem = dynamic_cast<QgsIdentifyResultsFeatureItem *>( featureItem( item ) );
if ( !featItem )
Expand Down Expand Up @@ -2003,7 +2107,8 @@ void QgsIdentifyResultsDialog::copyFeatureAttributes()

QgsVectorLayer *vlayer = vectorLayer( lstResults->currentItem() );
QgsRasterLayer *rlayer = rasterLayer( lstResults->currentItem() );
if ( !vlayer && !rlayer )
QgsVectorTileLayer *vtlayer = vectorTileLayer( lstResults->currentItem() );
if ( !vlayer && !rlayer && !vtlayer )
{
return;
}
Expand All @@ -2025,7 +2130,7 @@ void QgsIdentifyResultsDialog::copyFeatureAttributes()
text += QStringLiteral( "%1: %2\n" ).arg( fields.at( attrIdx ).name(), it.value().toString() );
}
}
else if ( rlayer )
else if ( rlayer || vtlayer )
{
QTreeWidgetItem *featItem = featureItem( lstResults->currentItem() );
if ( !featItem )
Expand Down
11 changes: 11 additions & 0 deletions src/app/qgsidentifyresultsdialog.h
Expand Up @@ -156,6 +156,16 @@ class APP_EXPORT QgsIdentifyResultsDialog: public QDialog, private Ui::QgsIdenti
const QMap< QString, QString > &attributes,
const QMap< QString, QString > &derivedAttributes );

/**
* Adds results from vector tile layer
* \since QGIS 3.14
*/
void addFeature( QgsVectorTileLayer *layer,
const QString &label,
const QgsFields &fields,
const QgsFeature &feature,
const QMap< QString, QString > &derivedAttributes );

//! Adds feature from identify results
void addFeature( const QgsMapToolIdentify::IdentifyResult &result );

Expand Down Expand Up @@ -275,6 +285,7 @@ class APP_EXPORT QgsIdentifyResultsDialog: public QDialog, private Ui::QgsIdenti
QgsVectorLayer *vectorLayer( QTreeWidgetItem *item );
QgsRasterLayer *rasterLayer( QTreeWidgetItem *item );
QgsMeshLayer *meshLayer( QTreeWidgetItem *item );
QgsVectorTileLayer *vectorTileLayer( QTreeWidgetItem *item );
QTreeWidgetItem *featureItem( QTreeWidgetItem *item );
QTreeWidgetItem *layerItem( QTreeWidgetItem *item );
QTreeWidgetItem *layerItem( QObject *layer );
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgslayerdefinition.cpp
Expand Up @@ -28,6 +28,7 @@
#include "qgsrasterlayer.h"
#include "qgsreadwritecontext.h"
#include "qgsvectorlayer.h"
#include "qgsvectortilelayer.h"
#include "qgsapplication.h"

bool QgsLayerDefinition::loadLayerDefinition( const QString &path, QgsProject *project, QgsLayerTreeGroup *rootGroup, QString &errorMessage )
Expand Down Expand Up @@ -293,6 +294,10 @@ QList<QgsMapLayer *> QgsLayerDefinition::loadLayerDefinitionLayers( QDomDocument
{
layer = new QgsRasterLayer;
}
else if ( type == QLatin1String( "vector-tile" ) )
{
layer = new QgsVectorTileLayer;
}
else if ( type == QLatin1String( "plugin" ) )
{
QString typeName = layerElem.attribute( QStringLiteral( "name" ) );
Expand Down
4 changes: 4 additions & 0 deletions src/core/vectortile/qgsvectortilemvtdecoder.cpp
Expand Up @@ -48,6 +48,10 @@ inline bool _isExteriorRing( const QVector<QgsPoint> &pts )
}


QgsVectorTileMVTDecoder::QgsVectorTileMVTDecoder() = default;

QgsVectorTileMVTDecoder::~QgsVectorTileMVTDecoder() = default;

bool QgsVectorTileMVTDecoder::decode( QgsTileXYZ tileID, const QByteArray &rawTileData )
{
if ( !tile.ParseFromArray( rawTileData.constData(), rawTileData.count() ) )
Expand Down
4 changes: 3 additions & 1 deletion src/core/vectortile/qgsvectortilemvtdecoder.h
Expand Up @@ -33,9 +33,11 @@ class QgsFeature;
*
* \since QGIS 3.14
*/
class QgsVectorTileMVTDecoder
class CORE_EXPORT QgsVectorTileMVTDecoder
{
public:
QgsVectorTileMVTDecoder();
~QgsVectorTileMVTDecoder();

//! Tries to decode raw tile data, returns true on success
bool decode( QgsTileXYZ tileID, const QByteArray &rawTileData );
Expand Down
4 changes: 3 additions & 1 deletion src/core/vectortile/qgsvectortileutils.cpp
Expand Up @@ -51,7 +51,9 @@ QPolygon QgsVectorTileUtils::tilePolygon( QgsTileXYZ id, const QgsCoordinateTran
QgsFields QgsVectorTileUtils::makeQgisFields( QSet<QString> flds )
{
QgsFields fields;
for ( QString fieldName : flds )
QStringList fieldsSorted = flds.toList();
std::sort( fieldsSorted.begin(), fieldsSorted.end() );
for ( QString fieldName : qgis::as_const( fieldsSorted ) )
{
fields.append( QgsField( fieldName, QVariant::String ) );
}
Expand Down
4 changes: 3 additions & 1 deletion src/core/vectortile/qgsvectortileutils.h
Expand Up @@ -16,6 +16,8 @@
#ifndef QGSVECTORTILEUTILS_H
#define QGSVECTORTILEUTILS_H

#include "qgis_core.h"

#define SIP_NO_FILE

#include <QSet>
Expand All @@ -40,7 +42,7 @@ class QgsVectorTileLayer;
*
* \since QGIS 3.14
*/
class QgsVectorTileUtils
class CORE_EXPORT QgsVectorTileUtils
{
public:

Expand Down

0 comments on commit 59c1ac3

Please sign in to comment.