From 5b278d746ecb58b15e7ce26895bde9ea532b3964 Mon Sep 17 00:00:00 2001 From: Blottiere Paul Date: Fri, 1 Sep 2017 09:47:05 +0100 Subject: [PATCH] Move/rotate/hide/pin map tools are always available --- python/core/qgsauxiliarystorage.sip | 26 ++++ python/core/qgsrulebasedlabeling.sip | 11 ++ python/core/qgsvectorlayer.sip | 4 +- python/core/qgsvectorlayerlabeling.sip | 21 +++ src/app/qgisapp.cpp | 36 +---- src/app/qgsmaptoollabel.cpp | 119 ++++++++++------ src/app/qgsmaptoollabel.h | 13 ++ src/app/qgsmaptoolmovelabel.cpp | 31 ++++- src/app/qgsmaptoolpinlabels.cpp | 9 +- src/app/qgsmaptoolrotatelabel.cpp | 9 ++ src/app/qgsmaptoolshowhidelabels.cpp | 155 +++++++++++---------- src/app/qgsmaptoolshowhidelabels.h | 3 +- src/core/qgsauxiliarystorage.cpp | 58 +++++++- src/core/qgsauxiliarystorage.h | 26 ++++ src/core/qgsrulebasedlabeling.cpp | 24 ++++ src/core/qgsrulebasedlabeling.h | 21 +++ src/core/qgsvectorlayer.h | 8 +- src/core/qgsvectorlayerdiagramprovider.cpp | 2 +- src/core/qgsvectorlayerlabeling.cpp | 10 ++ src/core/qgsvectorlayerlabeling.h | 21 +++ 20 files changed, 444 insertions(+), 163 deletions(-) diff --git a/python/core/qgsauxiliarystorage.sip b/python/core/qgsauxiliarystorage.sip index 8e19f96356e..89fafabb122 100644 --- a/python/core/qgsauxiliarystorage.sip +++ b/python/core/qgsauxiliarystorage.sip @@ -179,6 +179,32 @@ class QgsAuxiliaryLayer : QgsVectorLayer :rtype: bool %End + static int createProperty( QgsPalLayerSettings::Property p, const QString &providerId, QgsVectorLayer *vlayer ); +%Docstring + Create if necessary a new auxiliary field for a PAL property and + activate this property in settings. + + \param p The property to create + \param providerId The id of the provider to use + \param vlayer The vector layer + + :return: The index of the auxiliary field or -1 + :rtype: int +%End + + static int createProperty( QgsDiagramLayerSettings::Property p, QgsVectorLayer *vlayer ); +%Docstring + Create if necessary a new auxiliary field for a diagram's property and + activate this this property in settings. + + \param p The property to create + \param providerId The id of the provider to use + \param vlayer The vector layer + + :return: The index of the auxiliary field or -1 + :rtype: int +%End + }; diff --git a/python/core/qgsrulebasedlabeling.sip b/python/core/qgsrulebasedlabeling.sip index d5876aa7d09..372462c7276 100644 --- a/python/core/qgsrulebasedlabeling.sip +++ b/python/core/qgsrulebasedlabeling.sip @@ -223,6 +223,7 @@ Try to find a rule given its unique key :rtype: QgsRuleBasedLabeling.Rule %End + QgsRuleBasedLabeling::Rule *clone() const /Factory/; %Docstring clone this rule, return new instance @@ -285,6 +286,16 @@ Create the instance from a DOM element with saved configuration virtual QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context ) const; virtual QStringList subProviders() const; virtual QgsPalLayerSettings settings( const QString &providerId = QString() ) const; + + virtual void setSettings( QgsPalLayerSettings *settings /Transfer/, const QString &providerId = QString() ); +%Docstring + Set pal settings for a specific provider (takes ownership). + + \param settings Pal layer settings + \param providerId The id of the provider + +.. versionadded:: 3.0 +%End virtual bool requiresAdvancedEffects() const; diff --git a/python/core/qgsvectorlayer.sip b/python/core/qgsvectorlayer.sip index 6e50eef1c94..0447733bd84 100644 --- a/python/core/qgsvectorlayer.sip +++ b/python/core/qgsvectorlayer.sip @@ -1092,9 +1092,11 @@ Return the provider type for this layer :rtype: int %End - const QgsAbstractVectorLayerLabeling *labeling() const; + + QgsAbstractVectorLayerLabeling *labeling(); %Docstring Access to labeling configuration. May be null if labeling is not used. + .. versionadded:: 3.0 :rtype: QgsAbstractVectorLayerLabeling %End diff --git a/python/core/qgsvectorlayerlabeling.sip b/python/core/qgsvectorlayerlabeling.sip index f733f081c71..eeef3c6cf08 100644 --- a/python/core/qgsvectorlayerlabeling.sip +++ b/python/core/qgsvectorlayerlabeling.sip @@ -61,6 +61,16 @@ Get list of sub-providers within the layer's labeling. :rtype: QgsPalLayerSettings %End + virtual void setSettings( QgsPalLayerSettings *settings /Transfer/, const QString &providerId = QString() ) = 0; +%Docstring + Set pal settings for a specific provider (takes ownership). + + \param settings Pal layer settings + \param providerId The id of the provider + +.. versionadded:: 3.0 +%End + virtual bool requiresAdvancedEffects() const = 0; %Docstring Returns true if drawing labels requires advanced effects like composition @@ -109,6 +119,17 @@ Constructs simple labeling configuration with given initial settings virtual QgsAbstractVectorLayerLabeling *clone() const /Factory/; virtual QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context ) const; virtual QgsPalLayerSettings settings( const QString &providerId = QString() ) const; + + virtual void setSettings( QgsPalLayerSettings *settings /Transfer/, const QString &providerId = QString() ); +%Docstring + Set pal settings (takes ownership). + + \param settings Pal layer settings + \param providerId Unused parameter + +.. versionadded:: 3.0 +%End + virtual bool requiresAdvancedEffects() const; virtual void toSld( QDomNode &parent, const QgsStringMap &props ) const; diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index cb631989be4..32db19d4fc7 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -10997,38 +10997,16 @@ void QgisApp::updateLabelToolButtons() for ( QMap::iterator it = layers.begin(); it != layers.end(); ++it ) { QgsVectorLayer *vlayer = qobject_cast( it.value() ); - if ( !vlayer || ( !vlayer->diagramsEnabled() && !vlayer->labelsEnabled() ) ) - continue; - - int colX, colY, colShow, colAng; - enablePin = - enablePin || - ( qobject_cast( mMapTools.mPinLabels ) && - ( qobject_cast( mMapTools.mPinLabels )->labelMoveable( vlayer, colX, colY ) - || qobject_cast( mMapTools.mPinLabels )->diagramMoveable( vlayer, colX, colY ) ) ); - - enableShowHide = - enableShowHide || - ( qobject_cast( mMapTools.mShowHideLabels ) && - ( qobject_cast( mMapTools.mShowHideLabels )->labelCanShowHide( vlayer, colShow ) - || qobject_cast( mMapTools.mShowHideLabels )->diagramCanShowHide( vlayer, colShow ) ) ); - - enableMove = - enableMove || - ( qobject_cast( mMapTools.mMoveLabel ) && - ( qobject_cast( mMapTools.mMoveLabel )->labelMoveable( vlayer, colX, colY ) - || qobject_cast( mMapTools.mMoveLabel )->diagramMoveable( vlayer, colX, colY ) ) ); - - enableRotate = - enableRotate || - ( qobject_cast( mMapTools.mRotateLabel ) && - qobject_cast( mMapTools.mRotateLabel )->layerIsRotatable( vlayer, colAng ) ); - - if ( vlayer->isEditable() ) + if ( vlayer && ( vlayer->diagramsEnabled() || vlayer->labelsEnabled() ) ) + { + enablePin = true; + enableShowHide = true; + enableMove = true; + enableRotate = true; enableChange = true; - if ( enablePin && enableShowHide && enableMove && enableRotate && enableChange ) break; + } } mActionPinLabels->setEnabled( enablePin ); diff --git a/src/app/qgsmaptoollabel.cpp b/src/app/qgsmaptoollabel.cpp index 4aa0494a823..271172b9282 100644 --- a/src/app/qgsmaptoollabel.cpp +++ b/src/app/qgsmaptoollabel.cpp @@ -626,7 +626,7 @@ bool QgsMapToolLabel::diagramMoveable( QgsVectorLayer *vlayer, int &xCol, int &y bool QgsMapToolLabel::labelMoveable( QgsVectorLayer *vlayer, int &xCol, int &yCol ) const { - if ( !vlayer || !vlayer->labeling() ) + if ( !vlayer || !vlayer->isEditable() || !vlayer->labeling() ) { return false; } @@ -648,26 +648,7 @@ bool QgsMapToolLabel::labelMoveable( QgsVectorLayer *vlayer, const QgsPalLayerSe //return !xColName.isEmpty() && !yColName.isEmpty(); xCol = vlayer->fields().lookupField( xColName ); yCol = vlayer->fields().lookupField( yColName ); - - // labels may be moveable even if layer is not editable when data defined - // columns come from auxiliary storage - if ( xCol >= 0 && yCol >= 0 ) - { - bool xAuxiliaryField = vlayer->isAuxiliaryField( xCol ); - bool yAuxiliaryField = vlayer->isAuxiliaryField( yCol ); - - if ( ! xAuxiliaryField || ! yAuxiliaryField ) - { - if ( vlayer->isEditable() ) - return true; - else - return false; - } - else - return true; - } - - return false; + return ( xCol != -1 && yCol != -1 ); } bool QgsMapToolLabel::layerCanPin( QgsVectorLayer *vlayer, int &xCol, int &yCol ) const @@ -679,7 +660,7 @@ bool QgsMapToolLabel::layerCanPin( QgsVectorLayer *vlayer, int &xCol, int &yCol bool QgsMapToolLabel::labelCanShowHide( QgsVectorLayer *vlayer, int &showCol ) const { - if ( !vlayer || !vlayer->labeling() ) + if ( !vlayer || !vlayer->isEditable() || !vlayer->labeling() ) { return false; } @@ -689,20 +670,8 @@ bool QgsMapToolLabel::labelCanShowHide( QgsVectorLayer *vlayer, int &showCol ) c QString fieldname = dataDefinedColumnName( QgsPalLayerSettings::Show, vlayer->labeling()->settings( providerId ) ); showCol = vlayer->fields().lookupField( fieldname ); - if ( showCol >= 0 ) - { - bool auxiliaryField = vlayer->isAuxiliaryField( showCol ); - - if ( ! auxiliaryField ) - { - if ( vlayer->isEditable() ) - return true; - else - return false; - } - else - return true; - } + if ( showCol != -1 ) + return true; } return false; @@ -773,14 +742,14 @@ QgsMapToolLabel::LabelDetails::LabelDetails( const QgsLabelPosition &p ) : pos( p ) { layer = qobject_cast( QgsProject::instance()->mapLayer( pos.layerID ) ); - if ( layer && layer->labeling() ) + if ( layer && layer->labeling() && !p.isDiagram ) { settings = layer->labeling()->settings( pos.providerID ); - - if ( p.isDiagram ) - valid = layer->diagramsEnabled(); - else - valid = true; + valid = true; + } + else if ( layer && layer->diagramsEnabled() && p.isDiagram ) + { + valid = true; } if ( !valid ) @@ -789,3 +758,69 @@ QgsMapToolLabel::LabelDetails::LabelDetails( const QgsLabelPosition &p ) settings = QgsPalLayerSettings(); } } + +bool QgsMapToolLabel::createAuxiliaryFields( QgsPalIndexes &indexes ) +{ + return createAuxiliaryFields( mCurrentLabel, indexes ); +} + +bool QgsMapToolLabel::createAuxiliaryFields( LabelDetails &details, QgsPalIndexes &indexes ) const +{ + bool newAuxiliaryLayer = false; + QgsVectorLayer *vlayer = details.layer; + QString providerId = details.pos.providerID; + + if ( !vlayer ) + return newAuxiliaryLayer; + + if ( !vlayer->auxiliaryLayer() ) + { + QgsNewAuxiliaryLayerDialog dlg( vlayer ); + dlg.exec(); + newAuxiliaryLayer = true; + } + + if ( !vlayer->auxiliaryLayer() ) + return false; + + Q_FOREACH ( const QgsPalLayerSettings::Property &p, mPalProperties ) + { + indexes[p] = QgsAuxiliaryLayer::createProperty( p, providerId, vlayer ); + } + + details.settings = vlayer->labeling()->settings( providerId ); + + return newAuxiliaryLayer; +} + +bool QgsMapToolLabel::createAuxiliaryFields( QgsDiagramIndexes &indexes ) +{ + return createAuxiliaryFields( mCurrentLabel, indexes ); +} + + +bool QgsMapToolLabel::createAuxiliaryFields( LabelDetails &details, QgsDiagramIndexes &indexes ) +{ + bool newAuxiliaryLayer = false; + QgsVectorLayer *vlayer = details.layer; + + if ( !vlayer ) + return newAuxiliaryLayer; + + if ( !vlayer->auxiliaryLayer() ) + { + QgsNewAuxiliaryLayerDialog dlg( vlayer ); + dlg.exec(); + newAuxiliaryLayer = true; + } + + if ( !vlayer->auxiliaryLayer() ) + return false; + + Q_FOREACH ( const QgsDiagramLayerSettings::Property &p, mDiagramProperties ) + { + indexes[p] = QgsAuxiliaryLayer::createProperty( p, vlayer ); + } + + return newAuxiliaryLayer; +} diff --git a/src/app/qgsmaptoollabel.h b/src/app/qgsmaptoollabel.h index 055ce2bea25..72f3d1eea32 100644 --- a/src/app/qgsmaptoollabel.h +++ b/src/app/qgsmaptoollabel.h @@ -20,10 +20,15 @@ #include "qgsmaptool.h" #include "qgspallabeling.h" +#include "qgsnewauxiliarylayerdialog.h" +#include "qgsauxiliarystorage.h" #include "qgis_app.h" class QgsRubberBand; +typedef QMap QgsPalIndexes; +typedef QMap QgsDiagramIndexes; + //! Base class for map tools that modify label properties class APP_EXPORT QgsMapToolLabel: public QgsMapTool { @@ -175,6 +180,14 @@ class APP_EXPORT QgsMapToolLabel: public QgsMapTool \since QGIS 2.16 */ bool isPinned(); + + bool createAuxiliaryFields( QgsPalIndexes &palIndexes ); + bool createAuxiliaryFields( LabelDetails &details, QgsPalIndexes &palIndexes ) const; + bool createAuxiliaryFields( QgsDiagramIndexes &diagIndexes ); + bool createAuxiliaryFields( LabelDetails &details, QgsDiagramIndexes &diagIndexes ); + + QList mPalProperties; + QList mDiagramProperties; }; #endif // QGSMAPTOOLLABEL_H diff --git a/src/app/qgsmaptoolmovelabel.cpp b/src/app/qgsmaptoolmovelabel.cpp index 7353df64fff..330c0e65c25 100644 --- a/src/app/qgsmaptoolmovelabel.cpp +++ b/src/app/qgsmaptoolmovelabel.cpp @@ -27,6 +27,12 @@ QgsMapToolMoveLabel::QgsMapToolMoveLabel( QgsMapCanvas *canvas ) , mClickOffsetY( 0 ) { mToolName = tr( "Move label" ); + + mPalProperties << QgsPalLayerSettings::PositionX; + mPalProperties << QgsPalLayerSettings::PositionY; + + mDiagramProperties << QgsDiagramLayerSettings::PositionX; + mDiagramProperties << QgsDiagramLayerSettings::PositionY; } void QgsMapToolMoveLabel::canvasPressEvent( QgsMapMouseEvent *e ) @@ -49,8 +55,29 @@ void QgsMapToolMoveLabel::canvasPressEvent( QgsMapMouseEvent *e ) } int xCol, yCol; - if ( labelMoveable( vlayer, mCurrentLabel.settings, xCol, yCol ) || - diagramMoveable( vlayer, xCol, yCol ) ) + + if ( !mCurrentLabel.pos.isDiagram && !labelMoveable( vlayer, mCurrentLabel.settings, xCol, yCol ) ) + { + QgsPalIndexes indexes; + + if ( createAuxiliaryFields( indexes ) ) + return; + + xCol = indexes[ QgsPalLayerSettings::PositionX ]; + yCol = indexes[ QgsPalLayerSettings::PositionY ]; + } + else if ( mCurrentLabel.pos.isDiagram && !diagramMoveable( vlayer, xCol, yCol ) ) + { + QgsDiagramIndexes indexes; + + if ( createAuxiliaryFields( indexes ) ) + return; + + xCol = indexes[ QgsDiagramLayerSettings::PositionX ]; + yCol = indexes[ QgsDiagramLayerSettings::PositionY ]; + } + + if ( xCol >= 0 && yCol >= 0 ) { mStartPointMapCoords = toMapCoordinates( e->pos() ); QgsPointXY referencePoint; diff --git a/src/app/qgsmaptoolpinlabels.cpp b/src/app/qgsmaptoolpinlabels.cpp index 256ae4ea3ab..c8e2f1f532f 100644 --- a/src/app/qgsmaptoolpinlabels.cpp +++ b/src/app/qgsmaptoolpinlabels.cpp @@ -260,13 +260,6 @@ void QgsMapToolPinLabels::pinUnpinLabels( const QgsRectangle &ext, QMouseEvent * continue; } - QgsVectorLayer *vlayer = mCurrentLabel.layer; - if ( !vlayer->isEditable() ) - { - QgsDebugMsg( QString( "Vector layer not editable, skipping label" ) ); - continue; - } - // unpin label if ( isPinned() && ( doUnpin || toggleUnpinOrPin ) ) { @@ -297,7 +290,7 @@ void QgsMapToolPinLabels::pinUnpinLabels( const QgsRectangle &ext, QMouseEvent * if ( labelChanged ) { - mCanvas->refresh(); + mCurrentLabel.layer->triggerRepaint(); if ( !mShowPinned ) { diff --git a/src/app/qgsmaptoolrotatelabel.cpp b/src/app/qgsmaptoolrotatelabel.cpp index 93865933ee3..6307c507470 100644 --- a/src/app/qgsmaptoolrotatelabel.cpp +++ b/src/app/qgsmaptoolrotatelabel.cpp @@ -33,6 +33,7 @@ QgsMapToolRotateLabel::QgsMapToolRotateLabel( QgsMapCanvas *canvas ) , mCurrentMouseAzimuth( 0.0 ) , mCtrlPressed( false ) { + mPalProperties << QgsPalLayerSettings::LabelRotation; } QgsMapToolRotateLabel::~QgsMapToolRotateLabel() @@ -76,6 +77,14 @@ void QgsMapToolRotateLabel::canvasPressEvent( QgsMapMouseEvent *e ) bool hasRotationValue; int rotationCol; + + if ( !labelIsRotatable( mCurrentLabel.layer, mCurrentLabel.settings, rotationCol ) ) + { + QgsPalIndexes indexes; + if ( createAuxiliaryFields( indexes ) ) + return; + } + if ( currentLabelDataDefinedRotation( mCurrentRotation, hasRotationValue, rotationCol, true ) ) { if ( !hasRotationValue ) diff --git a/src/app/qgsmaptoolshowhidelabels.cpp b/src/app/qgsmaptoolshowhidelabels.cpp index 85fba5fa802..3bf64a15a3c 100644 --- a/src/app/qgsmaptoolshowhidelabels.cpp +++ b/src/app/qgsmaptoolshowhidelabels.cpp @@ -35,6 +35,9 @@ QgsMapToolShowHideLabels::QgsMapToolShowHideLabels( QgsMapCanvas *canvas ) { mToolName = tr( "Show/hide labels" ); mRubberBand = nullptr; + + mPalProperties << QgsPalLayerSettings::Show; + mDiagramProperties << QgsDiagramLayerSettings::Show; } QgsMapToolShowHideLabels::~QgsMapToolShowHideLabels() @@ -45,6 +48,24 @@ QgsMapToolShowHideLabels::~QgsMapToolShowHideLabels() void QgsMapToolShowHideLabels::canvasPressEvent( QgsMapMouseEvent *e ) { Q_UNUSED( e ); + + QgsMapLayer *layer = mCanvas->currentLayer(); + QgsVectorLayer *vlayer = dynamic_cast( layer ); + if ( !vlayer ) + return; + + int showCol; + if ( !labelCanShowHide( vlayer, showCol ) + || !diagramCanShowHide( vlayer, showCol ) ) + { + if ( !vlayer->auxiliaryLayer() ) + { + QgsNewAuxiliaryLayerDialog dlg( vlayer ); + dlg.exec(); + return; + } + } + mSelectRect.setRect( 0, 0, 0, 0 ); mSelectRect.setTopLeft( e->pos() ); mSelectRect.setBottomRight( e->pos() ); @@ -107,67 +128,46 @@ void QgsMapToolShowHideLabels::canvasReleaseEvent( QgsMapMouseEvent *e ) void QgsMapToolShowHideLabels::showHideLabels( QMouseEvent *e ) { QgsMapLayer *layer = mCanvas->currentLayer(); - QgsVectorLayer *vlayer = dynamic_cast( layer ); if ( !vlayer ) - { - QgsDebugMsg( "Failed to cast label layer to vector layer" ); return; - } bool doHide = e->modifiers() & Qt::ShiftModifier; - bool labelChanged = false; QString editTxt = doHide ? tr( "Hid labels" ) : tr( "Showed labels" ); vlayer->beginEditCommand( editTxt ); - if ( !doHide ) + bool labelChanged = false; + if ( doHide ) { - QgsDebugMsg( "Showing labels operation" ); - - QgsFeatureIds selectedFeatIds; - if ( !selectedFeatures( vlayer, selectedFeatIds ) ) - { - vlayer->destroyEditCommand(); - return; - } - - QgsDebugMsg( "Number of selected labels or features: " + QString::number( selectedFeatIds.size() ) ); - - if ( selectedFeatIds.isEmpty() ) - { - vlayer->destroyEditCommand(); - return; - } - - Q_FOREACH ( QgsFeatureId fid, selectedFeatIds ) - { - mCurrentLabel.pos.featureId = fid; - - mCurrentLabel.pos.isDiagram = false; - bool labChanged = showHide( vlayer, true ); - - mCurrentLabel.pos.isDiagram = true; - bool diagChanged = showHide( vlayer, true ); - - if ( labChanged || diagChanged ) - { - // TODO: highlight features (maybe with QTimer?) - labelChanged = true; - } - } - } - else - { - QgsDebugMsg( "Hiding labels operation" ); - QList positions; if ( selectedLabelFeatures( vlayer, positions ) ) { Q_FOREACH ( const QgsLabelPosition &pos, positions ) { - mCurrentLabel.pos = pos; + if ( showHide( pos, false ) ) + labelChanged = true; + } + } + } + else + { + QgsFeatureIds fids; + if ( selectedFeatures( vlayer, fids ) ) + { + Q_FOREACH ( QgsFeatureId fid, fids ) + { + QgsLabelPosition pos; + pos.featureId = fid; + pos.layerID = vlayer->id(); - if ( showHide( vlayer, false ) ) + // we want to show labels... + pos.isDiagram = false; + if ( showHide( pos, true ) ) + labelChanged = true; + + // ... and diagrams + pos.isDiagram = true; + if ( showHide( pos, true ) ) labelChanged = true; } } @@ -269,42 +269,45 @@ bool QgsMapToolShowHideLabels::selectedLabelFeatures( QgsVectorLayer *vlayer, return true; } -bool QgsMapToolShowHideLabels::showHide( QgsVectorLayer *vl, const bool show ) +bool QgsMapToolShowHideLabels::showHide( const QgsLabelPosition &pos, bool show ) { - // verify attribute table has proper field setup - bool showSuccess; - int showCol; - int showVal; + LabelDetails details = LabelDetails( pos ); - if ( !dataDefinedShowHide( vl, mCurrentLabel.pos.featureId, showVal, - showSuccess, showCol ) ) - { + if ( !details.valid ) return false; + + QgsVectorLayer *vlayer = details.layer; + if ( !vlayer ) + return false; + + int showCol = -1; + if ( pos.isDiagram ) + { + if ( !diagramCanShowHide( vlayer, showCol ) ) + { + QgsDiagramIndexes indexes; + createAuxiliaryFields( details, indexes ); + + showCol = indexes[ QgsDiagramLayerSettings::Show ]; + } + } + else + { + if ( !labelCanShowHide( vlayer, showCol ) ) + { + QgsPalIndexes indexes; + createAuxiliaryFields( details, indexes ); + + showCol = indexes[ QgsPalLayerSettings::Show ]; + } } - // we need to pass int value to the provider - // (committing bool value would fail on int field) - int curVal = show ? 1 : 0; - - // check if attribute value is already the same - if ( showSuccess && showVal == curVal ) + if ( showCol >= 0 ) { - return false; + int showVal = show ? 1 : 0; + vlayer->changeAttributeValue( pos.featureId, showCol, showVal ); + return true; } - // allow NULL (maybe default) value to stand for show label (i.e. 1) - // skip NULL attributes if trying to show label - if ( !showSuccess && curVal == 1 ) - { - return false; - } - - // different attribute value, edit table - if ( ! vl->changeAttributeValue( mCurrentLabel.pos.featureId, showCol, curVal ) ) - { - QgsDebugMsg( "Failed write to attribute table" ); - return false; - } - - return true; + return false; } diff --git a/src/app/qgsmaptoolshowhidelabels.h b/src/app/qgsmaptoolshowhidelabels.h index 14346e147a9..0f8ffd53dc7 100644 --- a/src/app/qgsmaptoolshowhidelabels.h +++ b/src/app/qgsmaptoolshowhidelabels.h @@ -64,8 +64,7 @@ class APP_EXPORT QgsMapToolShowHideLabels : public QgsMapToolLabel bool selectedLabelFeatures( QgsVectorLayer *vlayer, QList &listPos ); - //! Show label or diagram with feature ID - bool showHide( QgsVectorLayer *vl, const bool show ); + bool showHide( const QgsLabelPosition &pos, bool show ); }; #endif // QGSMAPTOOLSHOWHIDELABELS_H diff --git a/src/core/qgsauxiliarystorage.cpp b/src/core/qgsauxiliarystorage.cpp index 335de12cda1..a53dc4776af 100644 --- a/src/core/qgsauxiliarystorage.cpp +++ b/src/core/qgsauxiliarystorage.cpp @@ -19,7 +19,7 @@ #include "qgslogger.h" #include "qgsslconnect.h" #include "qgsproject.h" -#include "qgspallabeling.h" +#include "qgsvectorlayerlabeling.h" #include "qgsdiagramrenderer.h" #include "qgsmemoryproviderutils.h" @@ -241,6 +241,62 @@ bool QgsAuxiliaryLayer::save() return rc; } +int QgsAuxiliaryLayer::createProperty( QgsPalLayerSettings::Property p, const QString &providerId, QgsVectorLayer *layer ) +{ + int index = -1; + + if ( layer && layer->labeling() && layer->auxiliaryLayer() ) + { + const QgsPropertyDefinition def = layer->labeling()->settings( providerId ).propertyDefinitions()[p]; + const QString fieldName = QgsAuxiliaryField::nameFromProperty( def, true ); + + if ( layer->auxiliaryLayer()->addAuxiliaryField( def ) ) + { + const QgsProperty prop = QgsProperty::fromField( fieldName ); + + QgsPalLayerSettings *settings = new QgsPalLayerSettings( layer->labeling()->settings( providerId ) ); + + QgsPropertyCollection c = settings->dataDefinedProperties(); + c.setProperty( p, prop ); + settings->setDataDefinedProperties( c ); + + layer->labeling()->setSettings( settings, providerId ); + } + + index = layer->fields().lookupField( fieldName ); + } + + return index; +} + +int QgsAuxiliaryLayer::createProperty( QgsDiagramLayerSettings::Property p, QgsVectorLayer *layer ) +{ + int index = -1; + + if ( layer && layer->diagramLayerSettings() && layer->auxiliaryLayer() ) + { + const QgsPropertyDefinition def = layer->diagramLayerSettings()->propertyDefinitions()[p]; + + if ( layer->auxiliaryLayer()->addAuxiliaryField( def ) ) + { + const QString fieldName = QgsAuxiliaryField::nameFromProperty( def, true ); + const QgsProperty prop = QgsProperty::fromField( fieldName ); + + QgsDiagramLayerSettings settings( *layer->diagramLayerSettings() ); + + QgsPropertyCollection c = settings.dataDefinedProperties(); + c.setProperty( p, prop ); + settings.setDataDefinedProperties( c ); + + layer->setDiagramLayerSettings( settings ); + + index = layer->fields().lookupField( fieldName ); + } + } + + return index; +} + // // QgsAuxiliaryStorage // diff --git a/src/core/qgsauxiliarystorage.h b/src/core/qgsauxiliarystorage.h index 877423b7af3..daffca9d5b7 100644 --- a/src/core/qgsauxiliarystorage.h +++ b/src/core/qgsauxiliarystorage.h @@ -20,6 +20,8 @@ #include "qgis_core.h" #include "qgsdatasourceuri.h" +#include "qgspallabeling.h" +#include "qgsdiagramrenderer.h" #include "qgsvectorlayerjoininfo.h" #include "qgsproperty.h" @@ -197,6 +199,30 @@ class CORE_EXPORT QgsAuxiliaryLayer : public QgsVectorLayer */ virtual bool deleteAttribute( int attr ) override; + /** + * Create if necessary a new auxiliary field for a PAL property and + * activate this property in settings. + * + * \param p The property to create + * \param providerId The id of the provider to use + * \param vlayer The vector layer + * + * \returns The index of the auxiliary field or -1 + */ + static int createProperty( QgsPalLayerSettings::Property p, const QString &providerId, QgsVectorLayer *vlayer ); + + /** + * Create if necessary a new auxiliary field for a diagram's property and + * activate this this property in settings. + * + * \param p The property to create + * \param providerId The id of the provider to use + * \param vlayer The vector layer + * + * \returns The index of the auxiliary field or -1 + */ + static int createProperty( QgsDiagramLayerSettings::Property p, QgsVectorLayer *vlayer ); + private: QgsVectorLayerJoinInfo mJoinInfo; const QgsVectorLayer *mLayer = nullptr; diff --git a/src/core/qgsrulebasedlabeling.cpp b/src/core/qgsrulebasedlabeling.cpp index 3a074bf12e8..ce0963fea51 100644 --- a/src/core/qgsrulebasedlabeling.cpp +++ b/src/core/qgsrulebasedlabeling.cpp @@ -177,6 +177,20 @@ const QgsRuleBasedLabeling::Rule *QgsRuleBasedLabeling::Rule::findRuleByKey( con return nullptr; } +QgsRuleBasedLabeling::Rule *QgsRuleBasedLabeling::Rule::findRuleByKey( const QString &key ) +{ + if ( key == mRuleKey ) + return this; + + Q_FOREACH ( Rule *rule, mChildren ) + { + Rule *r = rule->findRuleByKey( key ); + if ( r ) + return r; + } + return nullptr; +} + QgsRuleBasedLabeling::Rule *QgsRuleBasedLabeling::Rule::clone() const { QgsPalLayerSettings *s = mSettings ? new QgsPalLayerSettings( *mSettings ) : nullptr; @@ -451,3 +465,13 @@ bool QgsRuleBasedLabeling::requiresAdvancedEffects() const { return mRootRule->requiresAdvancedEffects(); } + +void QgsRuleBasedLabeling::setSettings( QgsPalLayerSettings *settings, const QString &providerId ) +{ + if ( settings ) + { + Rule *rule = mRootRule->findRuleByKey( providerId ); + if ( rule && rule->settings() ) + return rule->setSettings( settings ); + } +} diff --git a/src/core/qgsrulebasedlabeling.h b/src/core/qgsrulebasedlabeling.h index 345b11fbc05..5ec565d50b6 100644 --- a/src/core/qgsrulebasedlabeling.h +++ b/src/core/qgsrulebasedlabeling.h @@ -231,6 +231,17 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling //! Try to find a rule given its unique key const QgsRuleBasedLabeling::Rule *findRuleByKey( const QString &key ) const; + /** + * Find a labeling rule thanks to its key. + * + * \param key The key of the rule to find + * + * \returns The rule or a nullptr if not found + * + * \since QGIS 3.0 + */ + QgsRuleBasedLabeling::Rule *findRuleByKey( const QString &key ) SIP_SKIP; + //! clone this rule, return new instance QgsRuleBasedLabeling::Rule *clone() const SIP_FACTORY; @@ -350,6 +361,16 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling virtual QgsVectorLayerLabelProvider *provider( QgsVectorLayer *layer ) const override SIP_SKIP; virtual QStringList subProviders() const override; virtual QgsPalLayerSettings settings( const QString &providerId = QString() ) const override; + + /** + * Set pal settings for a specific provider (takes ownership). + * + * \param settings Pal layer settings + * \param providerId The id of the provider + * + * \since QGIS 3.0 + */ + virtual void setSettings( QgsPalLayerSettings *settings SIP_TRANSFER, const QString &providerId = QString() ) override; bool requiresAdvancedEffects() const override; protected: diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h index 0f46e68014d..89d38a99eca 100644 --- a/src/core/qgsvectorlayer.h +++ b/src/core/qgsvectorlayer.h @@ -1133,11 +1133,17 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte */ int addTopologicalPoints( const QgsPointXY &p ); + /** + * Access to const labeling configuration. May be null if labeling is not used. + * \since QGIS 3.0 + */ + const QgsAbstractVectorLayerLabeling *labeling() const SIP_SKIP { return mLabeling; } + /** * Access to labeling configuration. May be null if labeling is not used. * \since QGIS 3.0 */ - const QgsAbstractVectorLayerLabeling *labeling() const { return mLabeling; } + QgsAbstractVectorLayerLabeling *labeling() { return mLabeling; } /** * Set labeling configuration. Takes ownership of the object. diff --git a/src/core/qgsvectorlayerdiagramprovider.cpp b/src/core/qgsvectorlayerdiagramprovider.cpp index a47f042e5e9..777a906158b 100644 --- a/src/core/qgsvectorlayerdiagramprovider.cpp +++ b/src/core/qgsvectorlayerdiagramprovider.cpp @@ -192,7 +192,7 @@ QgsLabelFeature *QgsVectorLayerDiagramProvider::registerDiagram( QgsFeature &fea } // data defined show diagram? check this before doing any other processing - if ( !mSettings.dataDefinedProperties().valueAsBool( QgsDiagramLayerSettings::Show, context.expressionContext(), true ) ) + if ( !mSettings.dataDefinedProperties().valueAsBool( QgsDiagramLayerSettings::Show, context.expressionContext(), true ) || !context.expressionContext().feature().isValid() ) return nullptr; // data defined obstacle? diff --git a/src/core/qgsvectorlayerlabeling.cpp b/src/core/qgsvectorlayerlabeling.cpp index 7bd8637fd73..8723b6b567a 100644 --- a/src/core/qgsvectorlayerlabeling.cpp +++ b/src/core/qgsvectorlayerlabeling.cpp @@ -546,3 +546,13 @@ void QgsVectorLayerSimpleLabeling::toSld( QDomNode &parent, const QgsStringMap & } + +void QgsVectorLayerSimpleLabeling::setSettings( QgsPalLayerSettings *settings, const QString &providerId ) +{ + Q_UNUSED( providerId ); + + if ( mSettings.get() == settings ) + return; + + mSettings.reset( settings ); +} diff --git a/src/core/qgsvectorlayerlabeling.h b/src/core/qgsvectorlayerlabeling.h index 6c48f2bc70f..f65b82b1e59 100644 --- a/src/core/qgsvectorlayerlabeling.h +++ b/src/core/qgsvectorlayerlabeling.h @@ -68,6 +68,16 @@ class CORE_EXPORT QgsAbstractVectorLayerLabeling */ virtual QgsPalLayerSettings settings( const QString &providerId = QString() ) const = 0; + /** + * Set pal settings for a specific provider (takes ownership). + * + * \param settings Pal layer settings + * \param providerId The id of the provider + * + * \since QGIS 3.0 + */ + virtual void setSettings( QgsPalLayerSettings *settings SIP_TRANSFER, const QString &providerId = QString() ) = 0; + /** * Returns true if drawing labels requires advanced effects like composition * modes, which could prevent it being used as an isolated cached image @@ -121,6 +131,17 @@ class CORE_EXPORT QgsVectorLayerSimpleLabeling : public QgsAbstractVectorLayerLa virtual QgsVectorLayerLabelProvider *provider( QgsVectorLayer *layer ) const override SIP_SKIP; virtual QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context ) const override; virtual QgsPalLayerSettings settings( const QString &providerId = QString() ) const override; + + /** + * Set pal settings (takes ownership). + * + * \param settings Pal layer settings + * \param providerId Unused parameter + * + * \since QGIS 3.0 + */ + virtual void setSettings( QgsPalLayerSettings *settings SIP_TRANSFER, const QString &providerId = QString() ) override; + bool requiresAdvancedEffects() const override; virtual void toSld( QDomNode &parent, const QgsStringMap &props ) const override;