37 case Qgis::VectorTemporalMode::FixedTemporalRange:
38 return range.isInfinite() || mFixedRange.isInfinite() || mFixedRange.overlaps( range );
40 case Qgis::VectorTemporalMode::FeatureDateTimeInstantFromField:
41 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromFields:
42 case Qgis::VectorTemporalMode::RedrawLayerOnly:
43 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndDurationFromFields:
44 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromExpressions:
52 QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer );
54 return QgsDateTimeRange();
58 case Qgis::VectorTemporalMode::FixedTemporalRange:
61 case Qgis::VectorTemporalMode::FeatureDateTimeInstantFromField:
64 if ( fieldIndex >= 0 )
70 const QDateTime min = minVal.toDateTime();
71 const QDateTime maxStartTime = maxVal.toDateTime();
73 return QgsDateTimeRange( min, maxStartTime + eventDuration );
78 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndDurationFromFields:
81 const int durationFieldIndex = vectorLayer->
fields().
lookupField( mDurationFieldName );
82 if ( fieldIndex >= 0 && durationFieldIndex >= 0 )
84 const QDateTime minTime = vectorLayer->
minimumValue( fieldIndex ).toDateTime();
92 const QDateTime start = f.
attribute( fieldIndex ).toDateTime();
93 if ( start.isValid() )
95 const QVariant durationValue = f.
attribute( durationFieldIndex );
96 if ( durationValue.isValid() )
98 const double duration = durationValue.toDouble();
99 const QDateTime end = start.addMSecs(
QgsInterval( duration, mDurationUnit ).seconds() * 1000.0 );
101 maxTime = maxTime.isValid() ? std::max( maxTime, end ) : end;
105 return QgsDateTimeRange( minTime, maxTime );
110 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromFields:
112 const int startFieldIndex = vectorLayer->
fields().
lookupField( mStartFieldName );
114 if ( startFieldIndex >= 0 && endFieldIndex >= 0 )
116 QVariant startMinVal;
117 QVariant startMaxVal;
123 return QgsDateTimeRange( std::min( startMinVal.toDateTime(),
124 endMinVal.toDateTime() ),
125 std::max( startMaxVal.toDateTime(),
126 endMaxVal.toDateTime() ) );
128 else if ( startFieldIndex >= 0 )
130 QVariant startMinVal;
131 QVariant startMaxVal;
133 return QgsDateTimeRange( startMinVal.toDateTime(),
134 startMaxVal.toDateTime() );
136 else if ( endFieldIndex >= 0 )
141 return QgsDateTimeRange( endMinVal.toDateTime(),
142 endMaxVal.toDateTime() );
147 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromExpressions:
149 const bool hasStartExpression = !mStartExpression.isEmpty();
150 const bool hasEndExpression = !mEndExpression.isEmpty();
151 if ( !hasStartExpression && !hasEndExpression )
152 return QgsDateTimeRange();
162 if ( hasStartExpression )
169 if ( hasEndExpression )
175 QSet< QString > fields;
176 if ( hasStartExpression )
178 if ( hasEndExpression )
194 const QDateTime start = hasStartExpression ?
startExpression.evaluate( &context ).toDateTime() : QDateTime();
195 const QDateTime end = hasEndExpression ?
endExpression.evaluate( &context ).toDateTime() : QDateTime();
197 if ( start.isValid() )
199 minTime = minTime.isValid() ? std::min( minTime, start ) : start;
200 if ( !hasEndExpression )
201 maxTime = maxTime.isValid() ? std::max( maxTime, start ) : start;
205 maxTime = maxTime.isValid() ? std::max( maxTime, end ) : end;
206 if ( !hasStartExpression )
207 minTime = minTime.isValid() ? std::min( minTime, end ) : end;
210 return QgsDateTimeRange( minTime, maxTime );
213 case Qgis::VectorTemporalMode::RedrawLayerOnly:
217 return QgsDateTimeRange();
263 const QDomElement temporalNode = element.firstChildElement( QStringLiteral(
"temporal" ) );
265 setIsActive( temporalNode.attribute( QStringLiteral(
"enabled" ), QStringLiteral(
"0" ) ).toInt() );
267 mMode =
static_cast< Qgis::VectorTemporalMode >( temporalNode.attribute( QStringLiteral(
"mode" ), QStringLiteral(
"0" ) ). toInt() );
269 mLimitMode =
static_cast< Qgis::VectorTemporalLimitMode >( temporalNode.attribute( QStringLiteral(
"limitMode" ), QStringLiteral(
"0" ) ). toInt() );
270 mStartFieldName = temporalNode.attribute( QStringLiteral(
"startField" ) );
271 mEndFieldName = temporalNode.attribute( QStringLiteral(
"endField" ) );
272 mStartExpression = temporalNode.attribute( QStringLiteral(
"startExpression" ) );
273 mEndExpression = temporalNode.attribute( QStringLiteral(
"endExpression" ) );
274 mDurationFieldName = temporalNode.attribute( QStringLiteral(
"durationField" ) );
276 mFixedDuration = temporalNode.attribute( QStringLiteral(
"fixedDuration" ) ).toDouble();
277 mAccumulateFeatures = temporalNode.attribute( QStringLiteral(
"accumulate" ), QStringLiteral(
"0" ) ).toInt();
279 const QDomNode rangeElement = temporalNode.namedItem( QStringLiteral(
"fixedRange" ) );
281 const QDomNode begin = rangeElement.namedItem( QStringLiteral(
"start" ) );
282 const QDomNode end = rangeElement.namedItem( QStringLiteral(
"end" ) );
284 const QDateTime beginDate = QDateTime::fromString( begin.toElement().text(), Qt::ISODate );
285 const QDateTime endDate = QDateTime::fromString( end.toElement().text(), Qt::ISODate );
287 const QgsDateTimeRange range = QgsDateTimeRange( beginDate, endDate );
296 if ( element.isNull() )
297 return QDomElement();
299 QDomElement temporalElement = document.createElement( QStringLiteral(
"temporal" ) );
300 temporalElement.setAttribute( QStringLiteral(
"enabled" ),
isActive() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
301 temporalElement.setAttribute( QStringLiteral(
"mode" ), QString::number(
static_cast< int >( mMode ) ) );
303 temporalElement.setAttribute( QStringLiteral(
"limitMode" ), QString::number(
static_cast< int >( mLimitMode ) ) );
304 temporalElement.setAttribute( QStringLiteral(
"startField" ), mStartFieldName );
305 temporalElement.setAttribute( QStringLiteral(
"endField" ), mEndFieldName );
306 temporalElement.setAttribute( QStringLiteral(
"startExpression" ), mStartExpression );
307 temporalElement.setAttribute( QStringLiteral(
"endExpression" ), mEndExpression );
308 temporalElement.setAttribute( QStringLiteral(
"durationField" ), mDurationFieldName );
310 temporalElement.setAttribute( QStringLiteral(
"fixedDuration" ),
qgsDoubleToString( mFixedDuration ) );
311 temporalElement.setAttribute( QStringLiteral(
"accumulate" ), mAccumulateFeatures ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
313 QDomElement rangeElement = document.createElement( QStringLiteral(
"fixedRange" ) );
315 QDomElement startElement = document.createElement( QStringLiteral(
"start" ) );
316 QDomElement endElement = document.createElement( QStringLiteral(
"end" ) );
318 const QDomText startText = document.createTextNode( mFixedRange.begin().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
319 const QDomText endText = document.createTextNode( mFixedRange.end().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
320 startElement.appendChild( startText );
321 endElement.appendChild( endText );
322 rangeElement.appendChild( startElement );
323 rangeElement.appendChild( endElement );
325 temporalElement.appendChild( rangeElement );
327 element.appendChild( temporalElement );
336 setIsActive( vectorCaps->hasTemporalCapabilities() );
340 switch ( vectorCaps->mode() )
342 case Qgis::VectorDataProviderTemporalMode::HasFixedTemporalRange:
343 setMode( Qgis::VectorTemporalMode::FixedTemporalRange );
345 case Qgis::VectorDataProviderTemporalMode::StoresFeatureDateTimeInstantInField:
346 setMode( Qgis::VectorTemporalMode::FeatureDateTimeInstantFromField );
348 case Qgis::VectorDataProviderTemporalMode::StoresFeatureDateTimeStartAndEndInSeparateFields:
349 setMode( Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromFields );
357 return mStartExpression;
367 return mEndExpression;
377 return mAccumulateFeatures;
387 return mFixedDuration;
397 return mStartFieldName;
402 mStartFieldName = startFieldName;
407 return mEndFieldName;
412 mEndFieldName =
field;
417 return mDurationFieldName;
422 mDurationFieldName =
field;
427 return mDurationUnit;
432 mDurationUnit = units;
437 return QStringLiteral(
"make_datetime(%1,%2,%3,%4,%5,%6)" ).arg( datetime.date().year() )
438 .arg( datetime.date().month() )
439 .arg( datetime.date().day() )
440 .arg( datetime.time().hour() )
441 .arg( datetime.time().minute() )
442 .arg( datetime.time().second() + datetime.time().msec() / 1000.0 );
450 auto dateTimefieldCast = [ &context ](
const QString & fieldName ) -> QString
463 case Qgis::VectorTemporalMode::FixedTemporalRange:
464 case Qgis::VectorTemporalMode::RedrawLayerOnly:
467 case Qgis::VectorTemporalMode::FeatureDateTimeInstantFromField:
469 if ( mAccumulateFeatures )
471 return QStringLiteral(
"(%1 %2 %3) OR %1 IS NULL" ).arg( dateTimefieldCast( mStartFieldName ),
472 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
477 return QStringLiteral(
"(%1 %2 %3 AND %1 %4 %5) OR %1 IS NULL" ).arg( dateTimefieldCast( mStartFieldName ),
478 filterRange.includeBeginning() ? QStringLiteral(
">=" ) : QStringLiteral(
">" ),
480 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
486 return QStringLiteral(
"(%1 %2 %3 AND %1 %4 %5) OR %1 IS NULL" ).arg( dateTimefieldCast( mStartFieldName ),
489 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
494 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndDurationFromFields:
496 QString intervalExpression;
497 switch ( mDurationUnit )
543 return QStringLiteral(
"(%1 %2 %3 OR %1 IS NULL) AND ((%1 + %4 %5 %6) OR %7 IS NULL)" ).arg( dateTimefieldCast( mStartFieldName ),
544 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
552 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromFields:
554 if ( !mStartFieldName.isEmpty() && !mEndFieldName.isEmpty() )
556 return QStringLiteral(
"(%1 %2 %3 OR %1 IS NULL) AND (%4 %5 %6 OR %4 IS NULL)" ).arg( dateTimefieldCast( mStartFieldName ),
557 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
559 dateTimefieldCast( mEndFieldName ),
564 else if ( !mStartFieldName.isEmpty() )
566 return QStringLiteral(
"%1 %2 %3 OR %1 IS NULL" ).arg( dateTimefieldCast( mStartFieldName ),
567 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
570 else if ( !mEndFieldName.isEmpty() )
572 return QStringLiteral(
"%1 %2 %3 OR %1 IS NULL" ).arg( dateTimefieldCast( mEndFieldName ),
579 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromExpressions:
581 if ( !mStartExpression.isEmpty() && !mEndExpression.isEmpty() )
583 return QStringLiteral(
"((%1) %2 %3) AND ((%4) %5 %6)" ).arg( mStartExpression,
584 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
590 else if ( !mStartExpression.isEmpty() )
592 return QStringLiteral(
"(%1) %2 %3" ).arg( mStartExpression,
593 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
596 else if ( !mEndExpression.isEmpty() )
598 return QStringLiteral(
"(%1) %2 %3" ).arg( mEndExpression,
618 static const QStringList sStartCandidates{ QStringLiteral(
"start" ),
619 QStringLiteral(
"begin" ),
620 QStringLiteral(
"from" )};
622 static const QStringList sEndCandidates{ QStringLiteral(
"end" ),
623 QStringLiteral(
"last" ),
624 QStringLiteral(
"to" )};
626 static const QStringList sSingleFieldCandidates{ QStringLiteral(
"event" ) };
629 bool foundStart =
false;
630 bool foundEnd =
false;
639 for (
const QString &candidate : sStartCandidates )
642 if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
644 mStartFieldName = fldName;
652 for (
const QString &candidate : sEndCandidates )
655 if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
657 mEndFieldName = fldName;
663 if ( foundStart && foundEnd )
675 for (
const QString &candidate : sSingleFieldCandidates )
678 if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
680 mStartFieldName = fldName;
690 if ( foundStart && foundEnd )
691 mMode = Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromFields;
692 else if ( foundStart )
693 mMode = Qgis::VectorTemporalMode::FeatureDateTimeInstantFromField;