Implement action create auxiliary field

This commit is contained in:
Blottiere Paul 2017-08-29 05:58:40 +01:00
parent 1cfa21512d
commit 6b81286a8f
10 changed files with 353 additions and 3 deletions

View File

@ -297,6 +297,7 @@
%Include qgsapplication.sip
%Include qgsactionscoperegistry.sip
%Include qgsanimatedicon.sip
%Include qgsauxiliarystorage.sip
%Include qgsbrowsermodel.sip
%Include qgscoordinatereferencesystem.sip
%Include qgscredentials.sip
@ -421,6 +422,5 @@
%Include layertree/qgslayertreeregistrybridge.sip
%Include qgsuserprofilemanager.sip
%Include symbology/qgsarrowsymbollayer.sip
%Include qgsauxiliarystorage.sip
%Include composer/qgscomposerutils.sip
%Include qgsuserprofile.sip

View File

@ -12,6 +12,52 @@
class QgsAuxiliaryField : QgsField
{
%Docstring
Class allowing to manage fields from of auxiliary layers
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsauxiliarystorage.h"
%End
public:
QgsAuxiliaryField( const QgsPropertyDefinition &def );
%Docstring
Constructor
\param def Definition of the property to be stored by this auxiliary
field.
%End
virtual ~QgsAuxiliaryField();
%Docstring
Destructor
%End
QgsPropertyDefinition propertyDefinition() const;
%Docstring
Returns the property definition corresponding to this field.
:rtype: QgsPropertyDefinition
%End
static QString name( const QgsPropertyDefinition &def, bool joined = false );
%Docstring
Returns the name of the auxiliary field for a property definition.
:return: def The property definition
:return: joined The join prefix is tok into account if true
:rtype: str
%End
};
class QgsAuxiliaryLayer : QgsVectorLayer
{
%Docstring
@ -50,6 +96,27 @@ class QgsAuxiliaryLayer : QgsVectorLayer
:rtype: QgsVectorLayerJoinInfo
%End
bool exists( const QgsPropertyDefinition &definition ) const;
%Docstring
Returns true if the property is stored in the layer yet, false
otherwise.
\param definition The property definition to check
:return: true if the property is stored, false otherwise
:rtype: bool
%End
bool addAuxiliaryField( const QgsPropertyDefinition &definition );
%Docstring
Add an an auxiliary field for the given property.
\param definition The definition of the property to add
:return: true if the auxiliary field is well added, false otherwise
:rtype: bool
%End
bool save();
%Docstring
Commit changes and starts editing then.

View File

@ -172,6 +172,13 @@ class QgsPropertyOverrideButton: QToolButton
an expression context for the button when required.
%End
void updateFieldLists();
%Docstring
Updates list of fields.
.. versionadded:: 3.0
%End
public slots:

View File

@ -39,6 +39,8 @@
#include "qgslogger.h"
#include "qgisapp.h"
#include "qgssettings.h"
#include "qgsnewauxiliarylayerdialog.h"
#include "qgsauxiliarystorage.h"
#include <QList>
#include <QMessageBox>
@ -486,6 +488,7 @@ void QgsDiagramProperties::registerDataDefinedButton( QgsPropertyOverrideButton
{
button->init( key, mDataDefinedProperties, QgsDiagramLayerSettings::propertyDefinitions(), mLayer );
connect( button, &QgsPropertyOverrideButton::changed, this, &QgsDiagramProperties::updateProperty );
connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsDiagramProperties::createAuxiliaryField );
button->registerExpressionContextGenerator( this );
}
@ -1048,3 +1051,32 @@ void QgsDiagramProperties::showHelp()
{
QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html#legend" ) );
}
void QgsDiagramProperties::createAuxiliaryField()
{
// try to create an auxiliary layer if not yet created
if ( !mLayer->auxiliaryLayer() )
{
QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
dlg.exec();
}
// return if still not exists
if ( !mLayer->auxiliaryLayer() )
return;
QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
const QgsDiagramLayerSettings::Property key = static_cast< QgsDiagramLayerSettings::Property >( button->propertyKey() );
const QgsPropertyDefinition def = QgsDiagramLayerSettings::propertyDefinitions()[key];
// create property in auxiliary storage
mLayer->auxiliaryLayer()->addAuxiliaryField( def );
// update property with join field name from auxiliary storage
QgsProperty property = button->toProperty();
property.setField( QgsAuxiliaryField::name( def, true ) );
property.setActive( true );
button->updateFieldLists();
button->setToProperty( property );
mDataDefinedProperties.setProperty( key, button->toProperty() );
}

View File

@ -95,6 +95,8 @@ class APP_EXPORT QgsDiagramProperties : public QWidget, private Ui::QgsDiagramPr
void updateProperty();
void showHelp();
void createAuxiliaryField();
};
class EditBlockerDelegate: public QStyledItemDelegate

