35#include <QRegularExpression>
38#include "moc_qgstemporalcontrollerwidget.cpp"
40using namespace Qt::StringLiterals;
49 mStartDateTime->setDateTimeRange( QDateTime( QDate( 1, 1, 1 ), QTime( 0, 0, 0 ) ), mStartDateTime->maximumDateTime() );
50 mEndDateTime->setDateTimeRange( QDateTime( QDate( 1, 1, 1 ), QTime( 0, 0, 0 ) ), mStartDateTime->maximumDateTime() );
51 mFixedRangeStartDateTime->setDateTimeRange( QDateTime( QDate( 1, 1, 1 ), QTime( 0, 0, 0 ) ), mStartDateTime->maximumDateTime() );
52 mFixedRangeEndDateTime->setDateTimeRange( QDateTime( QDate( 1, 1, 1 ), QTime( 0, 0, 0 ) ), mStartDateTime->maximumDateTime() );
58 mNavigationObject->rewindToStart();
62 mNavigationObject->previous();
66 mNavigationObject->playBackward();
70 mNavigationObject->pause();
74 mNavigationObject->playForward();
78 mNavigationObject->next();
82 mNavigationObject->skipToEnd();
89 connect( mAnimationLoopingCheckBox, &QCheckBox::toggled,
this, [
this](
bool state ) { mNavigationObject->setLooping( state ); mMovieLoopingCheckBox->setChecked( state ); } );
90 connect( mMovieLoopingCheckBox, &QCheckBox::toggled,
this, [
this](
bool state ) { mNavigationObject->setLooping( state ); mAnimationLoopingCheckBox->setChecked( state ); } );
92 setWidgetStateFromNavigationMode( mNavigationObject->navigationMode() );
96 if ( mBlockFrameDurationUpdates )
99 mBlockFrameDurationUpdates++;
100 updateTimeStepInputs( timeStep );
101 mBlockFrameDurationUpdates--;
103 connect( mNavigationOff, &QPushButton::clicked,
this, &QgsTemporalControllerWidget::mNavigationOff_clicked );
104 connect( mNavigationFixedRange, &QPushButton::clicked,
this, &QgsTemporalControllerWidget::mNavigationFixedRange_clicked );
105 connect( mNavigationAnimated, &QPushButton::clicked,
this, &QgsTemporalControllerWidget::mNavigationAnimated_clicked );
106 connect( mNavigationMovie, &QPushButton::clicked,
this, &QgsTemporalControllerWidget::mNavigationMovie_clicked );
109 mAnimationController->setState( state );
110 mMovieController->setState( state );
113 connect( mStartDateTime, &QDateTimeEdit::dateTimeChanged,
this, &QgsTemporalControllerWidget::startEndDateTime_changed );
114 connect( mEndDateTime, &QDateTimeEdit::dateTimeChanged,
this, &QgsTemporalControllerWidget::startEndDateTime_changed );
115 connect( mFixedRangeStartDateTime, &QDateTimeEdit::dateTimeChanged,
this, &QgsTemporalControllerWidget::fixedRangeStartEndDateTime_changed );
116 connect( mFixedRangeEndDateTime, &QDateTimeEdit::dateTimeChanged,
this, &QgsTemporalControllerWidget::fixedRangeStartEndDateTime_changed );
117 connect( mStepSpinBox, qOverload<double>( &QDoubleSpinBox::valueChanged ),
this, &QgsTemporalControllerWidget::updateFrameDuration );
118 connect( mTimeStepsComboBox, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &QgsTemporalControllerWidget::updateFrameDuration );
119 connect( mAnimationSlider, &QSlider::valueChanged,
this, &QgsTemporalControllerWidget::timeSlider_valueChanged );
120 connect( mMovieSlider, &QSlider::valueChanged,
this, &QgsTemporalControllerWidget::timeSlider_valueChanged );
122 connect( mTotalFramesSpinBox, qOverload<int>( &QSpinBox::valueChanged ),
this, [
this](
int frames ) {
123 mNavigationObject->setTotalMovieFrames( frames );
126 mStepSpinBox->setClearValue( 1 );
131 connect( mSettings, &QPushButton::clicked,
this, &QgsTemporalControllerWidget::settings_clicked );
135 mRangeMenu = std::make_unique<QMenu>(
this );
137 mRangeSetToAllLayersAction =
new QAction( tr(
"Set to Full Range" ), mRangeMenu.get() );
139 connect( mRangeSetToAllLayersAction, &QAction::triggered,
this, &QgsTemporalControllerWidget::mRangeSetToAllLayersAction_triggered );
140 mRangeMenu->addAction( mRangeSetToAllLayersAction );
142 mRangeSetToProjectAction =
new QAction( tr(
"Set to Preset Project Range" ), mRangeMenu.get() );
143 connect( mRangeSetToProjectAction, &QAction::triggered,
this, &QgsTemporalControllerWidget::mRangeSetToProjectAction_triggered );
144 mRangeMenu->addAction( mRangeSetToProjectAction );
146 mRangeMenu->addSeparator();
148 mRangeLayersSubMenu = std::make_unique<QMenu>( tr(
"Set to Single Layer's Range" ), mRangeMenu.get() );
149 mRangeLayersSubMenu->setEnabled(
false );
150 mRangeMenu->addMenu( mRangeLayersSubMenu.get() );
151 connect( mRangeMenu.get(), &QMenu::aboutToShow,
this, &QgsTemporalControllerWidget::aboutToShowRangeMenu );
153 mSetRangeButton->setPopupMode( QToolButton::MenuButtonPopup );
154 mSetRangeButton->setMenu( mRangeMenu.get() );
155 mSetRangeButton->setDefaultAction( mRangeSetToAllLayersAction );
156 mFixedRangeSetRangeButton->setPopupMode( QToolButton::MenuButtonPopup );
157 mFixedRangeSetRangeButton->setMenu( mRangeMenu.get() );
158 mFixedRangeSetRangeButton->setDefaultAction( mRangeSetToAllLayersAction );
168 if ( range.
begin().isValid() && range.
end().isValid() )
198 mStepSpinBox->setDecimals( 3 );
200 mStepSpinBox->setMinimum( 0.001 );
201 mStepSpinBox->setMaximum( std::numeric_limits<int>::max() );
202 mStepSpinBox->setSingleStep( 1 );
203 mStepSpinBox->setValue( 1 );
205 updateFrameDuration();
219 if ( ( mAnimationSlider->hasFocus() || mMovieSlider->hasFocus() ) && e->key() == Qt::Key_Space )
221 mAnimationController->togglePause();
227void QgsTemporalControllerWidget::aboutToShowRangeMenu()
232 mRangeSetToProjectAction->setEnabled( projectRange.
begin().isValid() && projectRange.
end().isValid() );
234 mRangeLayersSubMenu->clear();
235 for (
int i = 0; i < mMapLayerModel->
rowCount(); ++i )
237 const QModelIndex index = mMapLayerModel->
index( i, 0 );
242 const QIcon icon = qvariant_cast<QIcon>( mMapLayerModel->
data( index, Qt::DecorationRole ) );
243 const QString text = mMapLayerModel->
data( index, Qt::DisplayRole ).toString();
245 if ( range.
begin().isValid() && range.
end().isValid() )
247 QAction *action =
new QAction( icon, text, mRangeLayersSubMenu.get() );
248 connect( action, &QAction::triggered,
this, [
this, range] {
250 saveRangeToProject();
252 mRangeLayersSubMenu->addAction( action );
255 mRangeLayersSubMenu->setEnabled( !mRangeLayersSubMenu->actions().isEmpty() );
258void QgsTemporalControllerWidget::updateTemporalExtent()
262 const QDateTime start = mStartDateTime->dateTime();
263 const QDateTime end = mEndDateTime->dateTime();
264 const bool isTimeInstant = start == end;
266 mNavigationObject->setTemporalExtents( temporalExtent );
267 mAnimationSlider->setRange( 0, mNavigationObject->totalFrameCount() - 1 );
268 mAnimationSlider->setValue( mNavigationObject->currentFrameNumber() );
269 mMovieSlider->setRange( 0, mNavigationObject->totalFrameCount() - 1 );
270 mMovieSlider->setValue( mNavigationObject->currentFrameNumber() );
273void QgsTemporalControllerWidget::updateFrameDuration()
275 if ( mBlockSettingUpdates )
283 if ( !mBlockFrameDurationUpdates )
285 mNavigationObject->setFrameDuration(
288 mAnimationSlider->setValue( mNavigationObject->currentFrameNumber() );
290 mAnimationSlider->setRange( 0, mNavigationObject->totalFrameCount() - 1 );
291 mAnimationSlider->setValue( mNavigationObject->currentFrameNumber() );
292 mMovieSlider->setRange( 0, mNavigationObject->totalFrameCount() - 1 );
293 mMovieSlider->setValue( mNavigationObject->currentFrameNumber() );
297 mStepSpinBox->setEnabled(
false );
298 mStepSpinBox->setValue( 1 );
299 mAnimationSlider->setTickInterval( 1 );
300 mAnimationSlider->setTickPosition( QSlider::TicksBothSides );
304 mStepSpinBox->setEnabled(
true );
305 mAnimationSlider->setTickInterval( 0 );
306 mAnimationSlider->setTickPosition( QSlider::NoTicks );
310void QgsTemporalControllerWidget::setWidgetStateFromProject()
312 mBlockSettingUpdates++;
315 mBlockSettingUpdates--;
321 mNavigationObject->setNavigationMode( mode );
322 setWidgetStateFromNavigationMode( mode );
330 mNavigationObject->setTotalMovieFrames(
QgsProject::instance()->timeSettings()->totalMovieFrames() );
335 if ( !startString.isEmpty() && !endString.isEmpty() )
337 whileBlocking( mStartDateTime )->setDateTime( QDateTime::fromString( startString, Qt::ISODateWithMs ) );
338 whileBlocking( mEndDateTime )->setDateTime( QDateTime::fromString( endString, Qt::ISODateWithMs ) );
339 whileBlocking( mFixedRangeStartDateTime )->setDateTime( QDateTime::fromString( startString, Qt::ISODateWithMs ) );
340 whileBlocking( mFixedRangeEndDateTime )->setDateTime( QDateTime::fromString( endString, Qt::ISODateWithMs ) );
344 setDatesToProjectTime(
false );
346 updateTemporalExtent();
347 updateFrameDuration();
349 mNavigationObject->setFramesPerSecond(
QgsProject::instance()->timeSettings()->framesPerSecond() );
350 mNavigationObject->setTemporalRangeCumulative(
QgsProject::instance()->timeSettings()->isTemporalRangeCumulative() );
353void QgsTemporalControllerWidget::mNavigationOff_clicked()
361void QgsTemporalControllerWidget::mNavigationFixedRange_clicked()
369void QgsTemporalControllerWidget::mNavigationAnimated_clicked()
377void QgsTemporalControllerWidget::mNavigationMovie_clicked()
395 mNavigationModeStackedWidget->setCurrentIndex( 0 );
398 mNavigationModeStackedWidget->setCurrentIndex( 1 );
401 mNavigationModeStackedWidget->setCurrentIndex( 2 );
404 mNavigationModeStackedWidget->setCurrentIndex( 3 );
409void QgsTemporalControllerWidget::onLayersAdded(
const QList<QgsMapLayer *> &layers )
411 if ( !mHasTemporalLayersLoaded )
413 for ( QgsMapLayer *layer : layers )
415 if ( layer->temporalProperties() )
417 mHasTemporalLayersLoaded |= layer->temporalProperties()->isActive();
419 if ( !mHasTemporalLayersLoaded )
422 if ( layer->isValid() && layer->temporalProperties()->isActive() && !mHasTemporalLayersLoaded )
424 mHasTemporalLayersLoaded =
true;
425 firstTemporalLayerLoaded( layer );
431 firstTemporalLayerLoaded( layer );
439void QgsTemporalControllerWidget::firstTemporalLayerLoaded(
QgsMapLayer *layer )
441 setDatesToProjectTime(
true );
443 if ( QgsMeshLayer *meshLayer = qobject_cast<QgsMeshLayer *>( layer ) )
445 mBlockFrameDurationUpdates++;
446 setTimeStep( meshLayer->firstValidTimeStep() );
447 mBlockFrameDurationUpdates--;
448 updateFrameDuration();
450 else if ( QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layer ) )
452 if ( rasterLayer->dataProvider() && rasterLayer->dataProvider()->temporalCapabilities() )
454 mBlockFrameDurationUpdates++;
455 setTimeStep( rasterLayer->dataProvider()->temporalCapabilities()->defaultInterval() );
456 mBlockFrameDurationUpdates--;
457 updateFrameDuration();
462void QgsTemporalControllerWidget::onProjectCleared()
464 mHasTemporalLayersLoaded =
false;
471 const QTime startOfCurrentHour = QTime( QTime::currentTime().hour(), 0, 0 );
472 const QDateTime end = QDateTime( QDate::currentDate(), startOfCurrentHour, Qt::UTC );
473 const QDateTime start = end.addSecs( -24 * 60 * 60 );
477 whileBlocking( mFixedRangeStartDateTime )->setDateTime( start );
480 updateTemporalExtent();
482 mStepSpinBox->setValue( 1 );
485void QgsTemporalControllerWidget::updateSlider(
const QgsDateTimeRange &range )
487 whileBlocking( mAnimationSlider )->setValue( mNavigationObject->currentFrameNumber() );
488 whileBlocking( mMovieSlider )->setValue( mNavigationObject->currentFrameNumber() );
489 updateRangeLabel( range );
492void QgsTemporalControllerWidget::totalMovieFramesChanged(
long long frames )
495 mTotalFramesSpinBox->setValue( frames );
496 mCurrentRangeLabel->setText( tr(
"Current frame: %1/%2" ).arg( mNavigationObject->currentFrameNumber() ).arg( frames ) );
499void QgsTemporalControllerWidget::updateRangeLabel(
const QgsDateTimeRange &range )
501 QString timeFrameFormat = u
"yyyy-MM-dd HH:mm:ss"_s;
504 timeFrameFormat = u
"yyyy-MM-dd HH:mm:ss.zzz"_s;
505 switch ( mNavigationObject->navigationMode() )
508 mCurrentRangeLabel->setText( tr(
"Current frame: %1 ≤ <i>t</i> < %2" ).arg( range.
begin().toString( timeFrameFormat ), range.
end().toString( timeFrameFormat ) ) );
511 mCurrentRangeLabel->setText( tr(
"Range: %1 ≤ <i>t</i> < %2" ).arg( range.
begin().toString( timeFrameFormat ), range.
end().toString( timeFrameFormat ) ) );
514 mCurrentRangeLabel->setText( tr(
"Temporal navigation disabled" ) );
517 mCurrentRangeLabel->setText( tr(
"Current frame: %1/%2" ).arg( mNavigationObject->currentFrameNumber() ).arg( mNavigationObject->totalMovieFrames() ) );
524 return mNavigationObject;
527void QgsTemporalControllerWidget::settings_clicked()
529 QgsTemporalMapSettingsWidget *settingsWidget =
new QgsTemporalMapSettingsWidget(
this );
530 settingsWidget->setFrameRateValue( mNavigationObject->
framesPerSecond() );
533 connect( settingsWidget, &QgsTemporalMapSettingsWidget::frameRateChanged,
this, [
this](
double rate ) {
539 connect( settingsWidget, &QgsTemporalMapSettingsWidget::temporalRangeCumulativeChanged,
this, [
this](
bool state ) {
542 mNavigationObject->setTemporalRangeCumulative( state );
547void QgsTemporalControllerWidget::timeSlider_valueChanged(
int value )
549 mNavigationObject->setCurrentFrameNumber( value );
552void QgsTemporalControllerWidget::startEndDateTime_changed()
554 whileBlocking( mFixedRangeStartDateTime )->setDateTime( mStartDateTime->dateTime() );
555 whileBlocking( mFixedRangeEndDateTime )->setDateTime( mEndDateTime->dateTime() );
557 updateTemporalExtent();
558 saveRangeToProject();
561void QgsTemporalControllerWidget::fixedRangeStartEndDateTime_changed()
563 whileBlocking( mStartDateTime )->setDateTime( mFixedRangeStartDateTime->dateTime() );
564 whileBlocking( mEndDateTime )->setDateTime( mFixedRangeEndDateTime->dateTime() );
566 updateTemporalExtent();
567 saveRangeToProject();
570void QgsTemporalControllerWidget::mRangeSetToAllLayersAction_triggered()
572 setDatesToAllLayers();
573 saveRangeToProject();
576void QgsTemporalControllerWidget::setTimeStep(
const QgsInterval &timeStep )
581 int selectedUnit = -1;
582 double selectedValue = std::numeric_limits<double>::max();
588 int stringSize = std::numeric_limits<int>::max();
589 const int precision = mStepSpinBox->decimals();
590 for (
int i = 0; i < mTimeStepsComboBox->count(); ++i )
594 QString
string = QString::number( value,
'f', precision );
596 const thread_local QRegularExpression trailingZeroRegEx = QRegularExpression( u
"0+$"_s );
598 string.remove( trailingZeroRegEx );
600 const thread_local QRegularExpression trailingPointRegEx = QRegularExpression( u
"[.]+$"_s );
602 string.remove( trailingPointRegEx );
605 &&
string.size() <= stringSize
606 && value < selectedValue )
609 selectedValue = value;
610 stringSize =
string.size();
612 else if (
string !=
'0'
613 &&
string.size() < precision + 2
614 &&
string.size() < stringSize )
617 selectedValue = value;
618 stringSize =
string.size();
624 selectedUnit = mTimeStepsComboBox->findData(
static_cast<int>( timeStep.
originalUnit() ) );
628 if ( selectedUnit >= 0 )
630 mStepSpinBox->setValue( selectedValue );
631 mTimeStepsComboBox->setCurrentIndex( selectedUnit );
634 updateFrameDuration();
637void QgsTemporalControllerWidget::updateTimeStepInputs(
const QgsInterval &timeStep )
642 QString timeDisplayFormat = u
"yyyy-MM-dd HH:mm:ss"_s;
645 timeDisplayFormat = u
"yyyy-MM-dd HH:mm:ss.zzz"_s;
647 updateTemporalExtent();
649 mStartDateTime->setDisplayFormat( timeDisplayFormat );
650 mEndDateTime->setDisplayFormat( timeDisplayFormat );
651 mFixedRangeStartDateTime->setDisplayFormat( timeDisplayFormat );
652 mFixedRangeEndDateTime->setDisplayFormat( timeDisplayFormat );
655 if ( timeStep == QgsInterval( mStepSpinBox->value(),
static_cast<Qgis::TemporalUnit>( mTimeStepsComboBox->currentData().toInt() ) ) )
661 mTimeStepsComboBox->setCurrentIndex( mTimeStepsComboBox->findData(
static_cast<int>( timeStep.
originalUnit() ) ) );
664 updateFrameDuration();
667void QgsTemporalControllerWidget::mRangeSetToProjectAction_triggered()
669 setDatesToProjectTime(
false );
670 saveRangeToProject();
675 if ( range.
begin().isValid() && range.
end().isValid() )
681 updateTemporalExtent();
685void QgsTemporalControllerWidget::setDatesToAllLayers()
694void QgsTemporalControllerWidget::setDatesToProjectTime(
bool tryLastStoredRange )
698 if ( tryLastStoredRange )
702 if ( !startString.isEmpty() && !endString.isEmpty() )
704 range =
QgsDateTimeRange( QDateTime::fromString( startString, Qt::ISODateWithMs ), QDateTime::fromString( endString, Qt::ISODateWithMs ) );
713 if ( !range.
begin().isValid() || !range.
end().isValid() )
723void QgsTemporalControllerWidget::saveRangeToProject()
725 QgsProject::instance()->
writeEntry( u
"TemporalControllerWidget"_s, u
"/StartDateTime"_s, mStartDateTime->dateTime().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODateWithMs ) );
726 QgsProject::instance()->
writeEntry( u
"TemporalControllerWidget"_s, u
"/EndDateTime"_s, mEndDateTime->dateTime().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODateWithMs ) );
TemporalNavigationMode
Temporal navigation modes.
@ Animated
Temporal navigation relies on frames within a datetime range.
@ Movie
Movie mode – behaves like a video player, with a fixed frame duration and no temporal range.
@ FixedRange
Temporal navigation relies on a fixed datetime range.
@ Disabled
Temporal navigation is disabled.
PlaybackOperation
Media playback operations.
@ PlayReverse
Play in reverse.
@ PlayForward
Play forward.
@ SkipToStart
Jump to start of playback.
@ PreviousFrame
Step to previous frame.
@ SkipToEnd
Jump to end of playback.
@ NextFrame
Step to next frame.
TemporalUnit
Temporal units.
@ IrregularStep
Special 'irregular step' time unit, used for temporal data which uses irregular, non-real-world unit ...
@ Milliseconds
Milliseconds.
@ Unknown
Unknown time unit.
AnimationState
Animation states.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
A representation of the interval between two datetime values.
double originalDuration() const
Returns the original interval duration.
bool isValid() const
Returns true if the interval is valid.
double seconds() const
Returns the interval duration in seconds.
Qgis::TemporalUnit originalUnit() const
Returns the original interval temporal unit.
A model for display of map layers in widgets.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
@ Layer
Stores pointer to the map layer itself.
virtual QgsDateTimeRange calculateTemporalExtent(QgsMapLayer *layer) const
Attempts to calculate the overall temporal extent for the specified layer, using the settings defined...
Base class for all map layer types.
void dataSourceChanged()
Emitted whenever the layer's data source has been changed.
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal properties.
QgsDateTimeRange temporalRange() const
Returns the project's temporal range, which indicates the earliest and latest datetime ranges associa...
void setTotalMovieFrames(long long frames)
Sets the total number of frames for the movie.
void setFramesPerSecond(double rate)
Sets the project's default animation frame rate, in frames per second.
Qgis::TemporalUnit timeStepUnit() const
Returns the project's time step (length of one animation frame) unit, which is used as the default va...
void setTimeStepUnit(Qgis::TemporalUnit unit)
Sets the project's time step (length of one animation frame) unit, which is used as the default value...
void setIsTemporalRangeCumulative(bool state)
Sets the project's temporal range as cumulative in animation settings.
void setTimeStep(double step)
Sets the project's time step (length of one animation frame), which is used as the default value when...
int readNumEntry(const QString &scope, const QString &key, int def=0, bool *ok=nullptr) const
Reads an integer from the specified scope and key.
static QgsProject * instance()
Returns the QgsProject singleton instance.
void cleared()
Emitted when the project is cleared (and additionally when an open project is cleared just before a n...
QString readEntry(const QString &scope, const QString &key, const QString &def=QString(), bool *ok=nullptr) const
Reads a string from the specified scope and key.
bool writeEntry(const QString &scope, const QString &key, bool value)
Write a boolean value to the project file.
void readProject(const QDomDocument &document)
Emitted when a project is being read.
void layersAdded(const QList< QgsMapLayer * > &layers)
Emitted when one or more layers were added to the registry.
const QgsProjectTimeSettings * timeSettings() const
Returns the project's time settings, which contains the project's temporal range and other time based...
void updateTemporalRange(const QgsDateTimeRange &range)
Signals that a temporal range has changed and needs to be updated in all connected objects.
Implements a temporal controller based on a frame by frame navigation and animation.
void stateChanged(Qgis::AnimationState state)
Emitted whenever the animation state changes.
double framesPerSecond() const
Returns the animation frame rate, in frames per second.
void navigationModeChanged(Qgis::TemporalNavigationMode mode)
Emitted whenever the navigation mode changes.
void temporalFrameDurationChanged(const QgsInterval &interval)
Emitted whenever the frameDuration interval of the controller changes.
void setFramesPerSecond(double rate)
Sets the animation frame rate, in frames per second.
bool temporalRangeCumulative() const
Returns the animation temporal range cumulative settings.
void totalMovieFramesChanged(long long frames)
Emitted whenever the total number of frames in the movie is changed.
void temporalExtentsChanged(const QgsDateTimeRange &extent)
Emitted whenever the temporalExtent extent changes.
bool isActive() const
Returns true if the temporal property is active.
T begin() const
Returns the beginning of the range.
T end() const
Returns the upper bound of the range.
static QgsDateTimeRange calculateTemporalRangeForProject(QgsProject *project)
Calculates the temporal range for a project.
static QList< QgsDateTimeRange > usedTemporalRangesForProject(QgsProject *project)
Calculates all temporal ranges which are in use for a project.
static Q_INVOKABLE QString toString(Qgis::DistanceUnit unit)
Returns a translated string representing a distance unit.
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
QgsTemporalRange< QDateTime > QgsDateTimeRange
QgsRange which stores a range of date times.