QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsvectorlayertemporalproperties.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvectorlayertemporalproperties.cpp
3 ---------------
4 begin : May 2020
5 copyright : (C) 2020 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
20#include "qgsexpression.h"
21#include "qgsvectorlayer.h"
22#include "qgsfields.h"
24#include "qgsunittypes.h"
25
27 : QgsMapLayerTemporalProperties( parent, enabled )
28{
29}
30
32{
33 if ( !isActive() )
34 return true;
35
36 switch ( mMode )
37 {
39 return range.isInfinite() || mFixedRange.isInfinite() || mFixedRange.overlaps( range );
40
46 return true;
47 }
48 return true;
49}
50
52{
53 QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer );
54 if ( !layer )
55 return QgsDateTimeRange();
56
57 switch ( mMode )
58 {
60 return mFixedRange;
61
63 {
64 const int fieldIndex = vectorLayer->fields().lookupField( mStartFieldName );
65 if ( fieldIndex >= 0 )
66 {
67 QVariant minVal;
68 QVariant maxVal;
69 vectorLayer->minimumAndMaximumValue( fieldIndex, minVal, maxVal );
70
71 const QDateTime min = minVal.toDateTime();
72 const QDateTime maxStartTime = maxVal.toDateTime();
73 const QgsInterval eventDuration = QgsInterval( mFixedDuration, mDurationUnit );
74 return QgsDateTimeRange( min, maxStartTime + eventDuration );
75 }
76 break;
77 }
78
80 {
81 const int fieldIndex = vectorLayer->fields().lookupField( mStartFieldName );
82 const int durationFieldIndex = vectorLayer->fields().lookupField( mDurationFieldName );
83 if ( fieldIndex >= 0 && durationFieldIndex >= 0 )
84 {
85 const QDateTime minTime = vectorLayer->minimumValue( fieldIndex ).toDateTime();
86 // no choice here but to loop through all features to calculate max time :(
87
88 QgsFeature f;
89 QgsFeatureIterator it = vectorLayer->getFeatures( QgsFeatureRequest().setFlags( Qgis::FeatureRequestFlag::NoGeometry ).setSubsetOfAttributes( QgsAttributeList() << durationFieldIndex << fieldIndex ) );
90 QDateTime maxTime;
91 while ( it.nextFeature( f ) )
92 {
93 const QDateTime start = f.attribute( fieldIndex ).toDateTime();
94 if ( start.isValid() )
95 {
96 const QVariant durationValue = f.attribute( durationFieldIndex );
97 if ( durationValue.isValid() )
98 {
99 const double duration = durationValue.toDouble();
100 const QDateTime end = start.addMSecs( QgsInterval( duration, mDurationUnit ).seconds() * 1000.0 );
101 if ( end.isValid() )
102 maxTime = maxTime.isValid() ? std::max( maxTime, end ) : end;
103 }
104 }
105 }
106 return QgsDateTimeRange( minTime, maxTime );
107 }
108 break;
109 }
110
112 {
113 const int startFieldIndex = vectorLayer->fields().lookupField( mStartFieldName );
114 const int endFieldIndex = vectorLayer->fields().lookupField( mEndFieldName );
115 if ( startFieldIndex >= 0 && endFieldIndex >= 0 )
116 {
117 QVariant startMinVal;
118 QVariant startMaxVal;
119 vectorLayer->minimumAndMaximumValue( startFieldIndex, startMinVal, startMaxVal );
120 QVariant endMinVal;
121 QVariant endMaxVal;
122 vectorLayer->minimumAndMaximumValue( endFieldIndex, endMinVal, endMaxVal );
123
124 return QgsDateTimeRange( std::min( startMinVal.toDateTime(),
125 endMinVal.toDateTime() ),
126 std::max( startMaxVal.toDateTime(),
127 endMaxVal.toDateTime() ) );
128 }
129 else if ( startFieldIndex >= 0 )
130 {
131 QVariant startMinVal;
132 QVariant startMaxVal;
133 vectorLayer->minimumAndMaximumValue( startFieldIndex, startMinVal, startMaxVal );
134 return QgsDateTimeRange( startMinVal.toDateTime(),
135 startMaxVal.toDateTime() );
136 }
137 else if ( endFieldIndex >= 0 )
138 {
139 QVariant endMinVal;
140 QVariant endMaxVal;
141 vectorLayer->minimumAndMaximumValue( endFieldIndex, endMinVal, endMaxVal );
142 return QgsDateTimeRange( endMinVal.toDateTime(),
143 endMaxVal.toDateTime() );
144 }
145 break;
146 }
147
149 {
150 const bool hasStartExpression = !mStartExpression.isEmpty();
151 const bool hasEndExpression = !mEndExpression.isEmpty();
152 if ( !hasStartExpression && !hasEndExpression )
153 return QgsDateTimeRange();
154
155 QDateTime minTime;
156 QDateTime maxTime;
157
158 // no choice here but to loop through all features
159 QgsExpressionContext context;
161
163 if ( hasStartExpression )
164 {
165 startExpression.setExpression( mStartExpression );
166 startExpression.prepare( &context );
167 }
168
170 if ( hasEndExpression )
171 {
172 endExpression.setExpression( mEndExpression );
173 endExpression.prepare( &context );
174 }
175
176 QSet< QString > fields;
177 if ( hasStartExpression )
178 fields.unite( startExpression.referencedColumns() );
179 if ( hasEndExpression )
180 fields.unite( endExpression.referencedColumns() );
181
182 const bool needsGeom = startExpression.needsGeometry() || endExpression.needsGeometry();
183
185 if ( !needsGeom )
187
188 req.setSubsetOfAttributes( fields, vectorLayer->fields() );
189
190 QgsFeature f;
191 QgsFeatureIterator it = vectorLayer->getFeatures( req );
192 while ( it.nextFeature( f ) )
193 {
194 context.setFeature( f );
195 const QDateTime start = hasStartExpression ? startExpression.evaluate( &context ).toDateTime() : QDateTime();
196 const QDateTime end = hasEndExpression ? endExpression.evaluate( &context ).toDateTime() : QDateTime();
197
198 if ( start.isValid() )
199 {
200 minTime = minTime.isValid() ? std::min( minTime, start ) : start;
201 if ( !hasEndExpression )
202 maxTime = maxTime.isValid() ? std::max( maxTime, start ) : start;
203 }
204 if ( end.isValid() )
205 {
206 maxTime = maxTime.isValid() ? std::max( maxTime, end ) : end;
207 if ( !hasStartExpression )
208 minTime = minTime.isValid() ? std::min( minTime, end ) : end;
209 }
210 }
211 return QgsDateTimeRange( minTime, maxTime );
212 }
213
215 break;
216 }
217
218 return QgsDateTimeRange();
219}
220
222{
223 return mMode;
224}
225
227{
228 if ( mMode == mode )
229 return;
230 mMode = mode;
231}
232
234{
235 return mLimitMode;
236}
237
239{
240 if ( mLimitMode == limitMode )
241 return;
242 mLimitMode = limitMode;
243}
244
246{
248}
249
251{
252 mFixedRange = range;
253}
254
256{
257 return mFixedRange;
258}
259
260bool QgsVectorLayerTemporalProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
261{
262 Q_UNUSED( context )
263
264 const QDomElement temporalNode = element.firstChildElement( QStringLiteral( "temporal" ) );
265
266 setIsActive( temporalNode.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt() );
267
268 mMode = static_cast< Qgis::VectorTemporalMode >( temporalNode.attribute( QStringLiteral( "mode" ), QStringLiteral( "0" ) ). toInt() );
269
270 mLimitMode = static_cast< Qgis::VectorTemporalLimitMode >( temporalNode.attribute( QStringLiteral( "limitMode" ), QStringLiteral( "0" ) ). toInt() );
271 mStartFieldName = temporalNode.attribute( QStringLiteral( "startField" ) );
272 mEndFieldName = temporalNode.attribute( QStringLiteral( "endField" ) );
273 mStartExpression = temporalNode.attribute( QStringLiteral( "startExpression" ) );
274 mEndExpression = temporalNode.attribute( QStringLiteral( "endExpression" ) );
275 mDurationFieldName = temporalNode.attribute( QStringLiteral( "durationField" ) );
276 mDurationUnit = QgsUnitTypes::decodeTemporalUnit( temporalNode.attribute( QStringLiteral( "durationUnit" ), QgsUnitTypes::encodeUnit( Qgis::TemporalUnit::Minutes ) ) );
277 mFixedDuration = temporalNode.attribute( QStringLiteral( "fixedDuration" ) ).toDouble();
278 mAccumulateFeatures = temporalNode.attribute( QStringLiteral( "accumulate" ), QStringLiteral( "0" ) ).toInt();
279
280 const QDomNode rangeElement = temporalNode.namedItem( QStringLiteral( "fixedRange" ) );
281
282 const QDomNode begin = rangeElement.namedItem( QStringLiteral( "start" ) );
283 const QDomNode end = rangeElement.namedItem( QStringLiteral( "end" ) );
284
285 const QDateTime beginDate = QDateTime::fromString( begin.toElement().text(), Qt::ISODate );
286 const QDateTime endDate = QDateTime::fromString( end.toElement().text(), Qt::ISODate );
287
288 const QgsDateTimeRange range = QgsDateTimeRange( beginDate, endDate );
289 setFixedTemporalRange( range );
290
291 return true;
292}
293
294QDomElement QgsVectorLayerTemporalProperties::writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context )
295{
296 Q_UNUSED( context )
297 if ( element.isNull() )
298 return QDomElement();
299
300 QDomElement temporalElement = document.createElement( QStringLiteral( "temporal" ) );
301 temporalElement.setAttribute( QStringLiteral( "enabled" ), isActive() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
302 temporalElement.setAttribute( QStringLiteral( "mode" ), QString::number( static_cast< int >( mMode ) ) );
303
304 temporalElement.setAttribute( QStringLiteral( "limitMode" ), QString::number( static_cast< int >( mLimitMode ) ) );
305 temporalElement.setAttribute( QStringLiteral( "startField" ), mStartFieldName );
306 temporalElement.setAttribute( QStringLiteral( "endField" ), mEndFieldName );
307 temporalElement.setAttribute( QStringLiteral( "startExpression" ), mStartExpression );
308 temporalElement.setAttribute( QStringLiteral( "endExpression" ), mEndExpression );
309 temporalElement.setAttribute( QStringLiteral( "durationField" ), mDurationFieldName );
310 temporalElement.setAttribute( QStringLiteral( "durationUnit" ), QgsUnitTypes::encodeUnit( mDurationUnit ) );
311 temporalElement.setAttribute( QStringLiteral( "fixedDuration" ), qgsDoubleToString( mFixedDuration ) );
312 temporalElement.setAttribute( QStringLiteral( "accumulate" ), mAccumulateFeatures ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
313
314 QDomElement rangeElement = document.createElement( QStringLiteral( "fixedRange" ) );
315
316 QDomElement startElement = document.createElement( QStringLiteral( "start" ) );
317 QDomElement endElement = document.createElement( QStringLiteral( "end" ) );
318
319 const QDomText startText = document.createTextNode( mFixedRange.begin().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
320 const QDomText endText = document.createTextNode( mFixedRange.end().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
321 startElement.appendChild( startText );
322 endElement.appendChild( endText );
323 rangeElement.appendChild( startElement );
324 rangeElement.appendChild( endElement );
325
326 temporalElement.appendChild( rangeElement );
327
328 element.appendChild( temporalElement );
329
330 return element;
331}
332
334{
335 if ( const QgsVectorDataProviderTemporalCapabilities *vectorCaps = dynamic_cast< const QgsVectorDataProviderTemporalCapabilities *>( capabilities ) )
336 {
337 setIsActive( vectorCaps->hasTemporalCapabilities() );
338 setFixedTemporalRange( vectorCaps->availableTemporalRange() );
339 setStartField( vectorCaps->startField() );
340 setEndField( vectorCaps->endField() );
341 switch ( vectorCaps->mode() )
342 {
345 break;
348 break;
351 break;
352 }
353 }
354}
355
357{
358 return mStartExpression;
359}
360
361void QgsVectorLayerTemporalProperties::setStartExpression( const QString &startExpression )
362{
363 mStartExpression = startExpression;
364}
365
367{
368 return mEndExpression;
369}
370
371void QgsVectorLayerTemporalProperties::setEndExpression( const QString &endExpression )
372{
373 mEndExpression = endExpression;
374}
375
377{
378 return mAccumulateFeatures;
379}
380
382{
383 mAccumulateFeatures = accumulateFeatures;
384}
385
387{
388 return mFixedDuration;
389}
390
392{
393 mFixedDuration = fixedDuration;
394}
395
397{
398 return mStartFieldName;
399}
400
401void QgsVectorLayerTemporalProperties::setStartField( const QString &startFieldName )
402{
403 mStartFieldName = startFieldName;
404}
405
407{
408 return mEndFieldName;
409}
410
412{
413 mEndFieldName = field;
414}
415
417{
418 return mDurationFieldName;
419}
420
422{
423 mDurationFieldName = field;
424}
425
427{
428 return mDurationUnit;
429}
430
432{
433 mDurationUnit = units;
434}
435
436QString dateTimeExpressionLiteral( const QDateTime &datetime )
437{
438 return QStringLiteral( "make_datetime(%1,%2,%3,%4,%5,%6)" ).arg( datetime.date().year() )
439 .arg( datetime.date().month() )
440 .arg( datetime.date().day() )
441 .arg( datetime.time().hour() )
442 .arg( datetime.time().minute() )
443 .arg( datetime.time().second() + datetime.time().msec() / 1000.0 );
444}
445
447{
448 if ( !isActive() )
449 return QString();
450
451 auto dateTimefieldCast = [ &context ]( const QString & fieldName ) -> QString
452 {
453 if ( context.layer()
454 && context.layer()->fields().lookupField( fieldName ) >= 0
455 && context.layer()->fields().at( context.layer()->fields().lookupField( fieldName ) ).type() != QVariant::DateTime )
456 {
457 return QStringLiteral( "to_datetime( %1 )" ) .arg( QgsExpression::quotedColumnRef( fieldName ) );
458 }
459 return QgsExpression::quotedColumnRef( fieldName );
460 };
461
462 switch ( mMode )
463 {
466 return QString();
467
469 {
470 if ( mAccumulateFeatures )
471 {
472 return QStringLiteral( "(%1 %2 %3) OR %1 IS NULL" ).arg( dateTimefieldCast( mStartFieldName ),
473 filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
474 dateTimeExpressionLiteral( filterRange.end() ) );
475 }
476 else if ( qgsDoubleNear( mFixedDuration, 0.0 ) )
477 {
478 return QStringLiteral( "(%1 %2 %3 AND %1 %4 %5) OR %1 IS NULL" ).arg( dateTimefieldCast( mStartFieldName ),
479 filterRange.includeBeginning() ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
480 dateTimeExpressionLiteral( filterRange.begin() ),
481 filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
482 dateTimeExpressionLiteral( filterRange.end() ) );
483 }
484 else
485 {
486 // Working with features with events with a duration, so taking this duration into account (+ QgsInterval( -mFixedDuration, mDurationUnit ) ))
487 return QStringLiteral( "(%1 %2 %3 AND %1 %4 %5) OR %1 IS NULL" ).arg( dateTimefieldCast( mStartFieldName ),
488 limitMode() == Qgis::VectorTemporalLimitMode::IncludeBeginIncludeEnd ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
489 dateTimeExpressionLiteral( filterRange.begin() + QgsInterval( -mFixedDuration, mDurationUnit ) ),
490 filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
491 dateTimeExpressionLiteral( filterRange.end() ) );
492 }
493 }
494
496 {
497 QString intervalExpression;
498 switch ( mDurationUnit )
499 {
501 intervalExpression = QStringLiteral( "make_interval(0,0,0,0,0,0,%1/1000)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
502 break;
503
505 intervalExpression = QStringLiteral( "make_interval(0,0,0,0,0,0,%1)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
506 break;
507
509 intervalExpression = QStringLiteral( "make_interval(0,0,0,0,0,%1,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
510 break;
511
513 intervalExpression = QStringLiteral( "make_interval(0,0,0,0,%1,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
514 break;
515
517 intervalExpression = QStringLiteral( "make_interval(0,0,0,%1,0,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
518 break;
519
521 intervalExpression = QStringLiteral( "make_interval(0,0,%1,0,0,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
522 break;
523
525 intervalExpression = QStringLiteral( "make_interval(0,%1,0,0,0,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
526 break;
527
529 intervalExpression = QStringLiteral( "make_interval(%1,0,0,0,0,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
530 break;
531
533 intervalExpression = QStringLiteral( "make_interval(10 * %1,0,0,0,0,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
534 break;
535
537 intervalExpression = QStringLiteral( "make_interval(100 * %1,0,0,0,0,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
538 break;
539
542 return QString();
543 }
544 return QStringLiteral( "(%1 %2 %3 OR %1 IS NULL) AND ((%1 + %4 %5 %6) OR %7 IS NULL)" ).arg( dateTimefieldCast( mStartFieldName ),
545 filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
546 dateTimeExpressionLiteral( filterRange.end() ),
547 intervalExpression,
548 limitMode() == Qgis::VectorTemporalLimitMode::IncludeBeginIncludeEnd ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
549 dateTimeExpressionLiteral( filterRange.begin() ),
550 QgsExpression::quotedColumnRef( mDurationFieldName ) );
551 }
552
554 {
555 if ( !mStartFieldName.isEmpty() && !mEndFieldName.isEmpty() )
556 {
557 return QStringLiteral( "(%1 %2 %3 OR %1 IS NULL) AND (%4 %5 %6 OR %4 IS NULL)" ).arg( dateTimefieldCast( mStartFieldName ),
558 filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
559 dateTimeExpressionLiteral( filterRange.end() ),
560 dateTimefieldCast( mEndFieldName ),
561 limitMode() == Qgis::VectorTemporalLimitMode::IncludeBeginIncludeEnd ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
562 dateTimeExpressionLiteral( filterRange.begin() ) );
563
564 }
565 else if ( !mStartFieldName.isEmpty() )
566 {
567 return QStringLiteral( "%1 %2 %3 OR %1 IS NULL" ).arg( dateTimefieldCast( mStartFieldName ),
568 filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
569 dateTimeExpressionLiteral( filterRange.end() ) );
570 }
571 else if ( !mEndFieldName.isEmpty() )
572 {
573 return QStringLiteral( "%1 %2 %3 OR %1 IS NULL" ).arg( dateTimefieldCast( mEndFieldName ),
574 limitMode() == Qgis::VectorTemporalLimitMode::IncludeBeginIncludeEnd ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
575 dateTimeExpressionLiteral( filterRange.begin() ) );
576 }
577 break;
578 }
579
581 {
582 if ( !mStartExpression.isEmpty() && !mEndExpression.isEmpty() )
583 {
584 return QStringLiteral( "((%1) %2 %3) AND ((%4) %5 %6)" ).arg( mStartExpression,
585 filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
586 dateTimeExpressionLiteral( filterRange.end() ),
587 mEndExpression,
588 limitMode() == Qgis::VectorTemporalLimitMode::IncludeBeginIncludeEnd ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
589 dateTimeExpressionLiteral( filterRange.begin() ) );
590 }
591 else if ( !mStartExpression.isEmpty() )
592 {
593 return QStringLiteral( "(%1) %2 %3" ).arg( mStartExpression,
594 filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
595 dateTimeExpressionLiteral( filterRange.end() ) );
596 }
597 else if ( !mEndExpression.isEmpty() )
598 {
599 return QStringLiteral( "(%1) %2 %3" ).arg( mEndExpression,
600 limitMode() == Qgis::VectorTemporalLimitMode::IncludeBeginIncludeEnd ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
601 dateTimeExpressionLiteral( filterRange.begin() ) );
602 }
603 break;
604 }
605 }
606
607 return QString();
608}
609
611{
612
613 // Check the fields and keep the first one that matches.
614 // We assume that the user has organized the data with the
615 // more "interesting" field names first.
616 // This candidates list is a prioritized list of candidates ranked by "interestingness"!
617 // See discussion at https://github.com/qgis/QGIS/pull/30245 - this list must NOT be translated,
618 // but adding hardcoded localized variants of the strings is encouraged.
619 static const QStringList sStartCandidates{ QStringLiteral( "start" ),
620 QStringLiteral( "begin" ),
621 QStringLiteral( "from" ),
622 QStringLiteral( "since" ),
623 // German candidates
624 QStringLiteral( "anfang" ),
625 QStringLiteral( "von" ),
626 QStringLiteral( "ab" ),
627 QStringLiteral( "seit" ) };
628
629 static const QStringList sEndCandidates{ QStringLiteral( "end" ),
630 QStringLiteral( "last" ),
631 QStringLiteral( "to" ),
632 QStringLiteral( "stop" ),
633 // German candidates
634 QStringLiteral( "ende" ),
635 QStringLiteral( "bis" ) };
636
637
638 static const QStringList sSingleFieldCandidates{ QStringLiteral( "event" ) };
639
640
641 bool foundStart = false;
642 bool foundEnd = false;
643
644 for ( const QgsField &field : fields )
645 {
646 if ( field.type() != QVariant::Date && field.type() != QVariant::DateTime )
647 continue;
648
649 if ( !foundStart )
650 {
651 for ( const QString &candidate : sStartCandidates )
652 {
653 const QString fldName = field.name();
654 if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
655 {
656 mStartFieldName = fldName;
657 foundStart = true;
658 }
659 }
660 }
661
662 if ( !foundEnd )
663 {
664 for ( const QString &candidate : sEndCandidates )
665 {
666 const QString fldName = field.name();
667 if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
668 {
669 mEndFieldName = fldName;
670 foundEnd = true;
671 }
672 }
673 }
674
675 if ( foundStart && foundEnd )
676 break;
677 }
678
679 if ( !foundStart )
680 {
681 // loop again, looking for likely "single field" candidates
682 for ( const QgsField &field : fields )
683 {
684 if ( field.type() != QVariant::Date && field.type() != QVariant::DateTime )
685 continue;
686
687 for ( const QString &candidate : sSingleFieldCandidates )
688 {
689 const QString fldName = field.name();
690 if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
691 {
692 mStartFieldName = fldName;
693 foundStart = true;
694 }
695 }
696
697 if ( foundStart )
698 break;
699 }
700 }
701
702 if ( foundStart && foundEnd )
704 else if ( foundStart )
706
707 // note -- NEVER auto enable temporal properties here! It's just a helper designed
708 // to shortcut the initial field selection
709}
710
712{
713 return mLayer;
714}
715
717{
718 mLayer = layer;
719}
VectorTemporalMode
Vector layer temporal feature modes.
Definition: qgis.h:2102
@ FeatureDateTimeStartAndDurationFromFields
Mode when features have a field for start time and a field for event duration.
@ RedrawLayerOnly
Redraw the layer when temporal range changes, but don't apply any filtering. Useful when symbology or...
@ FeatureDateTimeStartAndEndFromExpressions
Mode when features use expressions for start and end times.
@ FeatureDateTimeInstantFromField
Mode when features have a datetime instant taken from a single field.
@ FixedTemporalRange
Mode when temporal properties have fixed start and end datetimes.
@ FeatureDateTimeStartAndEndFromFields
Mode when features have separate fields for start and end times.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
TemporalUnit
Temporal units.
Definition: qgis.h:4231
@ IrregularStep
Special 'irregular step' time unit, used for temporal data which uses irregular, non-real-world unit ...
@ Milliseconds
Milliseconds.
@ Unknown
Unknown time unit.
@ Centuries
Centuries.
@ StoresFeatureDateTimeInstantInField
Dataset has feature datetime instants stored in a single field.
@ StoresFeatureDateTimeStartAndEndInSeparateFields
Dataset stores feature start and end datetimes in separate fields.
@ HasFixedTemporalRange
Entire dataset from provider has a fixed start and end datetime.
VectorTemporalLimitMode
Mode for the handling of the limits of the filtering timeframe for vector features.
Definition: qgis.h:2118
@ IncludeBeginIncludeEnd
Mode to include both limits of the filtering timeframe.
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)
Fetch next feature and stores in f, returns true on success.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:335
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:53
QVariant::Type type
Definition: qgsfield.h:60
Container of fields for a vector layer.
Definition: qgsfields.h:45
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:359
A representation of the interval between two datetime values.
Definition: qgsinterval.h:46
Base class for storage of map layer temporal properties.
Base class for all map layer types.
Definition: qgsmaplayer.h:75
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.
T begin() const
Returns the beginning of the range.
Definition: qgsrange.h:444
T end() const
Returns the upper bound of the range.
Definition: qgsrange.h:451
bool overlaps(const QgsTemporalRange< T > &other) const
Returns true if this range overlaps another range.
Definition: qgsrange.h:569
bool includeEnd() const
Returns true if the end is inclusive, or false if the end is exclusive.
Definition: qgsrange.h:466
bool includeBeginning() const
Returns true if the beginning is inclusive, or false if the beginning is exclusive.
Definition: qgsrange.h:459
bool isInfinite() const
Returns true if the range consists of all possible values.
Definition: qgsrange.h:480
static Q_INVOKABLE Qgis::TemporalUnit decodeTemporalUnit(const QString &string, bool *ok=nullptr)
Decodes a temporal unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
Implementation of data provider temporal properties for QgsVectorDataProviders.
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.
void setMode(Qgis::VectorTemporalMode mode)
Sets the temporal properties mode.
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.
bool isVisibleInTemporalRange(const QgsDateTimeRange &range) const override
Returns true if the layer should be visible and rendered for the specified time range.
Qgis::VectorTemporalLimitMode limitMode() const
Returns the temporal limit mode (to include or exclude begin/end limits).
void setLimitMode(Qgis::VectorTemporalLimitMode mode)
Sets the temporal limit mode (to include or exclude begin/end limits).
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.
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.
QString durationField() const
Returns the name of the duration field, which contains the duration of the event.
void setDurationUnits(Qgis::TemporalUnit units)
Sets the units of the event's duration.
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 ...
QDomElement writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) override
Writes the properties to a DOM element, to be used later with readXml().
Qgis::TemporalUnit durationUnits() const
Returns the units of the event's duration.
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...
Qgis::VectorTemporalMode mode() const
Returns the temporal properties mode.
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.
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.
void minimumAndMaximumValue(int index, QVariant &minimum, QVariant &maximum) const
Calculates both the minimum and maximum value for an attribute column.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:5124
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5207
QList< int > QgsAttributeList
Definition: qgsfield.h:27
QgsTemporalRange< QDateTime > QgsDateTimeRange
QgsRange which stores a range of date times.
Definition: qgsrange.h:742
QString dateTimeExpressionLiteral(const QDateTime &datetime)