View File

@ -21,6 +21,8 @@
#include "qgsmapcanvas.h"
#include "qgsvectorlayerlabeling.h"
#include "qgsproject.h"
#include "qgsauxiliarystorage.h"
#include "qgsnewauxiliarylayerdialog.h"
QgsExpressionContext QgsLabelingGui::createExpressionContext() const
{
@ -46,6 +48,7 @@ void QgsLabelingGui::registerDataDefinedButton( QgsPropertyOverrideButton *butto
{
button->init( key, mDataDefinedProperties, QgsPalLayerSettings::propertyDefinitions(), mLayer );
connect( button, &QgsPropertyOverrideButton::changed, this, &QgsLabelingGui::updateProperty );
connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsLabelingGui::createAuxiliaryField );
button->registerExpressionContextGenerator( this );
}
@ -610,6 +613,31 @@ void QgsLabelingGui::updateUi()
}
}
void QgsLabelingGui::createAuxiliaryField()
{
// try to create an auxiliary layer if not yet created
if ( !mLayer->auxiliaryLayer() )
{
QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
dlg.exec();
}
// return if still not exists
if ( !mLayer->auxiliaryLayer() )
return;
QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
const QgsPalLayerSettings::Property key = static_cast< QgsPalLayerSettings::Property >( button->propertyKey() );
const QgsPropertyDefinition def = QgsPalLayerSettings::propertyDefinitions()[key];
// create property in auxiliary storage
mLayer->auxiliaryLayer()->addAuxiliaryField( def );
// update property with join field name from auxiliary storage
QgsProperty property = button->toProperty();
property.setField( QgsAuxiliaryField::name( def, true ) );
property.setActive( true );
button->updateFieldLists();
button->setToProperty( property );
mDataDefinedProperties.setProperty( key, button->toProperty() );
}

View File

@ -47,6 +47,8 @@ class APP_EXPORT QgsLabelingGui : public QgsTextFormatWidget, private QgsExpress
void updateUi();
void createAuxiliaryField();
protected:
void blockInitSignals( bool block );
void syncDefinedCheckboxFrame( QgsPropertyOverrideButton *ddBtn, QCheckBox *chkBx, QFrame *f );

View File

