diff --git a/python/core/qgsauxiliarystorage.sip b/python/core/qgsauxiliarystorage.sip index c0a43b0d69c..a6c0dabaad7 100644 --- a/python/core/qgsauxiliarystorage.sip +++ b/python/core/qgsauxiliarystorage.sip @@ -211,7 +211,7 @@ class QgsAuxiliaryLayer : QgsVectorLayer :rtype: int %End - int propertyFromField( int index ) const; + int propertyFromIndex( int index ) const; %Docstring Returns the underlying property key for the field index. The key may be a PAL, diagram or symbology property according to the underlying @@ -224,6 +224,16 @@ class QgsAuxiliaryLayer : QgsVectorLayer :rtype: int %End + QgsPropertyDefinition propertyDefinitionFromIndex( int index ) const; +%Docstring + Returns the property definition fir the underlying field index. + + \param index The index of the field + +.. versionadded:: 3.0 + :rtype: QgsPropertyDefinition +%End + static int createProperty( QgsPalLayerSettings::Property property, const QString &providerId, QgsVectorLayer *vlayer ); %Docstring Create if necessary a new auxiliary field for a PAL property and diff --git a/python/core/qgsproperty.sip b/python/core/qgsproperty.sip index 89fba2ea92e..322e9d6fb06 100644 --- a/python/core/qgsproperty.sip +++ b/python/core/qgsproperty.sip @@ -72,16 +72,17 @@ class QgsPropertyDefinition Constructs an empty property. %End - QgsPropertyDefinition( const QString &name, const QString &description, StandardPropertyTemplate type, const QString &origin = QString() ); + QgsPropertyDefinition( const QString &name, const QString &description, StandardPropertyTemplate type, const QString &origin = QString(), const QString &comment = QString() ); %Docstring Constructor for QgsPropertyDefinition, using a standard property template. \param name is used internally and should be a unique, alphanumeric string. \param description can be any localised string describing what the property is used for. \param type one of the predefined standard property template \param origin The origin of the property + \param comment A free comment for the property %End - QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText, const QString &origin = QString() ); + QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText, const QString &origin = QString(), const QString &comment = QString() ); %Docstring Constructor for custom QgsPropertyDefinitions. \param name is used internally and should be a unique, alphanumeric string. @@ -90,6 +91,7 @@ class QgsPropertyDefinition \param helpText parameter should specify a descriptive string for users outlining the types of value acceptable by the property (eg 'dashed' or 'solid' for a line style property). \param origin The origin of the property + \param comment A free comment for the property %End QString name() const; @@ -120,6 +122,17 @@ class QgsPropertyDefinition :rtype: str %End + QString comment() const; +%Docstring + Returns the comment of the property + :rtype: str +%End + + void setComment( const QString &comment ); +%Docstring + Sets comment of the property +%End + QString helpText() const; %Docstring Helper text for using the property, including a description of the valid values for the property. diff --git a/src/app/qgsvectorlayerproperties.cpp b/src/app/qgsvectorlayerproperties.cpp index 32db8576a70..585dd9b23fd 100644 --- a/src/app/qgsvectorlayerproperties.cpp +++ b/src/app/qgsvectorlayerproperties.cpp @@ -58,6 +58,7 @@ #include "qgsauxiliarystorage.h" #include "qgsnewauxiliarylayerdialog.h" #include "qgslabelinggui.h" +#include "qgssymbollayer.h" #include "layertree/qgslayertreelayer.h" #include "qgslayertree.h" @@ -1532,7 +1533,9 @@ void QgsVectorLayerProperties::updateAuxiliaryStoragePage( bool reset ) item->setText( 0, prop.origin() ); item->setText( 1, prop.name() ); - item->setText( 2, field.typeName() ); + item->setText( 2, prop.comment() ); + item->setText( 3, field.typeName() ); + item->setText( 4, field.name() ); mAuxiliaryStorageFieldsTree->addTopLevelItem( item ); } @@ -1653,6 +1656,7 @@ void QgsVectorLayerProperties::onAuxiliaryLayerDeleteField() QgsPropertyDefinition def; def.setOrigin( item->text( 0 ) ); def.setName( item->text( 1 ) ); + def.setComment( item->text( 2 ) ); const QString fieldName = QgsAuxiliaryField::nameFromProperty( def ); @@ -1680,14 +1684,20 @@ void QgsVectorLayerProperties::deleteAuxiliaryField( int index ) if ( !mLayer->auxiliaryLayer() ) return; - int key = mLayer->auxiliaryLayer()->propertyFromField( index ); + int key = mLayer->auxiliaryLayer()->propertyFromIndex( index ); + QgsPropertyDefinition def = mLayer->auxiliaryLayer()->propertyDefinitionFromIndex( index ); + if ( mLayer->auxiliaryLayer()->deleteAttribute( index ) ) { mLayer->updateFields(); // immediately deactivate data defined button - if ( labelingDialog && labelingDialog->labelingGui() ) + if ( key >= 0 && def.origin().compare( "labeling", Qt::CaseInsensitive ) == 0 + && labelingDialog + && labelingDialog->labelingGui() ) + { labelingDialog->labelingGui()->deactivateField( ( QgsPalLayerSettings::Property ) key ); + } updateAuxiliaryStoragePage( true ); mFieldsPropertiesDialog->init(); diff --git a/src/core/qgsauxiliarystorage.cpp b/src/core/qgsauxiliarystorage.cpp index 12527b59b21..9e1ec120a9c 100644 --- a/src/core/qgsauxiliarystorage.cpp +++ b/src/core/qgsauxiliarystorage.cpp @@ -110,6 +110,11 @@ QgsAuxiliaryField::QgsAuxiliaryField( const QgsField &f ) } } + if ( parts.size() == 3 ) + { + def.setComment( parts[2] ); + } + if ( !def.name().isEmpty() ) { init( def ); @@ -162,7 +167,10 @@ bool QgsAuxiliaryLayer::clear() QString QgsAuxiliaryField::nameFromProperty( const QgsPropertyDefinition &def, bool joined ) { - QString fieldName = QString( "%2_%3" ).arg( def.origin(), def.name().toLower() ); + QString fieldName = QString( "%1_%2" ).arg( def.origin(), def.name().toLower() ); + + if ( !def.comment().isEmpty() ) + fieldName = QString( "%1_%2" ).arg( fieldName ).arg( def.comment() ); if ( joined ) fieldName = QString( "%1%2" ).arg( AS_JOINPREFIX, fieldName ); @@ -405,7 +413,7 @@ bool QgsAuxiliaryLayer::isHiddenProperty( int index ) const return hidden; } -int QgsAuxiliaryLayer::propertyFromField( int index ) const +int QgsAuxiliaryLayer::propertyFromIndex( int index ) const { int p = -1; QgsAuxiliaryField aField( fields().field( index ) ); @@ -424,10 +432,28 @@ int QgsAuxiliaryLayer::propertyFromField( int index ) const } } } + else if ( aDef.origin().compare( "symbol" ) == 0 ) + { + const QgsPropertiesDefinition defs = QgsSymbolLayer::propertyDefinitions(); + QgsPropertiesDefinition::const_iterator it = defs.constBegin(); + for ( ; it != defs.constEnd(); ++it ) + { + if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 ) + { + p = it.key(); + break; + } + } + } return p; } +QgsPropertyDefinition QgsAuxiliaryLayer::propertyDefinitionFromIndex( int index ) const +{ + return QgsAuxiliaryField( fields().field( index ) ).propertyDefinition(); +} + int QgsAuxiliaryLayer::indexOfProperty( const QgsPropertyDefinition &def ) const { return fields().indexOf( QgsAuxiliaryField::nameFromProperty( def ) ); diff --git a/src/core/qgsauxiliarystorage.h b/src/core/qgsauxiliarystorage.h index 6129a5fe94d..e7f48f1ef46 100644 --- a/src/core/qgsauxiliarystorage.h +++ b/src/core/qgsauxiliarystorage.h @@ -238,7 +238,16 @@ class CORE_EXPORT QgsAuxiliaryLayer : public QgsVectorLayer * * \since QGIS 3.0 */ - int propertyFromField( int index ) const; + int propertyFromIndex( int index ) const; + + /** + * Returns the property definition fir the underlying field index. + * + * \param index The index of the field + * + * \since QGIS 3.0 + */ + QgsPropertyDefinition propertyDefinitionFromIndex( int index ) const; /** * Create if necessary a new auxiliary field for a PAL property and diff --git a/src/core/qgsproperty.cpp b/src/core/qgsproperty.cpp index aaa4654626a..df1bd5e35c8 100644 --- a/src/core/qgsproperty.cpp +++ b/src/core/qgsproperty.cpp @@ -21,11 +21,12 @@ #include "qgssymbollayerutils.h" #include "qgscolorramp.h" -QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, const QString &description, QgsPropertyDefinition::StandardPropertyTemplate type, const QString &origin ) +QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, const QString &description, QgsPropertyDefinition::StandardPropertyTemplate type, const QString &origin, const QString &comment ) : mName( name ) , mDescription( description ) , mStandardType( type ) , mOrigin( origin ) + , mComment( comment ) { switch ( mStandardType ) { @@ -170,12 +171,13 @@ QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, const QString } } -QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText, const QString &origin ) +QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText, const QString &origin, const QString &comment ) : mName( name ) , mDescription( description ) , mTypes( dataType ) , mHelpText( helpText ) , mOrigin( origin ) + , mComment( comment ) {} bool QgsPropertyDefinition::supportsAssistant() const diff --git a/src/core/qgsproperty.h b/src/core/qgsproperty.h index cbdafd279cd..dc115cc404f 100644 --- a/src/core/qgsproperty.h +++ b/src/core/qgsproperty.h @@ -116,8 +116,9 @@ class CORE_EXPORT QgsPropertyDefinition * \param description can be any localised string describing what the property is used for. * \param type one of the predefined standard property template * \param origin The origin of the property + * \param comment A free comment for the property */ - QgsPropertyDefinition( const QString &name, const QString &description, StandardPropertyTemplate type, const QString &origin = QString() ); + QgsPropertyDefinition( const QString &name, const QString &description, StandardPropertyTemplate type, const QString &origin = QString(), const QString &comment = QString() ); /** * Constructor for custom QgsPropertyDefinitions. @@ -127,8 +128,9 @@ class CORE_EXPORT QgsPropertyDefinition * \param helpText parameter should specify a descriptive string for users outlining the types * of value acceptable by the property (eg 'dashed' or 'solid' for a line style property). * \param origin The origin of the property + * \param comment A free comment for the property */ - QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText, const QString &origin = QString() ); + QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText, const QString &origin = QString(), const QString &comment = QString() ); /** * Returns the name of the property. This is used internally and should be a unique, alphanumeric string. @@ -155,6 +157,16 @@ class CORE_EXPORT QgsPropertyDefinition */ QString description() const { return mDescription; } + /** + * Returns the comment of the property + */ + QString comment() const { return mComment; } + + /** + * Sets comment of the property + */ + void setComment( const QString &comment ) { mComment = comment; } + /** * Helper text for using the property, including a description of the valid values for the property. */ @@ -185,6 +197,7 @@ class CORE_EXPORT QgsPropertyDefinition QString mHelpText; StandardPropertyTemplate mStandardType = Custom; QString mOrigin; + QString mComment; static QString trString(); }; diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 5a088d77b8b..df3a6ffd177 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -297,6 +297,7 @@ SET(QGIS_GUI_SRCS qgsmessageviewer.cpp qgsmetadatawidget.cpp qgsnewauxiliarylayerdialog.cpp + qgsnewauxiliaryfielddialog.cpp qgsnewhttpconnection.cpp qgsnewmemorylayerdialog.cpp qgsnewnamedialog.cpp @@ -458,6 +459,7 @@ SET(QGIS_GUI_MOC_HDRS qgsmessageviewer.h qgsmetadatawidget.h qgsnewauxiliarylayerdialog.h + qgsnewauxiliaryfielddialog.h qgsnewhttpconnection.h qgsnewmemorylayerdialog.h qgsnewnamedialog.h diff --git a/src/gui/qgsnewauxiliaryfielddialog.cpp b/src/gui/qgsnewauxiliaryfielddialog.cpp new file mode 100644 index 00000000000..8b63f7534b6 --- /dev/null +++ b/src/gui/qgsnewauxiliaryfielddialog.cpp @@ -0,0 +1,82 @@ +/*************************************************************************** + qgsnewauxiliaryfielddialog.cpp - description + ------------------- + begin : Sept 05, 2017 + copyright : (C) 2017 by Paul Blottiere + email : paul.blottiere@oslandia.com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsnewauxiliaryfielddialog.h" +#include "qgsauxiliarystorage.h" + +#include + +QgsNewAuxiliaryFieldDialog::QgsNewAuxiliaryFieldDialog( const QgsPropertyDefinition &def, QgsVectorLayer *layer, bool nameOnly, QWidget *parent ) + : QDialog( parent ) + , mLayer( layer ) + , mNameOnly( nameOnly ) + , mPropertyDefinition( def ) +{ + setupUi( this ); + + mType->addItem( tr( "String" ) ); + mType->addItem( tr( "Numeric" ) ); + mType->addItem( tr( "Boolean" ) ); + + switch ( def.dataType() ) + { + case QgsPropertyDefinition::DataTypeString: + mType->setCurrentIndex( mType->findText( tr( "String" ) ) ); + break; + case QgsPropertyDefinition::DataTypeNumeric: + mType->setCurrentIndex( mType->findText( tr( "Numeric" ) ) ); + break; + case QgsPropertyDefinition::DataTypeBoolean: + mType->setCurrentIndex( mType->findText( tr( "Boolean" ) ) ); + break; + } + + if ( mNameOnly ) + mType->setEnabled( false ); +} + +void QgsNewAuxiliaryFieldDialog::accept() +{ + QgsPropertyDefinition def = mPropertyDefinition; + def.setComment( mName->text() ); + + QString fieldName = QgsAuxiliaryField::nameFromProperty( def, true ); + const int idx = mLayer->fields().lookupField( fieldName ); + if ( idx >= 0 ) + { + const QString title = tr( "Invalid name" ); + const QString msg = tr( "Auxiliary field '%1' already exists" ).arg( fieldName ); + QMessageBox::critical( this, title, msg, QMessageBox::Ok ); + } + else if ( def.comment().isEmpty() ) + { + const QString title = tr( "Invalid name" ); + const QString msg = tr( "Name is a mandatory parameter" ); + QMessageBox::critical( this, title, msg, QMessageBox::Ok ); + } + else + { + if ( mLayer->auxiliaryLayer()->addAuxiliaryField( def ) ) + mPropertyDefinition = def; + QDialog::accept(); + } +} + +QgsPropertyDefinition QgsNewAuxiliaryFieldDialog::propertyDefinition() const +{ + return mPropertyDefinition; +} diff --git a/src/gui/qgsnewauxiliaryfielddialog.h b/src/gui/qgsnewauxiliaryfielddialog.h new file mode 100644 index 00000000000..60e775d180c --- /dev/null +++ b/src/gui/qgsnewauxiliaryfielddialog.h @@ -0,0 +1,63 @@ +/*************************************************************************** + qgsnewauxiliaryfielddialog.h - description + ------------------- + begin : Sept 05, 2017 + copyright : (C) 2017 by Paul Blottiere + email : paul.blottiere@oslandia.com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSNEWAUXILIARYFIELDDIALOG_H +#define QGSNEWAUXILIARYFIELDDIALOG_H + +#include "ui_qgsnewauxiliaryfielddialogbase.h" +#include "qgsguiutils.h" +#include "qgis_gui.h" +#include "qgsvectorlayer.h" +#include "qgsproperty.h" + +/** + * \ingroup gui + * + * \brief A dialog to create a new auxiliary field + * + * \since QGIS 3.0 + */ +class GUI_EXPORT QgsNewAuxiliaryFieldDialog: public QDialog, private Ui::QgsNewAuxiliaryFieldDialogBase +{ + Q_OBJECT + + public: + + /** + * Constructor. + * + * \param def The property definition to use to create the auxiliary field + * \param layer The vector layer for which the auxiliary layer has to be created + * \param customOnly True to indicate that only the name widget is enabled + * \param parent Parent window + */ + QgsNewAuxiliaryFieldDialog( const QgsPropertyDefinition &def, QgsVectorLayer *layer, bool nameOnly = true, QWidget *parent = nullptr ); + + /** + * Returns the underlying property definition. + */ + QgsPropertyDefinition propertyDefinition() const; + + protected: + void accept() override; + + QgsVectorLayer *mLayer = nullptr; + bool mNameOnly = true; + QgsPropertyDefinition mPropertyDefinition; +}; + +#endif diff --git a/src/gui/symbology/qgssymbollayerwidget.cpp b/src/gui/symbology/qgssymbollayerwidget.cpp index aad649998d2..92a87464ef2 100644 --- a/src/gui/symbology/qgssymbollayerwidget.cpp +++ b/src/gui/symbology/qgssymbollayerwidget.cpp @@ -39,6 +39,7 @@ #include "qgslogger.h" #include "qgssettings.h" #include "qgsnewauxiliarylayerdialog.h" +#include "qgsnewauxiliaryfielddialog.h" #include "qgsauxiliarystorage.h" #include @@ -133,11 +134,19 @@ void QgsSymbolLayerWidget::createAuxiliaryField() QgsPropertyOverrideButton *button = qobject_cast( sender() ); QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( button->propertyKey() ); - const QgsPropertyDefinition def = QgsSymbolLayer::propertyDefinitions()[key]; + QgsPropertyDefinition def = QgsSymbolLayer::propertyDefinitions()[key]; // create property in auxiliary storage if necessary if ( !mVectorLayer->auxiliaryLayer()->exists( def ) ) - mVectorLayer->auxiliaryLayer()->addAuxiliaryField( def ); + { + QgsNewAuxiliaryFieldDialog dlg( def, mVectorLayer, true, this ); + if ( dlg.exec() == QDialog::Accepted ) + def = dlg.propertyDefinition(); + } + + // return if still not exist + if ( !mVectorLayer->auxiliaryLayer()->exists( def ) ) + return; // update property with join field name from auxiliary storage QgsProperty property = button->toProperty(); diff --git a/src/ui/qgsnewauxiliaryfielddialogbase.ui b/src/ui/qgsnewauxiliaryfielddialogbase.ui new file mode 100644 index 00000000000..c454b25b9c7 --- /dev/null +++ b/src/ui/qgsnewauxiliaryfielddialogbase.ui @@ -0,0 +1,111 @@ + + + QgsNewAuxiliaryFieldDialogBase + + + + 0 + 0 + 397 + 159 + + + + Auxiliary storage : new auxiliary field + + + + + 50 + 120 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 10 + 10 + 381 + 101 + + + + + + + New auxiliary field parameters + + + + + + + + + Type + + + + + + + + + + Name + + + + + + + + + + + + + + + buttonBox + accepted() + QgsNewAuxiliaryFieldDialogBase + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + QgsNewAuxiliaryFieldDialogBase + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/ui/qgsvectorlayerpropertiesbase.ui b/src/ui/qgsvectorlayerpropertiesbase.ui index 4eb4ae4567d..886ecb30e16 100644 --- a/src/ui/qgsvectorlayerpropertiesbase.ui +++ b/src/ui/qgsvectorlayerpropertiesbase.ui @@ -2191,11 +2191,21 @@ border-radius: 2px; Property + + + Name + + Type + + + Full Name + +