39 mStartDateTime->setDateTimeRange( QDateTime( QDate( 1, 1, 1 ), QTime( 0, 0, 0 ) ), mStartDateTime->maximumDateTime() );
40 mEndDateTime->setDateTimeRange( QDateTime( QDate( 1, 1, 1 ), QTime( 0, 0, 0 ) ), mStartDateTime->maximumDateTime() );
41 mFixedRangeStartDateTime->setDateTimeRange( QDateTime( QDate( 1, 1, 1 ), QTime( 0, 0, 0 ) ), mStartDateTime->maximumDateTime() );
42 mFixedRangeEndDateTime->setDateTimeRange( QDateTime( QDate( 1, 1, 1 ), QTime( 0, 0, 0 ) ), mStartDateTime->maximumDateTime() );
44 connect( mForwardButton, &QPushButton::clicked,
this, &QgsTemporalControllerWidget::togglePlayForward );
45 connect( mBackButton, &QPushButton::clicked,
this, &QgsTemporalControllerWidget::togglePlayBackward );
46 connect( mStopButton, &QPushButton::clicked,
this, &QgsTemporalControllerWidget::togglePause );
51 connect( mLoopingCheckBox, &QCheckBox::toggled,
this, [ = ](
bool state ) { mNavigationObject->
setLooping( state ); } );
53 setWidgetStateFromNavigationMode( mNavigationObject->
navigationMode() );
58 if ( mBlockFrameDurationUpdates )
61 mBlockFrameDurationUpdates++;
62 updateTimeStepInputs( timeStep );
63 mBlockFrameDurationUpdates--;
65 connect( mNavigationOff, &QPushButton::clicked,
this, &QgsTemporalControllerWidget::mNavigationOff_clicked );
66 connect( mNavigationFixedRange, &QPushButton::clicked,
this, &QgsTemporalControllerWidget::mNavigationFixedRange_clicked );
67 connect( mNavigationAnimated, &QPushButton::clicked,
this, &QgsTemporalControllerWidget::mNavigationAnimated_clicked );
76 connect( mStartDateTime, &QDateTimeEdit::dateTimeChanged,
this, &QgsTemporalControllerWidget::startEndDateTime_changed );
77 connect( mEndDateTime, &QDateTimeEdit::dateTimeChanged,
this, &QgsTemporalControllerWidget::startEndDateTime_changed );
78 connect( mFixedRangeStartDateTime, &QDateTimeEdit::dateTimeChanged,
this, &QgsTemporalControllerWidget::fixedRangeStartEndDateTime_changed );
79 connect( mFixedRangeEndDateTime, &QDateTimeEdit::dateTimeChanged,
this, &QgsTemporalControllerWidget::fixedRangeStartEndDateTime_changed );
80 connect( mStepSpinBox, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ),
this, &QgsTemporalControllerWidget::updateFrameDuration );
81 connect( mTimeStepsComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ),
this, &QgsTemporalControllerWidget::updateFrameDuration );
82 connect( mSlider, &QSlider::valueChanged,
this, &QgsTemporalControllerWidget::timeSlider_valueChanged );
84 mStepSpinBox->setClearValue( 1 );
88 connect( mSettings, &QPushButton::clicked,
this, &QgsTemporalControllerWidget::settings_clicked );
92 mRangeMenu.reset(
new QMenu(
this ) );
94 mRangeSetToAllLayersAction =
new QAction( tr(
"Set to Full Range" ), mRangeMenu.get() );
96 connect( mRangeSetToAllLayersAction, &QAction::triggered,
this, &QgsTemporalControllerWidget::mRangeSetToAllLayersAction_triggered );
97 mRangeMenu->addAction( mRangeSetToAllLayersAction );
99 mRangeSetToProjectAction =
new QAction( tr(
"Set to Preset Project Range" ), mRangeMenu.get() );
100 connect( mRangeSetToProjectAction, &QAction::triggered,
this, &QgsTemporalControllerWidget::mRangeSetToProjectAction_triggered );
101 mRangeMenu->addAction( mRangeSetToProjectAction );
103 mRangeMenu->addSeparator();
105 mRangeLayersSubMenu.reset(
new QMenu( tr(
"Set to Single Layer's Range" ), mRangeMenu.get() ) );
106 mRangeLayersSubMenu->setEnabled(
false );
107 mRangeMenu->addMenu( mRangeLayersSubMenu.get() );
108 connect( mRangeMenu.get(), &QMenu::aboutToShow,
this, &QgsTemporalControllerWidget::aboutToShowRangeMenu );
110 mSetRangeButton->setPopupMode( QToolButton::MenuButtonPopup );
111 mSetRangeButton->setMenu( mRangeMenu.get() );
112 mSetRangeButton->setDefaultAction( mRangeSetToAllLayersAction );
113 mFixedRangeSetRangeButton->setPopupMode( QToolButton::MenuButtonPopup );
114 mFixedRangeSetRangeButton->setMenu( mRangeMenu.get() );
115 mFixedRangeSetRangeButton->setDefaultAction( mRangeSetToAllLayersAction );
119 QgsDateTimeRange range;
124 if ( range.begin().isValid() && range.end().isValid() )
126 whileBlocking( mStartDateTime )->setDateTime( range.begin() );
128 whileBlocking( mFixedRangeStartDateTime )->setDateTime( range.begin() );
129 whileBlocking( mFixedRangeEndDateTime )->setDateTime( range.end() );
153 mStepSpinBox->setDecimals( 3 );
155 mStepSpinBox->setMinimum( 0.001 );
156 mStepSpinBox->setMaximum( std::numeric_limits<int>::max() );
157 mStepSpinBox->setSingleStep( 1 );
158 mStepSpinBox->setValue( 1 );
160 mForwardButton->setToolTip( tr(
"Play" ) );
161 mBackButton->setToolTip( tr(
"Reverse" ) );
162 mNextButton->setToolTip( tr(
"Go to next frame" ) );
163 mPreviousButton->setToolTip( tr(
"Go to previous frame" ) );
164 mStopButton->setToolTip( tr(
"Pause" ) );
165 mRewindButton->setToolTip( tr(
"Rewind to start" ) );
166 mFastForwardButton->setToolTip( tr(
"Fast forward to end" ) );
168 updateFrameDuration();
177 if ( mSlider->hasFocus() && e->key() == Qt::Key_Space )
181 QWidget::keyPressEvent( e );
184 void QgsTemporalControllerWidget::aboutToShowRangeMenu()
186 QgsDateTimeRange projectRange;
189 mRangeSetToProjectAction->setEnabled( projectRange.begin().isValid() && projectRange.end().isValid() );
191 mRangeLayersSubMenu->clear();
192 for (
int i = 0; i < mMapLayerModel->
rowCount(); ++i )
194 QModelIndex index = mMapLayerModel->
index( i, 0 );
199 QIcon icon = qvariant_cast<QIcon>( mMapLayerModel->
data( index, Qt::DecorationRole ) );
200 QString text = mMapLayerModel->
data( index, Qt::DisplayRole ).toString();
202 if ( range.begin().isValid() && range.end().isValid() )
204 QAction *action =
new QAction( icon, text, mRangeLayersSubMenu.get() );
205 connect( action, &QAction::triggered,
this, [ = ]
208 saveRangeToProject();
210 mRangeLayersSubMenu->addAction( action );
213 mRangeLayersSubMenu->setEnabled( !mRangeLayersSubMenu->actions().isEmpty() );
216 void QgsTemporalControllerWidget::togglePlayForward()
218 mPlayingForward =
true;
222 mStopButton->setChecked(
false );
223 mBackButton->setChecked(
false );
224 mForwardButton->setChecked(
true );
229 mBackButton->setChecked(
true );
230 mForwardButton->setChecked(
false );
231 mNavigationObject->
pause();
235 void QgsTemporalControllerWidget::togglePlayBackward()
237 mPlayingForward =
false;
241 mStopButton->setChecked(
false );
242 mBackButton->setChecked(
true );
243 mForwardButton->setChecked(
false );
248 mBackButton->setChecked(
true );
249 mBackButton->setChecked(
false );
250 mNavigationObject->
pause();
254 void QgsTemporalControllerWidget::togglePause()
258 mStopButton->setChecked(
true );
259 mBackButton->setChecked(
false );
260 mForwardButton->setChecked(
false );
261 mNavigationObject->
pause();
265 mBackButton->setChecked( mPlayingForward ?
false :
true );
266 mForwardButton->setChecked( mPlayingForward ?
false :
true );
267 if ( mPlayingForward )
278 void QgsTemporalControllerWidget::updateTemporalExtent()
280 QgsDateTimeRange temporalExtent = QgsDateTimeRange( mStartDateTime->dateTime(),
281 mEndDateTime->dateTime() );
287 void QgsTemporalControllerWidget::updateFrameDuration()
289 if ( mBlockSettingUpdates )
296 if ( !mBlockFrameDurationUpdates )
307 void QgsTemporalControllerWidget::setWidgetStateFromProject()
309 mBlockSettingUpdates++;
312 mBlockSettingUpdates--;
316 QStringLiteral(
"/NavigationMode" ), 0, &ok ) );
320 setWidgetStateFromNavigationMode( mode );
328 const QString startString =
QgsProject::instance()->
readEntry( QStringLiteral(
"TemporalControllerWidget" ), QStringLiteral(
"/StartDateTime" ) );
329 const QString endString =
QgsProject::instance()->
readEntry( QStringLiteral(
"TemporalControllerWidget" ), QStringLiteral(
"/EndDateTime" ) );
330 if ( !startString.isEmpty() && !endString.isEmpty() )
332 whileBlocking( mStartDateTime )->setDateTime( QDateTime::fromString( startString, Qt::ISODateWithMs ) );
333 whileBlocking( mEndDateTime )->setDateTime( QDateTime::fromString( endString, Qt::ISODateWithMs ) );
334 whileBlocking( mFixedRangeStartDateTime )->setDateTime( QDateTime::fromString( startString, Qt::ISODateWithMs ) );
335 whileBlocking( mFixedRangeEndDateTime )->setDateTime( QDateTime::fromString( endString, Qt::ISODateWithMs ) );
339 setDatesToProjectTime();
341 updateTemporalExtent();
342 updateFrameDuration();
348 void QgsTemporalControllerWidget::mNavigationOff_clicked()
357 void QgsTemporalControllerWidget::mNavigationFixedRange_clicked()
366 void QgsTemporalControllerWidget::mNavigationAnimated_clicked()
384 mNavigationModeStackedWidget->setCurrentIndex( 0 );
387 mNavigationModeStackedWidget->setCurrentIndex( 1 );
390 mNavigationModeStackedWidget->setCurrentIndex( 2 );
395 void QgsTemporalControllerWidget::onLayersAdded(
const QList<QgsMapLayer *> &layers )
397 if ( !mHasTemporalLayersLoaded )
401 if ( layer->temporalProperties() )
403 mHasTemporalLayersLoaded |= layer->temporalProperties()->isActive();
405 if ( !mHasTemporalLayersLoaded )
409 if ( layer->isValid() && layer->temporalProperties()->isActive() && !mHasTemporalLayersLoaded )
411 mHasTemporalLayersLoaded = true;
412 firstTemporalLayerLoaded( layer );
417 firstTemporalLayerLoaded( layer );
423 void QgsTemporalControllerWidget::firstTemporalLayerLoaded(
QgsMapLayer *layer )
425 setDatesToProjectTime();
427 QgsMeshLayer *meshLayer = qobject_cast<QgsMeshLayer *>( layer );
430 mBlockFrameDurationUpdates++;
432 mBlockFrameDurationUpdates--;
433 updateFrameDuration();
437 void QgsTemporalControllerWidget::onProjectCleared()
439 mHasTemporalLayersLoaded =
false;
444 whileBlocking( mStartDateTime )->setDateTime( QDateTime( QDate::currentDate(), QTime( 0, 0, 0 ), Qt::UTC ) );
445 whileBlocking( mEndDateTime )->setDateTime( mStartDateTime->dateTime() );
446 whileBlocking( mFixedRangeStartDateTime )->setDateTime( QDateTime( QDate::currentDate(), QTime( 0, 0, 0 ), Qt::UTC ) );
447 whileBlocking( mFixedRangeEndDateTime )->setDateTime( mStartDateTime->dateTime() );
448 updateTemporalExtent();
450 mStepSpinBox->setValue( 1 );
453 void QgsTemporalControllerWidget::updateSlider(
const QgsDateTimeRange &range )
456 updateRangeLabel( range );
459 void QgsTemporalControllerWidget::updateRangeLabel(
const QgsDateTimeRange &range )
461 QString timeFrameFormat =
"yyyy-MM-dd HH:mm:ss";
464 timeFrameFormat =
"yyyy-MM-dd HH:mm:ss.zzz";
468 mCurrentRangeLabel->setText( tr(
"Frame: %1 to %2" ).arg(
469 range.begin().toString( timeFrameFormat ),
470 range.end().toString( timeFrameFormat ) ) );
473 mCurrentRangeLabel->setText( tr(
"Range: %1 to %2" ).arg(
474 range.begin().toString( timeFrameFormat ),
475 range.end().toString( timeFrameFormat ) ) );
478 mCurrentRangeLabel->setText( tr(
"Temporal navigation disabled" ) );
485 return mNavigationObject;
488 void QgsTemporalControllerWidget::settings_clicked()
490 QgsTemporalMapSettingsWidget *settingsWidget =
new QgsTemporalMapSettingsWidget(
this );
491 settingsWidget->setFrameRateValue( mNavigationObject->
framesPerSecond() );
494 connect( settingsWidget, &QgsTemporalMapSettingsWidget::frameRateChanged,
this, [ = ](
double rate )
501 connect( settingsWidget, &QgsTemporalMapSettingsWidget::temporalRangeCumulativeChanged,
this, [ = ](
bool state )
510 void QgsTemporalControllerWidget::timeSlider_valueChanged(
int value )
515 void QgsTemporalControllerWidget::startEndDateTime_changed()
517 whileBlocking( mFixedRangeStartDateTime )->setDateTime( mStartDateTime->dateTime() );
518 whileBlocking( mFixedRangeEndDateTime )->setDateTime( mEndDateTime->dateTime() );
520 updateTemporalExtent();
521 saveRangeToProject();
524 void QgsTemporalControllerWidget::fixedRangeStartEndDateTime_changed()
526 whileBlocking( mStartDateTime )->setDateTime( mFixedRangeStartDateTime->dateTime() );
527 whileBlocking( mEndDateTime )->setDateTime( mFixedRangeEndDateTime->dateTime() );
529 updateTemporalExtent();
530 saveRangeToProject();
533 void QgsTemporalControllerWidget::mRangeSetToAllLayersAction_triggered()
535 setDatesToAllLayers();
536 saveRangeToProject();
539 void QgsTemporalControllerWidget::setTimeStep(
const QgsInterval &timeStep )
547 int selectedUnit = -1;
548 int stringSize = std::numeric_limits<int>::max();
549 int precision = mStepSpinBox->decimals();
550 double selectedValue = std::numeric_limits<double>::max();
551 for (
int i = 0; i < mTimeStepsComboBox->count(); ++i )
555 QString
string = QString::number( value,
'f',
precision );
556 string.remove( QRegExp(
"0+$" ) );
557 string.remove( QRegExp(
"[.]+$" ) );
560 &&
string.size() <= stringSize
561 && value < selectedValue )
564 selectedValue = value;
565 stringSize =
string.size();
567 else if (
string !=
'0'
569 &&
string.size() < stringSize )
572 selectedValue = value ;
573 stringSize =
string.size();
577 if ( selectedUnit >= 0 )
579 mStepSpinBox->setValue( selectedValue );
580 mTimeStepsComboBox->setCurrentIndex( selectedUnit );
583 updateFrameDuration();
586 void QgsTemporalControllerWidget::updateTimeStepInputs(
const QgsInterval &timeStep )
591 QString timeDisplayFormat =
"yyyy-MM-dd HH:mm:ss";
594 timeDisplayFormat =
"yyyy-MM-dd HH:mm:ss.zzz";
596 updateTemporalExtent();
598 mStartDateTime->setDisplayFormat( timeDisplayFormat );
599 mEndDateTime->setDisplayFormat( timeDisplayFormat );
600 mFixedRangeStartDateTime->setDisplayFormat( timeDisplayFormat );
601 mFixedRangeEndDateTime->setDisplayFormat( timeDisplayFormat );
604 if ( timeStep ==
QgsInterval( mStepSpinBox->value(),
611 mTimeStepsComboBox->setCurrentIndex( timeStep.
originalUnit() );
614 updateFrameDuration();
617 void QgsTemporalControllerWidget::mRangeSetToProjectAction_triggered()
619 setDatesToProjectTime();
620 saveRangeToProject();
623 void QgsTemporalControllerWidget::setDates(
const QgsDateTimeRange &range )
625 if ( range.begin().isValid() && range.end().isValid() )
627 whileBlocking( mStartDateTime )->setDateTime( range.begin() );
629 whileBlocking( mFixedRangeStartDateTime )->setDateTime( range.begin() );
630 whileBlocking( mFixedRangeEndDateTime )->setDateTime( range.end() );
631 updateTemporalExtent();
635 void QgsTemporalControllerWidget::setDatesToAllLayers()
637 QgsDateTimeRange range;
642 void QgsTemporalControllerWidget::setDatesToProjectTime()
644 QgsDateTimeRange range;
651 if ( !range.begin().isValid() || !range.end().isValid() )
659 void QgsTemporalControllerWidget::saveRangeToProject()
662 QStringLiteral(
"/StartDateTime" ), mStartDateTime->dateTime().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODateWithMs ) );
664 QStringLiteral(
"/EndDateTime" ), mEndDateTime->dateTime().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODateWithMs ) );
static QIcon getThemeIcon(const QString &name)
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.
QgsUnitTypes::TemporalUnit originalUnit() const
Returns the original interval temporal unit.
The QgsMapLayerModel class is a model to display 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
@ LayerRole
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.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
QgsInterval firstValidTimeStep() const
Returns the first valid time step of the dataset groups, invalid QgInterval if no time step is presen...
QgsDateTimeRange temporalRange() const
Returns the project's temporal range, which indicates the earliest and latest datetime ranges associa...
void setTimeStepUnit(QgsUnitTypes::TemporalUnit unit)
Sets the project's time step (length of one animation frame) unit, which is used as the default value...
void setFramesPerSecond(double rate)
Sets the project's default animation frame rate, in frames per second.
QgsUnitTypes::TemporalUnit timeStepUnit() const
Returns the project's time step (length of one animation frame) unit, which is used as the default va...
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.
void readProject(const QDomDocument &)
Emitted when a project is being read.
bool writeEntry(const QString &scope, const QString &key, bool value)
Write a boolean value to the project file.
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...
A controller base class for temporal objects, contains a signal for notifying updates of the objects ...
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 previous()
Jumps back to the previous frame.
double framesPerSecond() const
Returns the animation frame rate, in frames per second.
void playForward()
Starts the animation playing in a forward direction up till the end of all frames.
NavigationMode
Represents the current temporal navigation mode.
@ NavigationOff
Temporal navigation is disabled.
@ FixedRange
Temporal navigation relies on a fixed datetime range.
@ Animated
Temporal navigation relies on frames within a datetime range.
long long currentFrameNumber() const
Returns the current frame number.
void setFrameDuration(QgsInterval duration)
Sets the frame duration, which dictates the temporal length of each frame in the animation.
void rewindToStart()
Rewinds the temporal navigation to start of the temporal extent.
void pause()
Pauses the temporal navigation.
void setCurrentFrameNumber(long long frame)
Sets the current animation frame number.
long long totalFrameCount() const
Returns the total number of frames for the navigation.
void skipToEnd()
Skips the temporal navigation to end of the temporal extent.
void temporalFrameDurationChanged(const QgsInterval &interval)
Emitted whenever the frameDuration interval of the controller changes.
void navigationModeChanged(NavigationMode mode)
Emitted whenever the navigation mode changes.
void setFramesPerSecond(double rate)
Sets the animation frame rate, in frames per second.
void stateChanged(AnimationState state)
Emitted whenever the animation state changes.
AnimationState
Represents the current animation state.
@ Forward
Animation is playing forward.
@ Reverse
Animation is playing in reverse.
@ Idle
Animation is paused.
bool temporalRangeCumulative() const
Returns the animation temporal range cumulative settings.
void next()
Advances to the next frame.
void setTemporalExtents(const QgsDateTimeRange &extents)
Sets the navigation temporal extents, which dictate the earliest and latest date time possible in the...
void setTemporalRangeCumulative(bool state)
Sets the animation temporal range as cumulative.
void setLooping(bool loop)
Sets whether the animation should loop after hitting the end or start frame.
void playBackward()
Starts the animation playing in a reverse direction until the beginning of the time range.
void temporalExtentsChanged(const QgsDateTimeRange &extent)
Emitted whenever the temporalExtent extent changes.
void setNavigationMode(const NavigationMode mode)
Sets the temporal navigation mode.
AnimationState animationState() const
Returns the current animation state.
NavigationMode navigationMode() const
Returns the currenttemporal navigation mode.
bool isActive() const
Returns true if the temporal property is active.
static QgsDateTimeRange calculateTemporalRangeForProject(QgsProject *project)
Calculates the temporal range for a project.
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
TemporalUnit
Temporal units.
@ TemporalUnknownUnit
Unknown time unit.
@ TemporalMilliseconds
Milliseconds.
@ TemporalDecades
Decades.
@ TemporalCenturies
Centuries.
@ TemporalSeconds
Seconds.
@ TemporalMinutes
Minutes.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.