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 setTimeStep( 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 mStartDateTime->setDisplayFormat(
"yyyy-MM-dd HH:mm:ss" );
125 mEndDateTime->setDisplayFormat(
"yyyy-MM-dd HH:mm:ss" );
126 mFixedRangeStartDateTime->setDisplayFormat(
"yyyy-MM-dd HH:mm:ss" );
127 mFixedRangeEndDateTime->setDisplayFormat(
"yyyy-MM-dd HH:mm:ss" );
129 if ( range.begin().isValid() && range.end().isValid() )
131 whileBlocking( mStartDateTime )->setDateTime( range.begin() );
133 whileBlocking( mFixedRangeStartDateTime )->setDateTime( range.begin() );
134 whileBlocking( mFixedRangeEndDateTime )->setDateTime( range.end() );
157 mStepSpinBox->setMinimum( 0.0000001 );
158 mStepSpinBox->setMaximum( std::numeric_limits<int>::max() );
159 mStepSpinBox->setSingleStep( 1 );
160 mStepSpinBox->setValue( 1 );
162 mForwardButton->setToolTip( tr(
"Play" ) );
163 mBackButton->setToolTip( tr(
"Reverse" ) );
164 mNextButton->setToolTip( tr(
"Go to next frame" ) );
165 mPreviousButton->setToolTip( tr(
"Go to previous frame" ) );
166 mStopButton->setToolTip( tr(
"Pause" ) );
167 mRewindButton->setToolTip( tr(
"Rewind to start" ) );
168 mFastForwardButton->setToolTip( tr(
"Fast forward to end" ) );
170 updateFrameDuration();
179 if ( mSlider->hasFocus() && e->key() == Qt::Key_Space )
183 QWidget::keyPressEvent( e );
186 void QgsTemporalControllerWidget::aboutToShowRangeMenu()
188 QgsDateTimeRange projectRange;
191 mRangeSetToProjectAction->setEnabled( projectRange.begin().isValid() && projectRange.end().isValid() );
193 mRangeLayersSubMenu->clear();
194 for (
int i = 0; i < mMapLayerModel->
rowCount(); ++i )
196 QModelIndex index = mMapLayerModel->
index( i, 0 );
201 QIcon icon = qvariant_cast<QIcon>( mMapLayerModel->
data( index, Qt::DecorationRole ) );
202 QString text = mMapLayerModel->
data( index, Qt::DisplayRole ).toString();
204 if ( range.begin().isValid() && range.end().isValid() )
206 QAction *action =
new QAction( icon, text, mRangeLayersSubMenu.get() );
207 connect( action, &QAction::triggered,
this, [ = ]
210 saveRangeToProject();
212 mRangeLayersSubMenu->addAction( action );
215 mRangeLayersSubMenu->setEnabled( !mRangeLayersSubMenu->actions().isEmpty() );
218 void QgsTemporalControllerWidget::togglePlayForward()
220 mPlayingForward =
true;
224 mStopButton->setChecked(
false );
225 mBackButton->setChecked(
false );
226 mForwardButton->setChecked(
true );
231 mBackButton->setChecked(
true );
232 mForwardButton->setChecked(
false );
233 mNavigationObject->
pause();
237 void QgsTemporalControllerWidget::togglePlayBackward()
239 mPlayingForward =
false;
243 mStopButton->setChecked(
false );
244 mBackButton->setChecked(
true );
245 mForwardButton->setChecked(
false );
250 mBackButton->setChecked(
true );
251 mBackButton->setChecked(
false );
252 mNavigationObject->
pause();
256 void QgsTemporalControllerWidget::togglePause()
260 mStopButton->setChecked(
true );
261 mBackButton->setChecked(
false );
262 mForwardButton->setChecked(
false );
263 mNavigationObject->
pause();
267 mBackButton->setChecked( mPlayingForward ?
false :
true );
268 mForwardButton->setChecked( mPlayingForward ?
false :
true );
269 if ( mPlayingForward )
280 void QgsTemporalControllerWidget::updateTemporalExtent()
282 QgsDateTimeRange temporalExtent = QgsDateTimeRange( mStartDateTime->dateTime(),
283 mEndDateTime->dateTime() );
286 mSlider->setValue( 0 );
289 void QgsTemporalControllerWidget::updateFrameDuration()
291 if ( mBlockSettingUpdates )
298 if ( !mBlockFrameDurationUpdates )
305 void QgsTemporalControllerWidget::setWidgetStateFromProject()
307 mBlockSettingUpdates++;
310 mBlockSettingUpdates--;
314 QStringLiteral(
"/NavigationMode" ), 0, &ok ) );
318 setWidgetStateFromNavigationMode( mode );
326 const QString startString =
QgsProject::instance()->
readEntry( QStringLiteral(
"TemporalControllerWidget" ), QStringLiteral(
"/StartDateTime" ) );
327 const QString endString =
QgsProject::instance()->
readEntry( QStringLiteral(
"TemporalControllerWidget" ), QStringLiteral(
"/EndDateTime" ) );
328 if ( !startString.isEmpty() && !endString.isEmpty() )
330 whileBlocking( mStartDateTime )->setDateTime( QDateTime::fromString( startString, Qt::ISODate ) );
331 whileBlocking( mEndDateTime )->setDateTime( QDateTime::fromString( endString, Qt::ISODate ) );
332 whileBlocking( mFixedRangeStartDateTime )->setDateTime( QDateTime::fromString( startString, Qt::ISODate ) );
333 whileBlocking( mFixedRangeEndDateTime )->setDateTime( QDateTime::fromString( endString, Qt::ISODate ) );
337 setDatesToProjectTime();
339 updateTemporalExtent();
340 updateFrameDuration();
346 void QgsTemporalControllerWidget::mNavigationOff_clicked()
355 void QgsTemporalControllerWidget::mNavigationFixedRange_clicked()
364 void QgsTemporalControllerWidget::mNavigationAnimated_clicked()
382 mNavigationModeStackedWidget->setCurrentIndex( 0 );
385 mNavigationModeStackedWidget->setCurrentIndex( 1 );
388 mNavigationModeStackedWidget->setCurrentIndex( 2 );
393 void QgsTemporalControllerWidget::onLayersAdded(
const QList<QgsMapLayer *> &layers )
395 if ( !mHasTemporalLayersLoaded )
399 if ( layer->temporalProperties() )
401 mHasTemporalLayersLoaded |= layer->temporalProperties()->isActive();
403 if ( !mHasTemporalLayersLoaded )
407 if ( layer->isValid() && layer->temporalProperties()->isActive() && !mHasTemporalLayersLoaded )
409 mHasTemporalLayersLoaded = true;
410 firstTemporalLayerLoaded( layer );
415 firstTemporalLayerLoaded( layer );
421 void QgsTemporalControllerWidget::firstTemporalLayerLoaded(
QgsMapLayer *layer )
423 setDatesToProjectTime();
425 QgsMeshLayer *meshLayer = qobject_cast<QgsMeshLayer *>( layer );
430 void QgsTemporalControllerWidget::onProjectCleared()
432 mHasTemporalLayersLoaded =
false;
437 whileBlocking( mStartDateTime )->setDateTime( QDateTime( QDate::currentDate(), QTime( 0, 0, 0, Qt::UTC ) ) );
438 whileBlocking( mEndDateTime )->setDateTime( mStartDateTime->dateTime() );
439 whileBlocking( mFixedRangeStartDateTime )->setDateTime( QDateTime( QDate::currentDate(), QTime( 0, 0, 0, Qt::UTC ) ) );
440 whileBlocking( mFixedRangeEndDateTime )->setDateTime( mStartDateTime->dateTime() );
441 updateTemporalExtent();
443 mStepSpinBox->setValue( 1 );
446 void QgsTemporalControllerWidget::updateSlider(
const QgsDateTimeRange &range )
449 updateRangeLabel( range );
452 void QgsTemporalControllerWidget::updateRangeLabel(
const QgsDateTimeRange &range )
457 mCurrentRangeLabel->setText( tr(
"Frame: %1 to %2" ).arg(
458 range.begin().toString(
"yyyy-MM-dd HH:mm:ss" ),
459 range.end().toString(
"yyyy-MM-dd HH:mm:ss" ) ) );
462 mCurrentRangeLabel->setText( tr(
"Range: %1 to %2" ).arg(
463 range.begin().toString(
"yyyy-MM-dd HH:mm:ss" ),
464 range.end().toString(
"yyyy-MM-dd HH:mm:ss" ) ) );
467 mCurrentRangeLabel->setText( tr(
"Temporal navigation disabled" ) );
474 return mNavigationObject;
477 void QgsTemporalControllerWidget::settings_clicked()
479 QgsTemporalMapSettingsWidget *settingsWidget =
new QgsTemporalMapSettingsWidget(
this );
480 settingsWidget->setFrameRateValue( mNavigationObject->
framesPerSecond() );
483 connect( settingsWidget, &QgsTemporalMapSettingsWidget::frameRateChanged,
this, [ = ](
double rate )
490 connect( settingsWidget, &QgsTemporalMapSettingsWidget::temporalRangeCumulativeChanged,
this, [ = ](
bool state )
499 void QgsTemporalControllerWidget::timeSlider_valueChanged(
int value )
504 void QgsTemporalControllerWidget::startEndDateTime_changed()
506 whileBlocking( mFixedRangeStartDateTime )->setDateTime( mStartDateTime->dateTime() );
507 whileBlocking( mFixedRangeEndDateTime )->setDateTime( mEndDateTime->dateTime() );
509 updateTemporalExtent();
510 saveRangeToProject();
513 void QgsTemporalControllerWidget::fixedRangeStartEndDateTime_changed()
515 whileBlocking( mStartDateTime )->setDateTime( mFixedRangeStartDateTime->dateTime() );
516 whileBlocking( mEndDateTime )->setDateTime( mFixedRangeEndDateTime->dateTime() );
518 updateTemporalExtent();
519 saveRangeToProject();
522 void QgsTemporalControllerWidget::mRangeSetToAllLayersAction_triggered()
524 setDatesToAllLayers();
525 saveRangeToProject();
528 void QgsTemporalControllerWidget::setTimeStep(
const QgsInterval &timeStep )
536 int selectedUnit = -1;
537 int stringSize = std::numeric_limits<int>::max();
538 int precision = mStepSpinBox->decimals();
539 double selectedValue = std::numeric_limits<double>::max();
540 for (
int i = 0; i < mTimeStepsComboBox->count(); ++i )
544 QString
string = QString::number( value,
'f',
precision );
545 string.remove( QRegExp(
"0+$" ) );
546 string.remove( QRegExp(
"[.]+$" ) );
549 &&
string.size() <= stringSize
550 && value < selectedValue )
553 selectedValue = value;
554 stringSize =
string.size();
556 else if (
string !=
'0'
558 &&
string.size() < stringSize )
561 selectedValue = value ;
562 stringSize =
string.size();
566 if ( selectedUnit >= 0 )
568 mStepSpinBox->setValue( selectedValue );
569 mTimeStepsComboBox->setCurrentIndex( selectedUnit );
572 updateFrameDuration();
575 void QgsTemporalControllerWidget::mRangeSetToProjectAction_triggered()
577 setDatesToProjectTime();
578 saveRangeToProject();
581 void QgsTemporalControllerWidget::setDates(
const QgsDateTimeRange &range )
583 if ( range.begin().isValid() && range.end().isValid() )
585 whileBlocking( mStartDateTime )->setDateTime( range.begin() );
587 whileBlocking( mFixedRangeStartDateTime )->setDateTime( range.begin() );
588 whileBlocking( mFixedRangeEndDateTime )->setDateTime( range.end() );
589 updateTemporalExtent();
593 void QgsTemporalControllerWidget::setDatesToAllLayers()
595 QgsDateTimeRange range;
600 void QgsTemporalControllerWidget::setDatesToProjectTime()
602 QgsDateTimeRange range;
609 if ( !range.begin().isValid() || !range.end().isValid() )
617 void QgsTemporalControllerWidget::saveRangeToProject()
620 QStringLiteral(
"/StartDateTime" ), mStartDateTime->dateTime().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
622 QStringLiteral(
"/EndDateTime" ), mEndDateTime->dateTime().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );