QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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 
26  : QgsMapLayerTemporalProperties( parent, enabled )
27 {
28 }
29 
30 bool QgsVectorLayerTemporalProperties::isVisibleInTemporalRange( const QgsDateTimeRange &range ) const
31 {
32  if ( !isActive() )
33  return true;
34 
35  switch ( mMode )
36  {
38  return range.isInfinite() || mFixedRange.isInfinite() || mFixedRange.overlaps( range );
39 
45  return true;
46  }
47  return true;
48 }
49 
51 {
52  QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer );
53  if ( !layer )
54  return QgsDateTimeRange();
55 
56  switch ( mMode )
57  {
59  return mFixedRange;
60 
62  {
63  const int fieldIndex = vectorLayer->fields().lookupField( mStartFieldName );
64  if ( fieldIndex >= 0 )
65  {
66  const QDateTime min = vectorLayer->minimumValue( fieldIndex ).toDateTime();
67  const QDateTime maxStartTime = vectorLayer->maximumValue( fieldIndex ).toDateTime();
68  const QgsInterval eventDuration = QgsInterval( mFixedDuration, mDurationUnit );
69  return QgsDateTimeRange( min, maxStartTime + eventDuration );
70  }
71  break;
72  }
73 
75  {
76  const int fieldIndex = vectorLayer->fields().lookupField( mStartFieldName );
77  const int durationFieldIndex = vectorLayer->fields().lookupField( mDurationFieldName );
78  if ( fieldIndex >= 0 && durationFieldIndex >= 0 )
79  {
80  const QDateTime minTime = vectorLayer->minimumValue( fieldIndex ).toDateTime();
81  // no choice here but to loop through all features to calculate max time :(
82 
83  QgsFeature f;
84  QgsFeatureIterator it = vectorLayer->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes( QgsAttributeList() << durationFieldIndex << fieldIndex ) );
85  QDateTime maxTime;
86  while ( it.nextFeature( f ) )
87  {
88  const QDateTime start = f.attribute( fieldIndex ).toDateTime();
89  if ( start.isValid() )
90  {
91  const QVariant durationValue = f.attribute( durationFieldIndex );
92  if ( durationValue.isValid() )
93  {
94  const double duration = durationValue.toDouble();
95  const QDateTime end = start.addMSecs( QgsInterval( duration, mDurationUnit ).seconds() * 1000.0 );
96  if ( end.isValid() )
97  maxTime = maxTime.isValid() ? std::max( maxTime, end ) : end;
98  }
99  }
100  }
101  return QgsDateTimeRange( minTime, maxTime );
102  }
103  break;
104  }
105 
107  {
108  const int startFieldIndex = vectorLayer->fields().lookupField( mStartFieldName );
109  const int endFieldIndex = vectorLayer->fields().lookupField( mEndFieldName );
110  if ( startFieldIndex >= 0 && endFieldIndex >= 0 )
111  {
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() ) );
116  }
117  else if ( startFieldIndex >= 0 )
118  {
119  return QgsDateTimeRange( vectorLayer->minimumValue( startFieldIndex ).toDateTime(),
120  vectorLayer->maximumValue( startFieldIndex ).toDateTime() );
121  }
122  else if ( endFieldIndex >= 0 )
123  {
124  return QgsDateTimeRange( vectorLayer->minimumValue( endFieldIndex ).toDateTime(),
125  vectorLayer->maximumValue( endFieldIndex ).toDateTime() );
126  }
127  break;
128  }
129 
131  {
132  bool hasStartExpression = !mStartExpression.isEmpty();
133  bool hasEndExpression = !mEndExpression.isEmpty();
134  if ( !hasStartExpression && !hasEndExpression )
135  return QgsDateTimeRange();
136 
137  QDateTime minTime;
138  QDateTime maxTime;
139 
140  // no choice here but to loop through all features
141  QgsExpressionContext context;
143 
145  if ( hasStartExpression )
146  {
147  startExpression.setExpression( mStartExpression );
148  startExpression.prepare( &context );
149  }
150 
152  if ( hasEndExpression )
153  {
154  endExpression.setExpression( mEndExpression );
155  endExpression.prepare( &context );
156  }
157 
158  QSet< QString > fields;
159  if ( hasStartExpression )
160  fields.unite( startExpression.referencedColumns() );
161  if ( hasEndExpression )
162  fields.unite( endExpression.referencedColumns() );
163 
164  const bool needsGeom = startExpression.needsGeometry() || endExpression.needsGeometry();
165 
166  QgsFeatureRequest req;
167  if ( !needsGeom )
169 
170  req.setSubsetOfAttributes( fields, vectorLayer->fields() );
171 
172  QgsFeature f;
173  QgsFeatureIterator it = vectorLayer->getFeatures( req );
174  while ( it.nextFeature( f ) )
175  {
176  context.setFeature( f );
177  const QDateTime start = hasStartExpression ? startExpression.evaluate( &context ).toDateTime() : QDateTime();
178  const QDateTime end = hasEndExpression ? endExpression.evaluate( &context ).toDateTime() : QDateTime();
179 
180  if ( start.isValid() )
181  {
182  minTime = minTime.isValid() ? std::min( minTime, start ) : start;
183  if ( !hasEndExpression )
184  maxTime = maxTime.isValid() ? std::max( maxTime, start ) : start;
185  }
186  if ( end.isValid() )
187  {
188  maxTime = maxTime.isValid() ? std::max( maxTime, end ) : end;
189  if ( !hasStartExpression )
190  minTime = minTime.isValid() ? std::min( minTime, end ) : end;
191  }
192  }
193  return QgsDateTimeRange( minTime, maxTime );
194  }
195 
197  break;
198  }
199 
200  return QgsDateTimeRange();
201 }
202 
204 {
205  return mMode;
206 }
207 
209 {
210  if ( mMode == mode )
211  return;
212  mMode = mode;
213 }
214 
215 QgsTemporalProperty::Flags QgsVectorLayerTemporalProperties::flags() const
216 {
218 }
219 
220 void QgsVectorLayerTemporalProperties::setFixedTemporalRange( const QgsDateTimeRange &range )
221 {
222  mFixedRange = range;
223 }
224 
226 {
227  return mFixedRange;
228 }
229 
230 bool QgsVectorLayerTemporalProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
231 {
232  Q_UNUSED( context )
233 
234  QDomElement temporalNode = element.firstChildElement( QStringLiteral( "temporal" ) );
235 
236  setIsActive( temporalNode.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt() );
237 
238  mMode = static_cast< TemporalMode >( temporalNode.attribute( QStringLiteral( "mode" ), QStringLiteral( "0" ) ). toInt() );
239 
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" ) );
245  mDurationUnit = QgsUnitTypes::decodeTemporalUnit( temporalNode.attribute( QStringLiteral( "durationUnit" ), QgsUnitTypes::encodeUnit( QgsUnitTypes::TemporalMinutes ) ) );
246  mFixedDuration = temporalNode.attribute( QStringLiteral( "fixedDuration" ) ).toDouble();
247  mAccumulateFeatures = temporalNode.attribute( QStringLiteral( "accumulate" ), QStringLiteral( "0" ) ).toInt();
248 
249  QDomNode rangeElement = temporalNode.namedItem( QStringLiteral( "fixedRange" ) );
250 
251  QDomNode begin = rangeElement.namedItem( QStringLiteral( "start" ) );
252  QDomNode end = rangeElement.namedItem( QStringLiteral( "end" ) );
253 
254  QDateTime beginDate = QDateTime::fromString( begin.toElement().text(), Qt::ISODate );
255  QDateTime endDate = QDateTime::fromString( end.toElement().text(), Qt::ISODate );
256 
257  QgsDateTimeRange range = QgsDateTimeRange( beginDate, endDate );
258  setFixedTemporalRange( range );
259 
260  return true;
261 }
262 
263 QDomElement QgsVectorLayerTemporalProperties::writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context )
264 {
265  Q_UNUSED( context )
266  if ( element.isNull() )
267  return QDomElement();
268 
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 ) );
272 
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 );
278  temporalElement.setAttribute( QStringLiteral( "durationUnit" ), QgsUnitTypes::encodeUnit( mDurationUnit ) );
279  temporalElement.setAttribute( QStringLiteral( "fixedDuration" ), qgsDoubleToString( mFixedDuration ) );
280  temporalElement.setAttribute( QStringLiteral( "accumulate" ), mAccumulateFeatures ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
281 
282  QDomElement rangeElement = document.createElement( QStringLiteral( "fixedRange" ) );
283 
284  QDomElement startElement = document.createElement( QStringLiteral( "start" ) );
285  QDomElement endElement = document.createElement( QStringLiteral( "end" ) );
286 
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 );
293 
294  temporalElement.appendChild( rangeElement );
295 
296  element.appendChild( temporalElement );
297 
298  return element;
299 }
300 
302 {
303  if ( const QgsVectorDataProviderTemporalCapabilities *vectorCaps = dynamic_cast< const QgsVectorDataProviderTemporalCapabilities *>( capabilities ) )
304  {
305  setIsActive( vectorCaps->hasTemporalCapabilities() );
306  setFixedTemporalRange( vectorCaps->availableTemporalRange() );
307  setStartField( vectorCaps->startField() );
308  setEndField( vectorCaps->endField() );
309  switch ( vectorCaps->mode() )
310  {
313  break;
316  break;
319  break;
320  }
321  }
322 }
323 
325 {
326  return mStartExpression;
327 }
328 
329 void QgsVectorLayerTemporalProperties::setStartExpression( const QString &startExpression )
330 {
331  mStartExpression = startExpression;
332 }
333 
335 {
336  return mEndExpression;
337 }
338 
339 void QgsVectorLayerTemporalProperties::setEndExpression( const QString &endExpression )
340 {
341  mEndExpression = endExpression;
342 }
343 
345 {
346  return mAccumulateFeatures;
347 }
348 
350 {
351  mAccumulateFeatures = accumulateFeatures;
352 }
353 
355 {
356  return mFixedDuration;
357 }
358 
360 {
361  mFixedDuration = fixedDuration;
362 }
363 
365 {
366  return mStartFieldName;
367 }
368 
369 void QgsVectorLayerTemporalProperties::setStartField( const QString &startFieldName )
370 {
371  mStartFieldName = startFieldName;
372 }
373 
375 {
376  return mEndFieldName;
377 }
378 
380 {
381  mEndFieldName = field;
382 }
383 
385 {
386  return mDurationFieldName;
387 }
388 
390 {
391  mDurationFieldName = field;
392 }
393 
395 {
396  return mDurationUnit;
397 }
398 
400 {
401  mDurationUnit = units;
402 }
403 
404 QString dateTimeExpressionLiteral( const QDateTime &datetime )
405 {
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 );
412 }
413 
414 QString QgsVectorLayerTemporalProperties::createFilterString( const QgsVectorLayerTemporalContext &, const QgsDateTimeRange &range ) const
415 {
416  if ( !isActive() )
417  return QString();
418 
419  switch ( mMode )
420  {
422  case ModeRedrawLayerOnly:
423  return QString();
424 
426  {
427  if ( mAccumulateFeatures )
428  {
429  return QStringLiteral( "(%1 %2 %3) OR %1 IS NULL" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
430  range.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
431  dateTimeExpressionLiteral( range.end() ) );
432  }
433  else if ( qgsDoubleNear( mFixedDuration, 0.0 ) )
434  {
435  return QStringLiteral( "(%1 %2 %3 AND %1 %4 %5) OR %1 IS NULL" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
436  range.includeBeginning() ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
437  dateTimeExpressionLiteral( range.begin() ),
438  range.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
439  dateTimeExpressionLiteral( range.end() ) );
440  }
441  else
442  {
443  // Working with features with events with a duration, so taking this duration into account (+ QgsInterval( -mFixedDuration, mDurationUnit ) ))
444  // Then we are NOT taking the range.includeBeginning() and range.includeEnd() into account (deliberately, see #38468)
445  return QStringLiteral( "(%1 > %2 AND %1 < %3) OR %1 IS NULL" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
446  dateTimeExpressionLiteral( range.begin() + QgsInterval( -mFixedDuration, mDurationUnit ) ),
447  dateTimeExpressionLiteral( range.end() ) );
448  }
449  }
450 
452  {
453  QString intervalExpression;
454  switch ( mDurationUnit )
455  {
457  intervalExpression = QStringLiteral( "make_interval(0,0,0,0,0,0,%1/1000)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
458  break;
459 
461  intervalExpression = QStringLiteral( "make_interval(0,0,0,0,0,0,%1)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
462  break;
463 
465  intervalExpression = QStringLiteral( "make_interval(0,0,0,0,0,%1,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
466  break;
467 
469  intervalExpression = QStringLiteral( "make_interval(0,0,0,0,%1,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
470  break;
471 
473  intervalExpression = QStringLiteral( "make_interval(0,0,0,%1,0,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
474  break;
475 
477  intervalExpression = QStringLiteral( "make_interval(0,0,%1,0,0,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
478  break;
479 
481  intervalExpression = QStringLiteral( "make_interval(0,%1,0,0,0,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
482  break;
483 
485  intervalExpression = QStringLiteral( "make_interval(%1,0,0,0,0,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
486  break;
487 
489  intervalExpression = QStringLiteral( "make_interval(10 * %1,0,0,0,0,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
490  break;
491 
493  intervalExpression = QStringLiteral( "make_interval(100 * %1,0,0,0,0,0,0)" ).arg( QgsExpression::quotedColumnRef( mDurationFieldName ) );
494  break;
495 
497  return QString();
498  }
499  return QStringLiteral( "(%1 %2 %3 OR %1 IS NULL) AND ((%1 + %4 %5 %6) OR %7 IS NULL)" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
500  range.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
501  dateTimeExpressionLiteral( range.end() ),
502  intervalExpression,
503  range.includeBeginning() ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
504  dateTimeExpressionLiteral( range.begin() ),
505  QgsExpression::quotedColumnRef( mDurationFieldName ) );
506  break;
507  }
508 
510  {
511  if ( !mStartFieldName.isEmpty() && !mEndFieldName.isEmpty() )
512  {
513  return QStringLiteral( "(%1 %2 %3 OR %1 IS NULL) AND (%4 %5 %6 OR %4 IS NULL)" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
514  range.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
515  dateTimeExpressionLiteral( range.end() ),
516  QgsExpression::quotedColumnRef( mEndFieldName ),
517  range.includeBeginning() ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
518  dateTimeExpressionLiteral( range.begin() ) );
519  }
520  else if ( !mStartFieldName.isEmpty() )
521  {
522  return QStringLiteral( "%1 %2 %3 OR %1 IS NULL" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
523  range.includeBeginning() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
524  dateTimeExpressionLiteral( range.end() ) );
525  }
526  else if ( !mEndFieldName.isEmpty() )
527  {
528  return QStringLiteral( "%1 %2 %3 OR %1 IS NULL" ).arg( QgsExpression::quotedColumnRef( mEndFieldName ),
529  range.includeBeginning() ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
530  dateTimeExpressionLiteral( range.begin() ) );
531  }
532  break;
533  }
534 
536  {
537  if ( !mStartExpression.isEmpty() && !mEndExpression.isEmpty() )
538  {
539  return QStringLiteral( "((%1) %2 %3) AND ((%4) %5 %6)" ).arg( mStartExpression,
540  range.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
541  dateTimeExpressionLiteral( range.end() ),
542  mEndExpression,
543  range.includeBeginning() ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
544  dateTimeExpressionLiteral( range.begin() ) );
545  }
546  else if ( !mStartExpression.isEmpty() )
547  {
548  return QStringLiteral( "(%1) %2 %3" ).arg( mStartExpression,
549  range.includeBeginning() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
550  dateTimeExpressionLiteral( range.end() ) );
551  }
552  else if ( !mEndExpression.isEmpty() )
553  {
554  return QStringLiteral( "(%1) %2 %3" ).arg( mEndExpression,
555  range.includeBeginning() ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
556  dateTimeExpressionLiteral( range.begin() ) );
557  }
558  break;
559  }
560  }
561 
562  return QString();
563 }
564 
566 {
567 
568  // Check the fields and keep the first one that matches.
569  // We assume that the user has organized the data with the
570  // more "interesting" field names first.
571  // This candidates list is a prioritized list of candidates ranked by "interestingness"!
572  // See discussion at https://github.com/qgis/QGIS/pull/30245 - this list must NOT be translated,
573  // but adding hardcoded localized variants of the strings is encouraged.
574  static QStringList sStartCandidates{ QStringLiteral( "start" ),
575  QStringLiteral( "begin" ),
576  QStringLiteral( "from" )};
577 
578  static QStringList sEndCandidates{ QStringLiteral( "end" ),
579  QStringLiteral( "last" ),
580  QStringLiteral( "to" )};
581 
582  static QStringList sSingleFieldCandidates{ QStringLiteral( "event" ) };
583 
584 
585  bool foundStart = false;
586  bool foundEnd = false;
587 
588  for ( const QgsField &field : fields )
589  {
590  if ( field.type() != QVariant::Date && field.type() != QVariant::DateTime )
591  continue;
592 
593  if ( !foundStart )
594  {
595  for ( const QString &candidate : sStartCandidates )
596  {
597  QString fldName = field.name();
598  if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
599  {
600  mStartFieldName = fldName;
601  foundStart = true;
602  }
603  }
604  }
605 
606  if ( !foundEnd )
607  {
608  for ( const QString &candidate : sEndCandidates )
609  {
610  QString fldName = field.name();
611  if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
612  {
613  mEndFieldName = fldName;
614  foundEnd = true;
615  }
616  }
617  }
618 
619  if ( foundStart && foundEnd )
620  break;
621  }
622 
623  if ( !foundStart )
624  {
625  // loop again, looking for likely "single field" candidates
626  for ( const QgsField &field : fields )
627  {
628  if ( field.type() != QVariant::Date && field.type() != QVariant::DateTime )
629  continue;
630 
631  for ( const QString &candidate : sSingleFieldCandidates )
632  {
633  QString fldName = field.name();
634  if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
635  {
636  mStartFieldName = fldName;
637  foundStart = true;
638  }
639  }
640 
641  if ( foundStart )
642  break;
643  }
644  }
645 
646  if ( foundStart && foundEnd )
648  else if ( foundStart )
650 
651  // note -- NEVER auto enable temporal properties here! It's just a helper designed
652  // to shortcut the initial field selection
653 }
654 
656 {
657  return mLayer;
658 }
659 
661 {
662  mLayer = layer;
663 }
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...
Definition: qgsfeature.h:56
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:287
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QString name
Definition: qgsfield.h:60
QVariant::Type type
Definition: qgsfield.h:58
Container of fields for a vector layer.
Definition: qgsfields.h:45
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
A representation of the interval between two datetime values.
Definition: qgsinterval.h:42
Base class for storage of map layer temporal properties.
Base class for all map layer types.
Definition: qgsmaplayer.h:85
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.
Definition: qgsunittypes.h:150
@ TemporalMonths
Months.
Definition: qgsunittypes.h:157
@ TemporalUnknownUnit
Unknown time unit.
Definition: qgsunittypes.h:161
@ TemporalWeeks
Weeks.
Definition: qgsunittypes.h:156
@ TemporalMilliseconds
Milliseconds.
Definition: qgsunittypes.h:151
@ TemporalDays
Days.
Definition: qgsunittypes.h:155
@ TemporalDecades
Decades.
Definition: qgsunittypes.h:159
@ TemporalCenturies
Centuries.
Definition: qgsunittypes.h:160
@ TemporalSeconds
Seconds.
Definition: qgsunittypes.h:152
@ TemporalMinutes
Minutes.
Definition: qgsunittypes.h:153
@ TemporalYears
Years.
Definition: qgsunittypes.h:158
@ TemporalHours
Hours.
Definition: qgsunittypes.h:154
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.
Definition: qgis.h:276
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:316
QList< int > QgsAttributeList
Definition: qgsfield.h:26
const QgsField & field
Definition: qgsfield.h:472
QString dateTimeExpressionLiteral(const QDateTime &datetime)