Skip to content

Commit

Permalink
[feature][temporal] Add a fixed static duration option for vector
Browse files Browse the repository at this point in the history
layers set to the "Single Field with Date/Time" mode

This allows layers with a single field representing the start date
but where all features have a constant event duration to play
nicely with the temporal framework

Also add user friendly descriptions for the various temporal modes
inside the widget

Fixes #26398
  • Loading branch information
nyalldawson committed May 13, 2020
1 parent 3dce1bf commit c162293
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 59 deletions.
42 changes: 42 additions & 0 deletions python/core/auto_generated/qgsvectorlayertemporalproperties.sip.in
Expand Up @@ -142,6 +142,11 @@ contains the duration of the event.

Units are specified by durationUnits()

.. warning::

This setting is only effective when mode() is
QgsVectorLayerTemporalProperties.ModeFeatureDateTimeStartAndDurationFromFields

.. seealso:: :py:func:`setDurationField`

.. seealso:: :py:func:`durationUnits`
Expand All @@ -154,6 +159,11 @@ contains the duration of the event.

Units are specified by setDurationUnits()

.. warning::

This setting is only effective when mode() is
QgsVectorLayerTemporalProperties.ModeFeatureDateTimeStartAndDurationFromFields

.. seealso:: :py:func:`durationField`

.. seealso:: :py:func:`setDurationUnits`
Expand All @@ -171,6 +181,38 @@ Returns the units of the event's duration.
Sets the ``units`` of the event's duration.

.. seealso:: :py:func:`durationUnits`
%End

double fixedDuration() const;
%Docstring
Returns the fixed duration length, which contains the duration of the event.

Units are specified by durationUnits()

.. warning::

This setting is only effective when mode() is
QgsVectorLayerTemporalProperties.ModeFeatureDateTimeInstantFromField

.. seealso:: :py:func:`setFixedDuration`

.. seealso:: :py:func:`durationUnits`
%End

void setFixedDuration( double duration );
%Docstring
Sets the fixed event ``duration``, which contains the duration of the event.

Units are specified by setDurationUnits()

.. warning::

This setting is only effective when mode() is
QgsVectorLayerTemporalProperties.ModeFeatureDateTimeInstantFromField

.. seealso:: :py:func:`fixedDuration`

.. seealso:: :py:func:`setDurationUnits`
%End

QString createFilterString( QgsVectorLayer *layer, const QgsDateTimeRange &range ) const;
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsinterval.cpp
Expand Up @@ -141,7 +141,7 @@ QgsInterval operator-( const QDateTime &dt1, const QDateTime &dt2 )
return QgsInterval( mSeconds / 1000.0 );
}

QDateTime operator+( const QDateTime &start, QgsInterval interval )
QDateTime operator+( const QDateTime &start, const QgsInterval &interval )
{
return start.addMSecs( static_cast<qint64>( interval.seconds() * 1000.0 ) );
}
Expand Down
41 changes: 34 additions & 7 deletions src/core/qgsvectorlayertemporalproperties.cpp
Expand Up @@ -61,8 +61,10 @@ QgsDateTimeRange QgsVectorLayerTemporalProperties::calculateTemporalExtent( QgsM
const int fieldIndex = vectorLayer->fields().lookupField( mStartFieldName );
if ( fieldIndex >= 0 )
{
return QgsDateTimeRange( vectorLayer->minimumValue( fieldIndex ).toDateTime(),
vectorLayer->maximumValue( fieldIndex ).toDateTime() );
const QDateTime min = vectorLayer->minimumValue( fieldIndex ).toDateTime();
const QDateTime maxStartTime = vectorLayer->maximumValue( fieldIndex ).toDateTime();
const QgsInterval eventDuration = QgsInterval( mFixedDuration, mDurationUnit );
return QgsDateTimeRange( min, maxStartTime + eventDuration );
}
break;
}
Expand Down Expand Up @@ -171,6 +173,7 @@ bool QgsVectorLayerTemporalProperties::readXml( const QDomElement &element, cons
mEndFieldName = temporalNode.attribute( QStringLiteral( "endField" ) );
mDurationFieldName = temporalNode.attribute( QStringLiteral( "durationField" ) );
mDurationUnit = QgsUnitTypes::decodeTemporalUnit( temporalNode.attribute( QStringLiteral( "durationUnit" ), QgsUnitTypes::encodeUnit( QgsUnitTypes::TemporalMinutes ) ) );
mFixedDuration = temporalNode.attribute( QStringLiteral( "fixedDuration" ) ).toDouble();

QDomNode rangeElement = temporalNode.namedItem( QStringLiteral( "fixedRange" ) );

Expand Down Expand Up @@ -200,6 +203,7 @@ QDomElement QgsVectorLayerTemporalProperties::writeXml( QDomElement &element, QD
temporalElement.setAttribute( QStringLiteral( "endField" ), mEndFieldName );
temporalElement.setAttribute( QStringLiteral( "durationField" ), mDurationFieldName );
temporalElement.setAttribute( QStringLiteral( "durationUnit" ), QgsUnitTypes::encodeUnit( mDurationUnit ) );
temporalElement.setAttribute( QStringLiteral( "fixedDuration" ), qgsDoubleToString( mFixedDuration ) );

QDomElement rangeElement = document.createElement( QStringLiteral( "fixedRange" ) );

Expand Down Expand Up @@ -243,6 +247,16 @@ void QgsVectorLayerTemporalProperties::setDefaultsFromDataProviderTemporalCapabi
}
}