@ -19,6 +19,8 @@
#include "qgslogger.h"
#include "qgsslconnect.h"
#include "qgsproject.h"
#include "qgspallabeling.h"
#include "qgsdiagramrenderer.h"
#include <QFile>
@ -26,6 +28,120 @@ const QString AS_JOINFIELD = "ASPK";
const QString AS_EXTENSION = "qgd";
const QString AS_JOINPREFIX = "auxiliary_storage_";
QgsAuxiliaryField::QgsAuxiliaryField( const QgsPropertyDefinition &def )
: QgsField()
, mPropertyDefinition( def )
{
init( def );
}
QgsAuxiliaryField::QgsAuxiliaryField( const QgsField &f )
{
const QStringList parts = f.name().split( '_' );
if ( parts.size() <= 1 )
return;
const QString origin = parts[0];
const QString propertyName = parts[1];
QgsPropertyDefinition def;
if ( origin.compare( "pal", Qt::CaseInsensitive ) == 0 )
{
const QgsPropertiesDefinition props = QgsPalLayerSettings::propertyDefinitions();
Q_FOREACH ( const QgsPropertyDefinition p, props.values() )
{
if ( p.name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
{
def = p;
break;
}
}
}
else if ( origin.compare( "diagram", Qt::CaseInsensitive ) == 0 )
{
const QgsPropertiesDefinition props = QgsDiagramLayerSettings::propertyDefinitions();
Q_FOREACH ( const QgsPropertyDefinition p, props.values() )
{
if ( p.name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
{
def = p;
break;
}
}
}
if ( !def.name().isEmpty() )
{
init( def );
setTypeName( f.typeName() );
mPropertyDefinition = def;
}
}
void QgsAuxiliaryField::init( const QgsPropertyDefinition &def )
{
if ( !def.name().isEmpty() )
{
QVariant::Type type;
int len( 0 ), precision( 0 );
switch ( def.dataType() )
{
case QgsPropertyDefinition::DataTypeString:
type = QVariant::String;
len = 50;
break;
case QgsPropertyDefinition::DataTypeNumeric:
type = QVariant::Double;
len = 0;
precision = 0;
break;
case QgsPropertyDefinition::DataTypeBoolean:
type = QVariant::Int; // sqlite does not have a bool type
break;
default:
break;
}
setType( type );
setName( name( def ) );
setLength( len );
setPrecision( precision );
}
}
QString QgsAuxiliaryField::name( const QgsPropertyDefinition &def, bool joined )
{
QString origin;
switch ( def.origin() )
{
case QgsPropertyDefinition::Pal:
origin = "pal";
break;
case QgsPropertyDefinition::Diagram:
origin = "diagram";
break;
default:
break;
}
QString fieldName = QString( "%2_%3" ).arg( origin, def.name().toLower() );
if ( joined )
fieldName = QString( "%1%2" ).arg( AS_JOINPREFIX, fieldName );
return fieldName;
}
QgsPropertyDefinition QgsAuxiliaryField::propertyDefinition() const
{
return mPropertyDefinition;
}
//
// QgsAuxiliaryLayer
//
QgsAuxiliaryLayer::QgsAuxiliaryLayer( const QString &pkField, const QString &filename, const QString &table, const QgsVectorLayer *vlayer )
: QgsVectorLayer( QString( "%1|layername=%2" ).arg( filename, table ), QString( "%1_auxiliarystorage" ).arg( table ), "ogr" )
, mLayer( vlayer )
@ -45,6 +161,23 @@ QgsVectorLayerJoinInfo QgsAuxiliaryLayer::joinInfo() const
return mJoinInfo;
}
bool QgsAuxiliaryLayer::exists( const QgsPropertyDefinition &definition ) const
{
return ( fields().indexOf( QgsAuxiliaryField::name( definition ) ) >= 0 );
}
bool QgsAuxiliaryLayer::addAuxiliaryField( const QgsPropertyDefinition &definition )
{
if ( definition.name().isEmpty() || exists( definition ) )
return false;
const QgsAuxiliaryField af( definition );
const bool rc = addAttribute( af );
updateFields();
return rc;
}
bool QgsAuxiliaryLayer::save()
{
bool rc = false;

View File

@ -21,6 +21,7 @@
#include "qgis_core.h"
#include "qgsdatasourceuri.h"
#include "qgsvectorlayerjoininfo.h"
#include "qgsproperty.h"
#include <sqlite3.h>
@ -28,6 +29,60 @@
class QgsProject;
/**
* \class QgsAuxiliaryField
*
* \ingroup core
*
* \brief Class allowing to manage fields from of auxiliary layers
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsAuxiliaryField : public QgsField
{
public:
/**
* Constructor
*
* \param def Definition of the property to be stored by this auxiliary
* field.
*/
QgsAuxiliaryField( const QgsPropertyDefinition &def );
/**
* Destructor
*/
virtual ~QgsAuxiliaryField() = default;
/**
* Returns the property definition corresponding to this field.
*/
QgsPropertyDefinition propertyDefinition() const;
/**
* Returns the name of the field.
*/
using QgsField::name SIP_SKIP;
/**
* Returns the name of the auxiliary field for a property definition.
*
* \returns def The property definition
* \returns joined The join prefix is tok into account if true
*/
static QString name( const QgsPropertyDefinition &def, bool joined = false );
private:
QgsAuxiliaryField( const QgsField &f ); // only for auxiliary layer
void init( const QgsPropertyDefinition &def );
QgsPropertyDefinition mPropertyDefinition;
friend class QgsAuxiliaryLayer;
};
/**
* \class QgsAuxiliaryLayer
*
@ -70,6 +125,25 @@ class CORE_EXPORT QgsAuxiliaryLayer : public QgsVectorLayer
*/
QgsVectorLayerJoinInfo joinInfo() const;
/**
* Returns true if the property is stored in the layer yet, false
* otherwise.
*
* \param definition The property definition to check
*
* \returns true if the property is stored, false otherwise
*/
bool exists( const QgsPropertyDefinition &definition ) const;
/**
* Add an an auxiliary field for the given property.
*
* \param definition The definition of the property to add
*
* \returns true if the auxiliary field is well added, false otherwise
*/
bool addAuxiliaryField( const QgsPropertyDefinition &definition );
/**
* Commit changes and starts editing then.
*

View File

@ -181,6 +181,13 @@ class GUI_EXPORT QgsPropertyOverrideButton: public QToolButton
*/
void registerExpressionContextGenerator( QgsExpressionContextGenerator *generator );
/**
* Updates list of fields.
*
* \since QGIS 3.0
*/
void updateFieldLists();
/**
* Sets a symbol which can be used for previews inside the widget or in any dialog created
* by the widget. If not specified, a default created symbol will be used instead.
@ -211,8 +218,6 @@ class GUI_EXPORT QgsPropertyOverrideButton: public QToolButton
private:
void updateFieldLists();
void showDescriptionDialog();
void showExpressionDialog();
void showAssistant();