38 return range.isInfinite() || mFixedRange.isInfinite() || mFixedRange.overlaps( range );
52 QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer );
54 return QgsDateTimeRange();
64 if ( fieldIndex >= 0 )
66 const QDateTime min = vectorLayer->
minimumValue( fieldIndex ).toDateTime();
67 const QDateTime maxStartTime = vectorLayer->
maximumValue( fieldIndex ).toDateTime();
69 return QgsDateTimeRange( min, maxStartTime + eventDuration );
77 const int durationFieldIndex = vectorLayer->
fields().
lookupField( mDurationFieldName );
78 if ( fieldIndex >= 0 && durationFieldIndex >= 0 )
80 const QDateTime minTime = vectorLayer->
minimumValue( fieldIndex ).toDateTime();
88 const QDateTime start = f.
attribute( fieldIndex ).toDateTime();
89 if ( start.isValid() )
91 const QVariant durationValue = f.
attribute( durationFieldIndex );
92 if ( durationValue.isValid() )
94 const double duration = durationValue.toDouble();
95 const QDateTime end = start.addMSecs(
QgsInterval( duration, mDurationUnit ).seconds() * 1000.0 );
97 maxTime = maxTime.isValid() ? std::max( maxTime, end ) : end;
101 return QgsDateTimeRange( minTime, maxTime );
108 const int startFieldIndex = vectorLayer->
fields().
lookupField( mStartFieldName );
110 if ( startFieldIndex >= 0 && endFieldIndex >= 0 )
112 return QgsDateTimeRange( std::min( vectorLayer->
minimumValue( startFieldIndex ).toDateTime(),
113 vectorLayer->
minimumValue( endFieldIndex ).toDateTime() ),
114 std::max( vectorLayer->
maximumValue( startFieldIndex ).toDateTime(),
115 vectorLayer->
maximumValue( endFieldIndex ).toDateTime() ) );
117 else if ( startFieldIndex >= 0 )
119 return QgsDateTimeRange( vectorLayer->
minimumValue( startFieldIndex ).toDateTime(),
120 vectorLayer->
maximumValue( startFieldIndex ).toDateTime() );
122 else if ( endFieldIndex >= 0 )
124 return QgsDateTimeRange( vectorLayer->
minimumValue( endFieldIndex ).toDateTime(),
125 vectorLayer->
maximumValue( endFieldIndex ).toDateTime() );
132 bool hasStartExpression = !mStartExpression.isEmpty();
133 bool hasEndExpression = !mEndExpression.isEmpty();
134 if ( !hasStartExpression && !hasEndExpression )
135 return QgsDateTimeRange();
145 if ( hasStartExpression )
152 if ( hasEndExpression )
158 QSet< QString > fields;
159 if ( hasStartExpression )
161 if ( hasEndExpression )
177 const QDateTime start = hasStartExpression ?
startExpression.evaluate( &context ).toDateTime() : QDateTime();
178 const QDateTime end = hasEndExpression ?
endExpression.evaluate( &context ).toDateTime() : QDateTime();
180 if ( start.isValid() )
182 minTime = minTime.isValid() ? std::min( minTime, start ) : start;
183 if ( !hasEndExpression )
184 maxTime = maxTime.isValid() ? std::max( maxTime, start ) : start;
188 maxTime = maxTime.isValid() ? std::max( maxTime, end ) : end;
189 if ( !hasStartExpression )
190 minTime = minTime.isValid() ? std::min( minTime, end ) : end;
193 return QgsDateTimeRange( minTime, maxTime );
200 return QgsDateTimeRange();
234 QDomElement temporalNode = element.firstChildElement( QStringLiteral(
"temporal" ) );
236 setIsActive( temporalNode.attribute( QStringLiteral(
"enabled" ), QStringLiteral(
"0" ) ).toInt() );
238 mMode =
static_cast< TemporalMode >( temporalNode.attribute( QStringLiteral(
"mode" ), QStringLiteral(
"0" ) ). toInt() );
240 mStartFieldName = temporalNode.attribute( QStringLiteral(
"startField" ) );
241 mEndFieldName = temporalNode.attribute( QStringLiteral(
"endField" ) );
242 mStartExpression = temporalNode.attribute( QStringLiteral(
"startExpression" ) );
243 mEndExpression = temporalNode.attribute( QStringLiteral(
"endExpression" ) );
244 mDurationFieldName = temporalNode.attribute( QStringLiteral(
"durationField" ) );
246 mFixedDuration = temporalNode.attribute( QStringLiteral(
"fixedDuration" ) ).toDouble();
247 mAccumulateFeatures = temporalNode.attribute( QStringLiteral(
"accumulate" ), QStringLiteral(
"0" ) ).toInt();
249 QDomNode rangeElement = temporalNode.namedItem( QStringLiteral(
"fixedRange" ) );
251 QDomNode begin = rangeElement.namedItem( QStringLiteral(
"start" ) );
252 QDomNode end = rangeElement.namedItem( QStringLiteral(
"end" ) );
254 QDateTime beginDate = QDateTime::fromString( begin.toElement().text(), Qt::ISODate );
255 QDateTime endDate = QDateTime::fromString( end.toElement().text(), Qt::ISODate );
257 QgsDateTimeRange range = QgsDateTimeRange( beginDate, endDate );
266 if ( element.isNull() )
267 return QDomElement();
269 QDomElement temporalElement = document.createElement( QStringLiteral(
"temporal" ) );
270 temporalElement.setAttribute( QStringLiteral(
"enabled" ),
isActive() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
271 temporalElement.setAttribute( QStringLiteral(
"mode" ), QString::number( mMode ) );
273 temporalElement.setAttribute( QStringLiteral(
"startField" ), mStartFieldName );
274 temporalElement.setAttribute( QStringLiteral(
"endField" ), mEndFieldName );
275 temporalElement.setAttribute( QStringLiteral(
"startExpression" ), mStartExpression );
276 temporalElement.setAttribute( QStringLiteral(
"endExpression" ), mEndExpression );
277 temporalElement.setAttribute( QStringLiteral(
"durationField" ), mDurationFieldName );
279 temporalElement.setAttribute( QStringLiteral(
"fixedDuration" ),
qgsDoubleToString( mFixedDuration ) );
280 temporalElement.setAttribute( QStringLiteral(
"accumulate" ), mAccumulateFeatures ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
282 QDomElement rangeElement = document.createElement( QStringLiteral(
"fixedRange" ) );
284 QDomElement startElement = document.createElement( QStringLiteral(
"start" ) );
285 QDomElement endElement = document.createElement( QStringLiteral(
"end" ) );
287 QDomText startText = document.createTextNode( mFixedRange.begin().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
288 QDomText endText = document.createTextNode( mFixedRange.end().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
289 startElement.appendChild( startText );
290 endElement.appendChild( endText );
291 rangeElement.appendChild( startElement );
292 rangeElement.appendChild( endElement );
294 temporalElement.appendChild( rangeElement );
296 element.appendChild( temporalElement );
305 setIsActive( vectorCaps->hasTemporalCapabilities() );
309 switch ( vectorCaps->mode() )
326 return mStartExpression;
336 return mEndExpression;
346 return mAccumulateFeatures;
356 return mFixedDuration;
366 return mStartFieldName;
371 mStartFieldName = startFieldName;
376 return mEndFieldName;
381 mEndFieldName =
field;
386 return mDurationFieldName;
391 mDurationFieldName =
field;
396 return mDurationUnit;
401 mDurationUnit = units;
406 return QStringLiteral(
"make_datetime(%1,%2,%3,%4,%5,%6)" ).arg( datetime.date().year() )
407 .arg( datetime.date().month() )
408 .arg( datetime.date().day() )
409 .arg( datetime.time().hour() )
410 .arg( datetime.time().minute() )
411 .arg( datetime.time().second() + datetime.time().msec() / 1000.0 );
427 if ( mAccumulateFeatures )
430 range.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
436 range.includeBeginning() ? QStringLiteral(
">=" ) : QStringLiteral(
">" ),
438 range.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
453 QString intervalExpression;
454 switch ( mDurationUnit )
500 range.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
503 range.includeBeginning() ? QStringLiteral(
">=" ) : QStringLiteral(
">" ),
511 if ( !mStartFieldName.isEmpty() && !mEndFieldName.isEmpty() )
514 range.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
517 range.includeBeginning() ? QStringLiteral(
">=" ) : QStringLiteral(
">" ),
520 else if ( !mStartFieldName.isEmpty() )
523 range.includeBeginning() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
526 else if ( !mEndFieldName.isEmpty() )
529 range.includeBeginning() ? QStringLiteral(
">=" ) : QStringLiteral(
">" ),
537 if ( !mStartExpression.isEmpty() && !mEndExpression.isEmpty() )
539 return QStringLiteral(
"((%1) %2 %3) AND ((%4) %5 %6)" ).arg( mStartExpression,
540 range.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
543 range.includeBeginning() ? QStringLiteral(
">=" ) : QStringLiteral(
">" ),
546 else if ( !mStartExpression.isEmpty() )
548 return QStringLiteral(
"(%1) %2 %3" ).arg( mStartExpression,
549 range.includeBeginning() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
552 else if ( !mEndExpression.isEmpty() )
554 return QStringLiteral(
"(%1) %2 %3" ).arg( mEndExpression,
555 range.includeBeginning() ? QStringLiteral(
">=" ) : QStringLiteral(
">" ),
574 static QStringList sStartCandidates{ QStringLiteral(
"start" ),
575 QStringLiteral(
"begin" ),
576 QStringLiteral(
"from" )};
578 static QStringList sEndCandidates{ QStringLiteral(
"end" ),
579 QStringLiteral(
"last" ),
580 QStringLiteral(
"to" )};
582 static QStringList sSingleFieldCandidates{ QStringLiteral(
"event" ) };
585 bool foundStart =
false;
586 bool foundEnd =
false;
595 for (
const QString &candidate : sStartCandidates )
598 if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
600 mStartFieldName = fldName;
608 for (
const QString &candidate : sEndCandidates )
611 if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
613 mEndFieldName = fldName;
619 if ( foundStart && foundEnd )
631 for (
const QString &candidate : sSingleFieldCandidates )
634 if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
636 mStartFieldName = fldName;
646 if ( foundStart && foundEnd )
648 else if ( foundStart )
Base class for handling properties relating to a data provider's temporal capabilities.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Encapsulate a field in an attribute table or data source.
Container of fields for a vector layer.
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A representation of the interval between two datetime values.
Base class for storage of map layer temporal properties.
Base class for all map layer types.
The class is used as a container of context for various read/write operations on other objects.
bool isActive() const
Returns true if the temporal property is active.
void setIsActive(bool active)
Sets whether the temporal property is active.
@ FlagDontInvalidateCachedRendersWhenRangeChanges
Any cached rendering will not be invalidated when temporal range context is modified.
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
TemporalUnit
Temporal units.
@ TemporalUnknownUnit
Unknown time unit.
@ TemporalMilliseconds
Milliseconds.
@ TemporalDecades
Decades.
@ TemporalCenturies
Centuries.
@ TemporalSeconds
Seconds.
@ TemporalMinutes
Minutes.
static Q_INVOKABLE QgsUnitTypes::TemporalUnit decodeTemporalUnit(const QString &string, bool *ok=nullptr)
Decodes a temporal unit from a string.
Implementation of data provider temporal properties for QgsVectorDataProviders.
@ ProviderHasFixedTemporalRange
Entire dataset from provider has a fixed start and end datetime.
@ ProviderStoresFeatureDateTimeStartAndEndInSeparateFields
Dataset stores feature start and end datetimes in separate fields.
@ ProviderStoresFeatureDateTimeInstantInField
Dataset has feature datetime instants stored in a single field.
Encapsulates the context in which a QgsVectorLayer's temporal capabilities will be applied.
QgsVectorLayer * layer() const
Returns the associated layer.
void setLayer(QgsVectorLayer *layer)
Sets the associated layer.
void guessDefaultsFromFields(const QgsFields &fields)
Attempts to setup the temporal properties by scanning a set of fields and looking for standard naming...
QString endExpression() const
Returns the expression for the end time for the feature's time spans.
void setDurationField(const QString &field)
Sets the name of the duration field, which contains the duration of the event.
QgsVectorLayerTemporalProperties(QObject *parent=nullptr, bool enabled=false)
Constructor for QgsVectorLayerTemporalProperties, with the specified parent object.
void setStartExpression(const QString &expression)
Sets the expression to use for the start time for the feature's time spans.
void setMode(TemporalMode mode)
Sets the temporal properties mode.
bool isVisibleInTemporalRange(const QgsDateTimeRange &range) const override
Returns true if the layer should be visible and rendered for the specified time range.
const QgsDateTimeRange & fixedTemporalRange() const
Returns the fixed temporal range for the layer.
double fixedDuration() const
Returns the fixed duration length, which contains the duration of the event.
bool accumulateFeatures() const
Returns true if features will be accumulated over time (i.e.
QgsTemporalProperty::Flags flags() const override
Returns flags associated to the temporal property.
void setFixedTemporalRange(const QgsDateTimeRange &range)
Sets a temporal range to apply to the whole layer.
QgsUnitTypes::TemporalUnit durationUnits() const
Returns the units of the event's duration.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads temporal properties from a DOM element previously written by writeXml().
void setEndExpression(const QString &endExpression)
Sets the expression to use for the end time for the feature's time spans.
TemporalMode
Mode of the vector temporal properties.
@ ModeFeatureDateTimeStartAndDurationFromFields
Mode when features have a field for start time and a field for event duration.
@ ModeFeatureDateTimeInstantFromField
Mode when features have a datetime instant taken from a single field.
@ ModeFixedTemporalRange
Mode when temporal properties have fixed start and end datetimes.
@ ModeFeatureDateTimeStartAndEndFromFields
Mode when features have separate fields for start and end times.
@ ModeRedrawLayerOnly
Redraw the layer when temporal range changes, but don't apply any filtering. Useful when symbology or...
@ ModeFeatureDateTimeStartAndEndFromExpressions
Mode when features use expressions for start and end times.
QString durationField() const
Returns the name of the duration field, which contains the duration of the event.
QString endField() const
Returns the name of the end datetime field, which contains the end time for the feature's time spans.
QString createFilterString(const QgsVectorLayerTemporalContext &context, const QgsDateTimeRange &range) const
Creates a QGIS expression filter string for filtering features within the specified context to those ...
void setDurationUnits(QgsUnitTypes::TemporalUnit units)
Sets the units of the event's duration.
QDomElement writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) override
Writes the properties to a DOM element, to be used later with readXml().
TemporalMode mode() const
Returns the temporal properties mode.
void setAccumulateFeatures(bool accumulate)
Sets whether features will be accumulated over time (i.e.
void setFixedDuration(double duration)
Sets the fixed event duration, which contains the duration of the event.
void setEndField(const QString &field)
Sets the name of the end datetime field, which contains the end time for the feature's time spans.
QgsDateTimeRange calculateTemporalExtent(QgsMapLayer *layer) const override
Attempts to calculate the overall temporal extent for the specified layer, using the settings defined...
void setDefaultsFromDataProviderTemporalCapabilities(const QgsDataProviderTemporalCapabilities *capabilities) override
Sets the layers temporal settings to appropriate defaults based on a provider's temporal capabilities...
QString startField() const
Returns the name of the start datetime field, which contains the start time for the feature's time sp...
void setStartField(const QString &field)
Sets the name of the start datetime field, which contains the start time for the feature's time spans...
QString startExpression() const
Returns the expression for the start time for the feature's time spans.
Represents a vector layer which manages a vector based data sets.
QVariant maximumValue(int index) const FINAL
Returns the maximum value for an attribute column or an invalid variant in case of error.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QVariant minimumValue(int index) const FINAL
Returns the minimum value for an attribute column or an invalid variant in case of error.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QList< int > QgsAttributeList
QString dateTimeExpressionLiteral(const QDateTime &datetime)