double QgsVectorLayerTemporalProperties::fixedDuration() const
{
return mFixedDuration;
}

void QgsVectorLayerTemporalProperties::setFixedDuration( double fixedDuration )
{
mFixedDuration = fixedDuration;
}

QString QgsVectorLayerTemporalProperties::startField() const
{
return mStartFieldName;
Expand Down Expand Up @@ -305,11 +319,24 @@ QString QgsVectorLayerTemporalProperties::createFilterString( QgsVectorLayer *,
return QString();

case ModeFeatureDateTimeInstantFromField:
return QStringLiteral( "(%1 %2 %3 AND %1 %4 %5) OR %1 IS NULL" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
range.includeBeginning() ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
dateTimeExpressionLiteral( range.begin() ),
range.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( range.end() ) );
{
if ( qgsDoubleNear( mFixedDuration, 0.0 ) )
{
return QStringLiteral( "(%1 %2 %3 AND %1 %4 %5) OR %1 IS NULL" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
range.includeBeginning() ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
dateTimeExpressionLiteral( range.begin() ),
range.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( range.end() ) );
}
else
{
return QStringLiteral( "(%1 %2 %3 AND %1 %4 %5) OR %1 IS NULL" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
range.includeBeginning() ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
dateTimeExpressionLiteral( range.begin() + QgsInterval( -mFixedDuration, mDurationUnit ) ),
range.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( range.end() ) );
}
}

case ModeFeatureDateTimeStartAndDurationFromFields:
{
Expand Down
34 changes: 34 additions & 0 deletions src/core/qgsvectorlayertemporalproperties.h
Expand Up @@ -153,6 +153,9 @@ class CORE_EXPORT QgsVectorLayerTemporalProperties : public QgsMapLayerTemporalP
*
* Units are specified by durationUnits()
*
* \warning This setting is only effective when mode() is
* QgsVectorLayerTemporalProperties::ModeFeatureDateTimeStartAndDurationFromFields
*
* \see setDurationField()
* \see durationUnits()
*/
Expand All @@ -164,6 +167,9 @@ class CORE_EXPORT QgsVectorLayerTemporalProperties : public QgsMapLayerTemporalP
*
* Units are specified by setDurationUnits()
*
* \warning This setting is only effective when mode() is
* QgsVectorLayerTemporalProperties::ModeFeatureDateTimeStartAndDurationFromFields
*
* \see durationField()
* \see setDurationUnits()
*/
Expand All @@ -183,6 +189,32 @@ class CORE_EXPORT QgsVectorLayerTemporalProperties : public QgsMapLayerTemporalP
*/
void setDurationUnits( QgsUnitTypes::TemporalUnit units );

/**
* Returns the fixed duration length, which contains the duration of the event.
*
* Units are specified by durationUnits()
*
* \warning This setting is only effective when mode() is
* QgsVectorLayerTemporalProperties::ModeFeatureDateTimeInstantFromField
*
* \see setFixedDuration()
* \see durationUnits()
*/
double fixedDuration() const;

/**
* Sets the fixed event \a duration, which contains the duration of the event.
*
* Units are specified by setDurationUnits()
*
* \warning This setting is only effective when mode() is
* QgsVectorLayerTemporalProperties::ModeFeatureDateTimeInstantFromField
*
* \see fixedDuration()
* \see setDurationUnits()
*/
void setFixedDuration( double duration );

/**
* Creates a QGIS expression filter string for filtering features from \a layer
* to those within the specified time \a range.
Expand Down Expand Up @@ -220,6 +252,8 @@ class CORE_EXPORT QgsVectorLayerTemporalProperties : public QgsMapLayerTemporalP
QString mDurationFieldName;
QgsUnitTypes::TemporalUnit mDurationUnit = QgsUnitTypes::TemporalMinutes;

double mFixedDuration = 0;

};

#endif // QGSVECTORLAYERTEMPORALPROPERTIES_H
17 changes: 14 additions & 3 deletions src/gui/qgsvectorlayertemporalpropertieswidget.cpp
Expand Up @@ -22,7 +22,7 @@
#include "qgsvectordataprovidertemporalcapabilities.h"
#include "qgsvectorlayer.h"
#include "qgsvectorlayertemporalproperties.h"

#include "qgsstringutils.h"

QgsVectorLayerTemporalPropertiesWidget::QgsVectorLayerTemporalPropertiesWidget( QWidget *parent, QgsVectorLayer *layer )
: QWidget( parent )
Expand Down Expand Up @@ -65,6 +65,10 @@ QgsVectorLayerTemporalPropertiesWidget::QgsVectorLayerTemporalPropertiesWidget(
mDurationStartFieldComboBox->setFilters( QgsFieldProxyModel::DateTime | QgsFieldProxyModel::Date );
mDurationFieldComboBox->setFilters( QgsFieldProxyModel::Numeric );

mFixedDurationSpinBox->setMinimum( 0 );
mFixedDurationSpinBox->setClearValue( 0 );
mFixedDurationSpinBox->setValue( properties->fixedDuration() );

for ( QgsUnitTypes::TemporalUnit u :
{
QgsUnitTypes::TemporalMilliseconds,
Expand All @@ -79,7 +83,10 @@ QgsVectorLayerTemporalPropertiesWidget::QgsVectorLayerTemporalPropertiesWidget(
QgsUnitTypes::TemporalCenturies
} )
{
mDurationUnitsComboBox->addItem( QgsUnitTypes::toString( u ), u );
const QString title = ( QgsGui::higFlags() & QgsGui::HigDialogTitleIsTitleCase ) ? QgsStringUtils::capitalize( QgsUnitTypes::toString( u ), QgsStringUtils::TitleCase )
: QgsUnitTypes::toString( u );
mDurationUnitsComboBox->addItem( title, u );
mFixedDurationUnitsComboBox->addItem( title, u );
}

if ( !properties->startField().isEmpty() )
Expand All @@ -94,6 +101,7 @@ QgsVectorLayerTemporalPropertiesWidget::QgsVectorLayerTemporalPropertiesWidget(
}
mDurationFieldComboBox->setField( properties->durationField() );
mDurationUnitsComboBox->setCurrentIndex( mDurationUnitsComboBox->findData( properties->durationUnits() ) );
mFixedDurationUnitsComboBox->setCurrentIndex( mDurationUnitsComboBox->findData( properties->durationUnits() ) );
}

void QgsVectorLayerTemporalPropertiesWidget::saveTemporalProperties()
Expand All @@ -114,18 +122,21 @@ void QgsVectorLayerTemporalPropertiesWidget::saveTemporalProperties()
case QgsVectorLayerTemporalProperties::ModeFixedTemporalRange:
case QgsVectorLayerTemporalProperties::ModeRedrawLayerOnly:
properties->setStartField( mSingleFieldComboBox->currentField() );
properties->setDurationUnits( static_cast< QgsUnitTypes::TemporalUnit >( mFixedDurationUnitsComboBox->currentData().toInt() ) );
break;

case QgsVectorLayerTemporalProperties::ModeFeatureDateTimeStartAndEndFromFields:
properties->setStartField( mStartFieldComboBox->currentField() );
properties->setDurationUnits( static_cast< QgsUnitTypes::TemporalUnit >( mFixedDurationUnitsComboBox->currentData().toInt() ) );
break;

case QgsVectorLayerTemporalProperties::ModeFeatureDateTimeStartAndDurationFromFields:
properties->setStartField( mDurationStartFieldComboBox->currentField() );
properties->setDurationUnits( static_cast< QgsUnitTypes::TemporalUnit >( mDurationUnitsComboBox->currentData().toInt() ) );
break;
}

properties->setEndField( mEndFieldComboBox->currentField() );
properties->setDurationField( mDurationFieldComboBox->currentField() );
properties->setDurationUnits( static_cast< QgsUnitTypes::TemporalUnit >( mDurationUnitsComboBox->currentData().toInt() ) );
properties->setFixedDuration( mFixedDurationSpinBox->value() );
}

0 comments on commit c162293

Please sign in to comment.