QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgstemporalcontrollerwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstemporalcontrollerwidget.cpp
3  ------------------------------
4  begin : February 2020
5  copyright : (C) 2020 by Samweli Mwakisambwe
6  email : samweli at kartoza 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 
18 #include "qgsapplication.h"
20 #include "qgsgui.h"
21 #include "qgsmaplayermodel.h"
22 #include "qgsproject.h"
23 #include "qgsprojecttimesettings.h"
25 #include "qgstemporalutils.h"
27 #include "qgsmeshlayer.h"
28 
29 #include <QAction>
30 #include <QMenu>
31 
33  : QgsPanelWidget( parent )
34 {
35  setupUi( this );
36 
37  mNavigationObject = new QgsTemporalNavigationObject( this );
38 
39  connect( mForwardButton, &QPushButton::clicked, this, &QgsTemporalControllerWidget::togglePlayForward );
40  connect( mBackButton, &QPushButton::clicked, this, &QgsTemporalControllerWidget::togglePlayBackward );
41  connect( mStopButton, &QPushButton::clicked, this, &QgsTemporalControllerWidget::togglePause );
42  connect( mNextButton, &QPushButton::clicked, mNavigationObject, &QgsTemporalNavigationObject::next );
43  connect( mPreviousButton, &QPushButton::clicked, mNavigationObject, &QgsTemporalNavigationObject::previous );
44  connect( mFastForwardButton, &QPushButton::clicked, mNavigationObject, &QgsTemporalNavigationObject::skipToEnd );
45  connect( mRewindButton, &QPushButton::clicked, mNavigationObject, &QgsTemporalNavigationObject::rewindToStart );
46  connect( mLoopingCheckBox, &QCheckBox::toggled, this, [ = ]( bool state ) { mNavigationObject->setLooping( state ); } );
47 
48  setWidgetStateFromNavigationMode( mNavigationObject->navigationMode() );
49  connect( mNavigationObject, &QgsTemporalNavigationObject::navigationModeChanged, this, &QgsTemporalControllerWidget::setWidgetStateFromNavigationMode );
50  connect( mNavigationOff, &QPushButton::clicked, this, &QgsTemporalControllerWidget::mNavigationOff_clicked );
51  connect( mNavigationFixedRange, &QPushButton::clicked, this, &QgsTemporalControllerWidget::mNavigationFixedRange_clicked );
52  connect( mNavigationAnimated, &QPushButton::clicked, this, &QgsTemporalControllerWidget::mNavigationAnimated_clicked );
53 
54  connect( mNavigationObject, &QgsTemporalNavigationObject::stateChanged, this, [ = ]( QgsTemporalNavigationObject::AnimationState state )
55  {
56  mForwardButton->setChecked( state == QgsTemporalNavigationObject::Forward );
57  mBackButton->setChecked( state == QgsTemporalNavigationObject::Reverse );
58  mStopButton->setChecked( state == QgsTemporalNavigationObject::Idle );
59  } );
60 
61  connect( mStartDateTime, &QDateTimeEdit::dateTimeChanged, this, &QgsTemporalControllerWidget::startEndDateTime_changed );
62  connect( mEndDateTime, &QDateTimeEdit::dateTimeChanged, this, &QgsTemporalControllerWidget::startEndDateTime_changed );
63  connect( mFixedRangeStartDateTime, &QDateTimeEdit::dateTimeChanged, this, &QgsTemporalControllerWidget::fixedRangeStartEndDateTime_changed );
64  connect( mFixedRangeEndDateTime, &QDateTimeEdit::dateTimeChanged, this, &QgsTemporalControllerWidget::fixedRangeStartEndDateTime_changed );
65  connect( mStepSpinBox, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsTemporalControllerWidget::updateFrameDuration );
66  connect( mTimeStepsComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsTemporalControllerWidget::updateFrameDuration );
67  connect( mSlider, &QSlider::valueChanged, this, &QgsTemporalControllerWidget::timeSlider_valueChanged );
68 
69  mStepSpinBox->setClearValue( 1 );
70 
71  connect( mNavigationObject, &QgsTemporalNavigationObject::updateTemporalRange, this, &QgsTemporalControllerWidget::updateSlider );
72 
73  connect( mSettings, &QPushButton::clicked, this, &QgsTemporalControllerWidget::settings_clicked );
74 
75  mMapLayerModel = new QgsMapLayerModel( this );
76 
77  mRangeMenu.reset( new QMenu( this ) );
78 
79  mRangeSetToAllLayersAction = new QAction( tr( "Set to Full Range" ), mRangeMenu.get() );
80  mRangeSetToAllLayersAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionRefresh.svg" ) ) );
81  connect( mRangeSetToAllLayersAction, &QAction::triggered, this, &QgsTemporalControllerWidget::mRangeSetToAllLayersAction_triggered );
82  mRangeMenu->addAction( mRangeSetToAllLayersAction );
83 
84  mRangeSetToProjectAction = new QAction( tr( "Set to Preset Project Range" ), mRangeMenu.get() );
85  connect( mRangeSetToProjectAction, &QAction::triggered, this, &QgsTemporalControllerWidget::mRangeSetToProjectAction_triggered );
86  mRangeMenu->addAction( mRangeSetToProjectAction );
87 
88  mRangeMenu->addSeparator();
89 
90  mRangeLayersSubMenu.reset( new QMenu( tr( "Set to Single Layer's Range" ), mRangeMenu.get() ) );
91  mRangeLayersSubMenu->setEnabled( false );
92  mRangeMenu->addMenu( mRangeLayersSubMenu.get() );
93  connect( mRangeMenu.get(), &QMenu::aboutToShow, this, &QgsTemporalControllerWidget::aboutToShowRangeMenu );
94 
95  mSetRangeButton->setPopupMode( QToolButton::MenuButtonPopup );
96  mSetRangeButton->setMenu( mRangeMenu.get() );
97  mSetRangeButton->setDefaultAction( mRangeSetToAllLayersAction );
98  mFixedRangeSetRangeButton->setPopupMode( QToolButton::MenuButtonPopup );
99  mFixedRangeSetRangeButton->setMenu( mRangeMenu.get() );
100  mFixedRangeSetRangeButton->setDefaultAction( mRangeSetToAllLayersAction );
101 
102  connect( mExportAnimationButton, &QPushButton::clicked, this, &QgsTemporalControllerWidget::exportAnimation );
103 
104  QgsDateTimeRange range;
105 
106  if ( QgsProject::instance()->timeSettings() )
108 
109  mStartDateTime->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
110  mEndDateTime->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
111  mFixedRangeStartDateTime->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
112  mFixedRangeEndDateTime->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
113 
114  if ( range.begin().isValid() && range.end().isValid() )
115  {
116  whileBlocking( mStartDateTime )->setDateTime( range.begin() );
117  whileBlocking( mEndDateTime )->setDateTime( range.end() );
118  whileBlocking( mFixedRangeStartDateTime )->setDateTime( range.begin() );
119  whileBlocking( mFixedRangeEndDateTime )->setDateTime( range.end() );
120  }
121 
123  {
134  } )
135  {
136  mTimeStepsComboBox->addItem( QgsUnitTypes::toString( u ), u );
137  }
138 
139  // TODO: might want to choose an appropriate default unit based on the range
140  mTimeStepsComboBox->setCurrentIndex( mTimeStepsComboBox->findData( QgsUnitTypes::TemporalHours ) );
141 
142  mStepSpinBox->setMinimum( 0.0000001 );
143  mStepSpinBox->setMaximum( std::numeric_limits<int>::max() );
144  mStepSpinBox->setSingleStep( 1 );
145  mStepSpinBox->setValue( 1 );
146 
147  mForwardButton->setToolTip( tr( "Play" ) );
148  mBackButton->setToolTip( tr( "Reverse" ) );
149  mNextButton->setToolTip( tr( "Go to next frame" ) );
150  mPreviousButton->setToolTip( tr( "Go to previous frame" ) );
151  mStopButton->setToolTip( tr( "Pause" ) );
152  mRewindButton->setToolTip( tr( "Rewind to start" ) );
153  mFastForwardButton->setToolTip( tr( "Fast forward to end" ) );
154 
155  updateFrameDuration();
156 
157  connect( QgsProject::instance(), &QgsProject::readProject, this, &QgsTemporalControllerWidget::setWidgetStateFromProject );
158  connect( QgsProject::instance(), &QgsProject::layersAdded, this, &QgsTemporalControllerWidget::onLayersAdded );
159  connect( QgsProject::instance(), &QgsProject::cleared, this, &QgsTemporalControllerWidget::onProjectCleared );
160 }
161 
163 {
164  if ( mSlider->hasFocus() && e->key() == Qt::Key_Space )
165  {
166  togglePause();
167  }
168  QWidget::keyPressEvent( e );
169 }
170 
171 void QgsTemporalControllerWidget::aboutToShowRangeMenu()
172 {
173  QgsDateTimeRange projectRange;
174  if ( QgsProject::instance()->timeSettings() )
175  projectRange = QgsProject::instance()->timeSettings()->temporalRange();
176  mRangeSetToProjectAction->setEnabled( projectRange.begin().isValid() && projectRange.end().isValid() );
177 
178  mRangeLayersSubMenu->clear();
179  for ( int i = 0; i < mMapLayerModel->rowCount(); ++i )
180  {
181  QModelIndex index = mMapLayerModel->index( i, 0 );
182  QgsMapLayer *currentLayer = mMapLayerModel->data( index, QgsMapLayerModel::LayerRole ).value<QgsMapLayer *>();
183  if ( !currentLayer->temporalProperties() || !currentLayer->temporalProperties()->isActive() )
184  continue;
185 
186  QIcon icon = qvariant_cast<QIcon>( mMapLayerModel->data( index, Qt::DecorationRole ) );
187  QString text = mMapLayerModel->data( index, Qt::DisplayRole ).toString();
188  QgsDateTimeRange range = currentLayer->temporalProperties()->calculateTemporalExtent( currentLayer );
189  if ( range.begin().isValid() && range.end().isValid() )
190  {
191  QAction *action = new QAction( icon, text, mRangeLayersSubMenu.get() );
192  connect( action, &QAction::triggered, this, [ = ]
193  {
194  setDates( range );
195  saveRangeToProject();
196  } );
197  mRangeLayersSubMenu->addAction( action );
198  }
199  }
200  mRangeLayersSubMenu->setEnabled( !mRangeLayersSubMenu->actions().isEmpty() );
201 }
202 
203 void QgsTemporalControllerWidget::togglePlayForward()
204 {
205  mPlayingForward = true;
206 
207  if ( mNavigationObject->animationState() != QgsTemporalNavigationObject::Forward )
208  {
209  mStopButton->setChecked( false );
210  mBackButton->setChecked( false );
211  mForwardButton->setChecked( true );
212  mNavigationObject->playForward();
213  }
214  else
215  {
216  mBackButton->setChecked( true );
217  mForwardButton->setChecked( false );
218  mNavigationObject->pause();
219  }
220 }
221 
222 void QgsTemporalControllerWidget::togglePlayBackward()
223 {
224  mPlayingForward = false;
225 
226  if ( mNavigationObject->animationState() != QgsTemporalNavigationObject::Reverse )
227  {
228  mStopButton->setChecked( false );
229  mBackButton->setChecked( true );
230  mForwardButton->setChecked( false );
231  mNavigationObject->playBackward();
232  }
233  else
234  {
235  mBackButton->setChecked( true );
236  mBackButton->setChecked( false );
237  mNavigationObject->pause();
238  }
239 }
240 
241 void QgsTemporalControllerWidget::togglePause()
242 {
243  if ( mNavigationObject->animationState() != QgsTemporalNavigationObject::Idle )
244  {
245  mStopButton->setChecked( true );
246  mBackButton->setChecked( false );
247  mForwardButton->setChecked( false );
248  mNavigationObject->pause();
249  }
250  else
251  {
252  mBackButton->setChecked( mPlayingForward ? false : true );
253  mForwardButton->setChecked( mPlayingForward ? false : true );
254  if ( mPlayingForward )
255  {
256  mNavigationObject->playForward();
257  }
258  else
259  {
260  mNavigationObject->playBackward();
261  }
262  }
263 }
264 
265 void QgsTemporalControllerWidget::updateTemporalExtent()
266 {
267  QgsDateTimeRange temporalExtent = QgsDateTimeRange( mStartDateTime->dateTime(),
268  mEndDateTime->dateTime() );
269  mNavigationObject->setTemporalExtents( temporalExtent );
270  mSlider->setRange( 0, mNavigationObject->totalFrameCount() - 1 );
271  mSlider->setValue( 0 );
272 }
273 
274 void QgsTemporalControllerWidget::updateFrameDuration()
275 {
276  if ( mBlockSettingUpdates )
277  return;
278 
279  // save new settings into project
280  QgsProject::instance()->timeSettings()->setTimeStepUnit( static_cast< QgsUnitTypes::TemporalUnit>( mTimeStepsComboBox->currentData().toInt() ) );
281  QgsProject::instance()->timeSettings()->setTimeStep( mStepSpinBox->value() );
282 
283  mNavigationObject->setFrameDuration( QgsInterval( QgsProject::instance()->timeSettings()->timeStep(),
284  QgsProject::instance()->timeSettings()->timeStepUnit() ) );
285  mSlider->setRange( 0, mNavigationObject->totalFrameCount() - 1 );
286 }
287 
288 void QgsTemporalControllerWidget::setWidgetStateFromProject()
289 {
290  mBlockSettingUpdates++;
291  mTimeStepsComboBox->setCurrentIndex( mTimeStepsComboBox->findData( QgsProject::instance()->timeSettings()->timeStepUnit() ) );
292  mStepSpinBox->setValue( QgsProject::instance()->timeSettings()->timeStep() );
293  mBlockSettingUpdates--;
294 
295  bool ok = false;
296  QgsTemporalNavigationObject::NavigationMode mode = static_cast< QgsTemporalNavigationObject::NavigationMode>( QgsProject::instance()->readNumEntry( QStringLiteral( "TemporalControllerWidget" ),
297  QStringLiteral( "/NavigationMode" ), 0, &ok ) );
298  if ( ok )
299  {
300  mNavigationObject->setNavigationMode( mode );
301  setWidgetStateFromNavigationMode( mode );
302  }
303  else
304  {
306  setWidgetStateFromNavigationMode( QgsTemporalNavigationObject::NavigationOff );
307  }
308 
309  const QString startString = QgsProject::instance()->readEntry( QStringLiteral( "TemporalControllerWidget" ), QStringLiteral( "/StartDateTime" ) );
310  const QString endString = QgsProject::instance()->readEntry( QStringLiteral( "TemporalControllerWidget" ), QStringLiteral( "/EndDateTime" ) );
311  if ( !startString.isEmpty() && !endString.isEmpty() )
312  {
313  whileBlocking( mStartDateTime )->setDateTime( QDateTime::fromString( startString, Qt::ISODate ) );
314  whileBlocking( mEndDateTime )->setDateTime( QDateTime::fromString( endString, Qt::ISODate ) );
315  whileBlocking( mFixedRangeStartDateTime )->setDateTime( QDateTime::fromString( startString, Qt::ISODate ) );
316  whileBlocking( mFixedRangeEndDateTime )->setDateTime( QDateTime::fromString( endString, Qt::ISODate ) );
317  }
318  else
319  {
320  setDatesToProjectTime();
321  }
322  updateTemporalExtent();
323  updateFrameDuration();
324 
325  mNavigationObject->setFramesPerSecond( QgsProject::instance()->timeSettings()->framesPerSecond() );
326  mNavigationObject->setTemporalRangeCumulative( QgsProject::instance()->timeSettings()->isTemporalRangeCumulative() );
327 }
328 
329 void QgsTemporalControllerWidget::mNavigationOff_clicked()
330 {
331  QgsProject::instance()->writeEntry( QStringLiteral( "TemporalControllerWidget" ), QStringLiteral( "/NavigationMode" ),
332  static_cast<int>( QgsTemporalNavigationObject::NavigationOff ) );
333 
335  setWidgetStateFromNavigationMode( QgsTemporalNavigationObject::NavigationOff );
336 }
337 
338 void QgsTemporalControllerWidget::mNavigationFixedRange_clicked()
339 {
340  QgsProject::instance()->writeEntry( QStringLiteral( "TemporalControllerWidget" ), QStringLiteral( "/NavigationMode" ),
341  static_cast<int>( QgsTemporalNavigationObject::FixedRange ) );
342 
344  setWidgetStateFromNavigationMode( QgsTemporalNavigationObject::FixedRange );
345 }
346 
347 void QgsTemporalControllerWidget::mNavigationAnimated_clicked()
348 {
349  QgsProject::instance()->writeEntry( QStringLiteral( "TemporalControllerWidget" ), QStringLiteral( "/NavigationMode" ),
350  static_cast<int>( QgsTemporalNavigationObject::Animated ) );
351 
353  setWidgetStateFromNavigationMode( QgsTemporalNavigationObject::Animated );
354 }
355 
356 void QgsTemporalControllerWidget::setWidgetStateFromNavigationMode( const QgsTemporalNavigationObject::NavigationMode mode )
357 {
358  mNavigationOff->setChecked( mode == QgsTemporalNavigationObject::NavigationOff );
359  mNavigationFixedRange->setChecked( mode == QgsTemporalNavigationObject::FixedRange );
360  mNavigationAnimated->setChecked( mode == QgsTemporalNavigationObject::Animated );
361 
362  switch ( mode )
363  {
365  mNavigationModeStackedWidget->setCurrentIndex( 0 );
366  break;
368  mNavigationModeStackedWidget->setCurrentIndex( 1 );
369  break;
371  mNavigationModeStackedWidget->setCurrentIndex( 2 );
372  break;
373  }
374 }
375 
376 void QgsTemporalControllerWidget::onLayersAdded( const QList<QgsMapLayer *> &layers )
377 {
378  if ( !mHasTemporalLayersLoaded )
379  {
380  for ( QgsMapLayer *layer : layers )
381  {
382  if ( layer->temporalProperties() )
383  {
384  mHasTemporalLayersLoaded |= layer->temporalProperties()->isActive();
385 
386  if ( !mHasTemporalLayersLoaded )
387  {
388  connect( layer, &QgsMapLayer::dataSourceChanged, this, [ this, layer ]
389  {
390  if ( layer->isValid() && layer->temporalProperties()->isActive() && !mHasTemporalLayersLoaded )
391  {
392  mHasTemporalLayersLoaded = true;
393  firstTemporalLayerLoaded( layer );
394  }
395  } );
396  }
397 
398  firstTemporalLayerLoaded( layer );
399  }
400  }
401  }
402 }
403 
404 void QgsTemporalControllerWidget::firstTemporalLayerLoaded( QgsMapLayer *layer )
405 {
406  setDatesToProjectTime();
407 
408  QgsMeshLayer *meshLayer = qobject_cast<QgsMeshLayer *>( layer );
409  if ( meshLayer )
410  setTimeStep( meshLayer->firstValidTimeStep() );
411 }
412 
413 void QgsTemporalControllerWidget::onProjectCleared()
414 {
415  mHasTemporalLayersLoaded = false;
416 
418  setWidgetStateFromNavigationMode( QgsTemporalNavigationObject::NavigationOff );
419 
420  whileBlocking( mStartDateTime )->setDateTime( QDateTime( QDate::currentDate(), QTime( 0, 0, 0, Qt::UTC ) ) );
421  whileBlocking( mEndDateTime )->setDateTime( mStartDateTime->dateTime() );
422  whileBlocking( mFixedRangeStartDateTime )->setDateTime( QDateTime( QDate::currentDate(), QTime( 0, 0, 0, Qt::UTC ) ) );
423  whileBlocking( mFixedRangeEndDateTime )->setDateTime( mStartDateTime->dateTime() );
424  updateTemporalExtent();
425  mTimeStepsComboBox->setCurrentIndex( mTimeStepsComboBox->findData( QgsUnitTypes::TemporalHours ) );
426  mStepSpinBox->setValue( 1 );
427 }
428 
429 void QgsTemporalControllerWidget::updateSlider( const QgsDateTimeRange &range )
430 {
431  whileBlocking( mSlider )->setValue( mNavigationObject->currentFrameNumber() );
432  updateRangeLabel( range );
433 }
434 
435 void QgsTemporalControllerWidget::updateRangeLabel( const QgsDateTimeRange &range )
436 {
437  switch ( mNavigationObject->navigationMode() )
438  {
440  mCurrentRangeLabel->setText( tr( "Frame: %1 to %2" ).arg(
441  range.begin().toString( "yyyy-MM-dd HH:mm:ss" ),
442  range.end().toString( "yyyy-MM-dd HH:mm:ss" ) ) );
443  break;
445  mCurrentRangeLabel->setText( tr( "Range: %1 to %2" ).arg(
446  range.begin().toString( "yyyy-MM-dd HH:mm:ss" ),
447  range.end().toString( "yyyy-MM-dd HH:mm:ss" ) ) );
448  break;
450  mCurrentRangeLabel->setText( tr( "Temporal navigation disabled" ) );
451  break;
452  }
453 }
454 
456 {
457  return mNavigationObject;
458 }
459 
460 void QgsTemporalControllerWidget::settings_clicked()
461 {
462  QgsTemporalMapSettingsWidget *settingsWidget = new QgsTemporalMapSettingsWidget( this );
463  settingsWidget->setFrameRateValue( mNavigationObject->framesPerSecond() );
464  settingsWidget->setIsTemporalRangeCumulative( mNavigationObject->temporalRangeCumulative() );
465 
466  connect( settingsWidget, &QgsTemporalMapSettingsWidget::frameRateChanged, this, [ = ]( double rate )
467  {
468  // save new settings into project
470  mNavigationObject->setFramesPerSecond( rate );
471  } );
472 
473  connect( settingsWidget, &QgsTemporalMapSettingsWidget::temporalRangeCumulativeChanged, this, [ = ]( bool state )
474  {
475  // save new settings into project
477  mNavigationObject->setTemporalRangeCumulative( state );
478  } );
479  openPanel( settingsWidget );
480 }
481 
482 void QgsTemporalControllerWidget::timeSlider_valueChanged( int value )
483 {
484  mNavigationObject->setCurrentFrameNumber( value );
485 }
486 
487 void QgsTemporalControllerWidget::startEndDateTime_changed()
488 {
489  whileBlocking( mFixedRangeStartDateTime )->setDateTime( mStartDateTime->dateTime() );
490  whileBlocking( mFixedRangeEndDateTime )->setDateTime( mEndDateTime->dateTime() );
491 
492  updateTemporalExtent();
493  saveRangeToProject();
494 }
495 
496 void QgsTemporalControllerWidget::fixedRangeStartEndDateTime_changed()
497 {
498  whileBlocking( mStartDateTime )->setDateTime( mFixedRangeStartDateTime->dateTime() );
499  whileBlocking( mEndDateTime )->setDateTime( mFixedRangeEndDateTime->dateTime() );
500 
501  updateTemporalExtent();
502  saveRangeToProject();
503 }
504 
505 void QgsTemporalControllerWidget::mRangeSetToAllLayersAction_triggered()
506 {
507  setDatesToAllLayers();
508  saveRangeToProject();
509 }
510 
511 void QgsTemporalControllerWidget::setTimeStep( const QgsInterval &timeStep )
512 {
513  if ( ! timeStep.isValid() || timeStep.seconds() <= 0 )
514  return;
515 
516  // Search the time unit the most appropriate :
517  // the one that gives the smallest time step value for double spin box with round value (if possible) and/or the less signifiant digits
518 
519  int selectedUnit = -1;
520  int stringSize = std::numeric_limits<int>::max();
521  int precision = mStepSpinBox->decimals();
522  double selectedValue = std::numeric_limits<double>::max();
523  for ( int i = 0; i < mTimeStepsComboBox->count(); ++i )
524  {
525  QgsUnitTypes::TemporalUnit unit = static_cast<QgsUnitTypes::TemporalUnit>( mTimeStepsComboBox->itemData( i ).toInt() );
526  double value = timeStep.seconds() * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalSeconds, unit );
527  QString string = QString::number( value, 'f', precision );
528  string.remove( QRegExp( "0+$" ) ); //remove trailing zero
529  string.remove( QRegExp( "[.]+$" ) ); //remove last point if present
530 
531  if ( value >= 1
532  && string.size() <= stringSize // less significant digit than currently selected
533  && value < selectedValue ) // less than currently selected
534  {
535  selectedUnit = i;
536  selectedValue = value;
537  stringSize = string.size();
538  }
539  else if ( string != '0'
540  && string.size() < precision + 2 //round value (ex: 0.xx with precision=3)
541  && string.size() < stringSize ) //less significant digit than currently selected
542  {
543  selectedUnit = i ;
544  selectedValue = value ;
545  stringSize = string.size();
546  }
547  }
548 
549  if ( selectedUnit >= 0 )
550  {
551  mStepSpinBox->setValue( selectedValue );
552  mTimeStepsComboBox->setCurrentIndex( selectedUnit );
553  }
554 
555  updateFrameDuration();
556 }
557 
558 void QgsTemporalControllerWidget::mRangeSetToProjectAction_triggered()
559 {
560  setDatesToProjectTime();
561  saveRangeToProject();
562 }
563 
564 void QgsTemporalControllerWidget::setDates( const QgsDateTimeRange &range )
565 {
566  if ( range.begin().isValid() && range.end().isValid() )
567  {
568  whileBlocking( mStartDateTime )->setDateTime( range.begin() );
569  whileBlocking( mEndDateTime )->setDateTime( range.end() );
570  whileBlocking( mFixedRangeStartDateTime )->setDateTime( range.begin() );
571  whileBlocking( mFixedRangeEndDateTime )->setDateTime( range.end() );
572  updateTemporalExtent();
573  }
574 }
575 
576 void QgsTemporalControllerWidget::setDatesToAllLayers()
577 {
578  QgsDateTimeRange range;
580  setDates( range );
581 }
582 
583 void QgsTemporalControllerWidget::setDatesToProjectTime()
584 {
585  QgsDateTimeRange range;
586 
587  // by default try taking the project's fixed temporal extent
588  if ( QgsProject::instance()->timeSettings() )
590 
591  // if that's not set, calculate the extent from the project's layers
592  if ( !range.begin().isValid() || !range.end().isValid() )
593  {
595  }
596 
597  setDates( range );
598 }
599 
600 void QgsTemporalControllerWidget::saveRangeToProject()
601 {
602  QgsProject::instance()->writeEntry( QStringLiteral( "TemporalControllerWidget" ),
603  QStringLiteral( "/StartDateTime" ), mStartDateTime->dateTime().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
604  QgsProject::instance()->writeEntry( QStringLiteral( "TemporalControllerWidget" ),
605  QStringLiteral( "/EndDateTime" ), mEndDateTime->dateTime().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
606 }
QgsUnitTypes::TemporalDecades
@ TemporalDecades
Decades.
Definition: qgsunittypes.h:159
QgsTemporalNavigationObject::rewindToStart
void rewindToStart()
Rewinds the temporal navigation to start of the temporal extent.
Definition: qgstemporalnavigationobject.cpp:253
QgsProject::writeEntry
bool writeEntry(const QString &scope, const QString &key, bool value)
Write a boolean entry to the project file.
Definition: qgsproject.cpp:2366
QgsTemporalControllerWidget::exportAnimation
void exportAnimation()
Triggered when an animation should be exported.
QgsTemporalNavigationObject::Animated
@ Animated
Temporal navigation relies on frames within a datetime range.
Definition: qgstemporalnavigationobject.h:54
QgsTemporalControllerWidget::temporalController
QgsTemporalController * temporalController()
Returns the temporal controller object used by this object in navigation.
Definition: qgstemporalcontrollerwidget.cpp:455
QgsProjectTimeSettings::setIsTemporalRangeCumulative
void setIsTemporalRangeCumulative(bool state)
Sets the project's temporal range as cumulative in animation settings.
Definition: qgsprojecttimesettings.cpp:131
QgsInterval::seconds
double seconds() const
Returns the interval duration in seconds.
Definition: qgsinterval.h:168
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:605
QgsProjectTimeSettings::setFramesPerSecond
void setFramesPerSecond(double rate)
Sets the project's default animation frame rate, in frames per second.
Definition: qgsprojecttimesettings.cpp:121
QgsProject::layersAdded
void layersAdded(const QList< QgsMapLayer * > &layers)
Emitted when one or more layers were added to the registry.
QgsMeshLayer::firstValidTimeStep
QgsInterval firstValidTimeStep() const
Returns the first valid time step of the dataset groups, invalid QgInterval if no time step is presen...
Definition: qgsmeshlayer.cpp:750
qgstemporalmapsettingswidget.h
QgsTemporalNavigationObject::setTemporalRangeCumulative
void setTemporalRangeCumulative(bool state)
Sets the animation temporal range as cumulative.
Definition: qgstemporalnavigationobject.cpp:198
QgsTemporalNavigationObject::Reverse
@ Reverse
Animation is playing in reverse.
Definition: qgstemporalnavigationobject.h:62
qgsgui.h
QgsUnitTypes::TemporalYears
@ TemporalYears
Years.
Definition: qgsunittypes.h:158
QgsProject::cleared
void cleared()
Emitted when the project is cleared (and additionally when an open project is cleared just before a n...
QgsUnitTypes::TemporalDays
@ TemporalDays
Days.
Definition: qgsunittypes.h:155
QgsPanelWidget::openPanel
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
Definition: qgspanelwidget.cpp:79
QgsTemporalNavigationObject::navigationMode
NavigationMode navigationMode() const
Returns the currenttemporal navigation mode.
Definition: qgstemporalnavigationobject.h:92
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:458
QgsProject::readProject
void readProject(const QDomDocument &)
Emitted when a project is being read.
QgsMapLayerTemporalProperties::calculateTemporalExtent
virtual QgsDateTimeRange calculateTemporalExtent(QgsMapLayer *layer) const
Attempts to calculate the overall temporal extent for the specified layer, using the settings defined...
Definition: qgsmaplayertemporalproperties.cpp:30
QgsMapLayerModel::data
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Definition: qgsmaplayermodel.cpp:227
QgsProject::readEntry
QString readEntry(const QString &scope, const QString &key, const QString &def=QString(), bool *ok=nullptr) const
Definition: qgsproject.cpp:2448
QgsTemporalNavigationObject::playForward
void playForward()
Starts the animation playing in a forward direction up till the end of all frames.
Definition: qgstemporalnavigationobject.cpp:219
QgsTemporalNavigationObject::navigationModeChanged
void navigationModeChanged(NavigationMode mode)
Emitted whenever the navigation mode changes.
QgsTemporalNavigationObject::setFrameDuration
void setFrameDuration(QgsInterval duration)
Sets the frame duration, which dictates the temporal length of each frame in the animation.
Definition: qgstemporalnavigationobject.cpp:173
QgsUnitTypes::TemporalUnit
TemporalUnit
Temporal units.
Definition: qgsunittypes.h:149
QgsTemporalNavigationObject::NavigationMode
NavigationMode
Represents the current temporal navigation mode.
Definition: qgstemporalnavigationobject.h:51
QgsTemporalNavigationObject::Forward
@ Forward
Animation is playing forward.
Definition: qgstemporalnavigationobject.h:61
QgsProjectTimeSettings::temporalRange
QgsDateTimeRange temporalRange() const
Returns the project's temporal range, which indicates the earliest and latest datetime ranges associa...
Definition: qgsprojecttimesettings.cpp:34
QgsUnitTypes::TemporalSeconds
@ TemporalSeconds
Seconds.
Definition: qgsunittypes.h:152
qgstemporalcontrollerwidget.h
qgsapplication.h
QgsTemporalNavigationObject::setLooping
void setLooping(bool loop)
Sets whether the animation should loop after hitting the end or start frame.
Definition: qgstemporalnavigationobject.cpp:67
QgsUnitTypes::TemporalMonths
@ TemporalMonths
Months.
Definition: qgsunittypes.h:157
QgsProjectTimeSettings::timeStepUnit
QgsUnitTypes::TemporalUnit timeStepUnit() const
Returns the project's time step (length of one animation frame) unit, which is used as the default va...
Definition: qgsprojecttimesettings.cpp:101
QgsMapLayer::dataSourceChanged
void dataSourceChanged()
Emitted whenever the layer's data source has been changed.
QgsUnitTypes::fromUnitToUnitFactor
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
Definition: qgsunittypes.cpp:352
QgsTemporalControllerWidget::QgsTemporalControllerWidget
QgsTemporalControllerWidget(QWidget *parent=nullptr)
Constructor for QgsTemporalControllerWidget, with the specified parent widget.
Definition: qgstemporalcontrollerwidget.cpp:32
QgsMapLayerModel::rowCount
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Definition: qgsmaplayermodel.cpp:212
precision
int precision
Definition: qgswfsgetfeature.cpp:103
qgsmaplayertemporalproperties.h
QgsTemporalNavigationObject::playBackward
void playBackward()
Starts the animation playing in a reverse direction until the beginning of the time range.
Definition: qgstemporalnavigationobject.cpp:231
QgsPanelWidget
Base class for any widget that can be shown as a inline panel.
Definition: qgspanelwidget.h:29
QgsProject::timeSettings
const QgsProjectTimeSettings * timeSettings() const
Returns the project's time settings, which contains the project's temporal range and other time based...
Definition: qgsproject.cpp:2996
QgsTemporalProperty::isActive
bool isActive() const
Returns true if the temporal property is active.
Definition: qgstemporalproperty.cpp:36
QgsTemporalNavigationObject::skipToEnd
void skipToEnd()
Skips the temporal navigation to end of the temporal extent.
Definition: qgstemporalnavigationobject.cpp:258
QgsTemporalNavigationObject::stateChanged
void stateChanged(AnimationState state)
Emitted whenever the animation state changes.
whileBlocking
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:262
QgsTemporalNavigationObject::setCurrentFrameNumber
void setCurrentFrameNumber(long long frame)
Sets the current animation frame number.
Definition: qgstemporalnavigationobject.cpp:158
QgsUnitTypes::toString
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
Definition: qgsunittypes.cpp:199
QgsMeshLayer
Definition: qgsmeshlayer.h:94
QgsTemporalNavigationObject::setTemporalExtents
void setTemporalExtents(const QgsDateTimeRange &extents)
Sets the navigation temporal extents, which dictate the earliest and latest date time possible in the...
Definition: qgstemporalnavigationobject.cpp:129
QgsTemporalNavigationObject::setFramesPerSecond
void setFramesPerSecond(double rate)
Sets the animation frame rate, in frames per second.
Definition: qgstemporalnavigationobject.cpp:184
QgsTemporalController
Definition: qgstemporalcontroller.h:35
QgsMapLayer::temporalProperties
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal properties.
Definition: qgsmaplayer.h:1194
QgsTemporalNavigationObject::Idle
@ Idle
Animation is paused.
Definition: qgstemporalnavigationobject.h:63
QgsTemporalNavigationObject::totalFrameCount
long long totalFrameCount()
Returns the total number of frames for the navigation.
Definition: qgstemporalnavigationobject.cpp:264
QgsTemporalNavigationObject
Definition: qgstemporalnavigationobject.h:39
qgstemporalutils.h
qgsmeshlayer.h
QgsUnitTypes::TemporalHours
@ TemporalHours
Hours.
Definition: qgsunittypes.h:154
qgsprojecttimesettings.h
QgsUnitTypes::TemporalMinutes
@ TemporalMinutes
Minutes.
Definition: qgsunittypes.h:153
QgsUnitTypes::TemporalMilliseconds
@ TemporalMilliseconds
Milliseconds.
Definition: qgsunittypes.h:151
QgsTemporalController::updateTemporalRange
void updateTemporalRange(const QgsDateTimeRange &range)
Signals that a temporal range has changed and needs to be updated in all connected objects.
QgsUnitTypes::TemporalCenturies
@ TemporalCenturies
Centuries.
Definition: qgsunittypes.h:160
QgsTemporalNavigationObject::pause
void pause()
Pauses the temporal navigation.
Definition: qgstemporalnavigationobject.cpp:213
qgsmaplayermodel.h
QgsTemporalNavigationObject::next
void next()
Advances to the next frame.
Definition: qgstemporalnavigationobject.cpp:243
QgsUnitTypes::TemporalWeeks
@ TemporalWeeks
Weeks.
Definition: qgsunittypes.h:156
QgsTemporalNavigationObject::temporalRangeCumulative
bool temporalRangeCumulative() const
Returns the animation temporal range cumulative settings.
Definition: qgstemporalnavigationobject.cpp:203
QgsMapLayer
Definition: qgsmaplayer.h:81
QgsMapLayerModel::LayerRole
@ LayerRole
Stores pointer to the map layer itself.
Definition: qgsmaplayermodel.h:51
QgsInterval
A representation of the interval between two datetime values.
Definition: qgsinterval.h:40
QgsTemporalNavigationObject::previous
void previous()
Jumps back to the previous frame.
Definition: qgstemporalnavigationobject.cpp:248
QgsTemporalNavigationObject::NavigationOff
@ NavigationOff
Temporal navigation is disabled.
Definition: qgstemporalnavigationobject.h:53
QgsTemporalNavigationObject::AnimationState
AnimationState
Represents the current animation state.
Definition: qgstemporalnavigationobject.h:59
QgsTemporalControllerWidget::keyPressEvent
void keyPressEvent(QKeyEvent *e) override
Definition: qgstemporalcontrollerwidget.cpp:162
QgsMapLayerModel::index
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Definition: qgsmaplayermodel.cpp:186
QgsTemporalNavigationObject::currentFrameNumber
long long currentFrameNumber() const
Returns the current frame number.
Definition: qgstemporalnavigationobject.cpp:168
QgsInterval::isValid
bool isValid() const
Returns true if the interval is valid.
Definition: qgsinterval.h:181
QgsProjectTimeSettings::setTimeStep
void setTimeStep(double step)
Sets the project's time step (length of one animation frame), which is used as the default value when...
Definition: qgsprojecttimesettings.cpp:116
qgsproject.h
QgsProjectTimeSettings::setTimeStepUnit
void setTimeStepUnit(QgsUnitTypes::TemporalUnit unit)
Sets the project's time step (length of one animation frame) unit, which is used as the default value...
Definition: qgsprojecttimesettings.cpp:106
QgsTemporalNavigationObject::setNavigationMode
void setNavigationMode(const NavigationMode mode)
Sets the temporal navigation mode.
Definition: qgstemporalnavigationobject.cpp:107
QgsTemporalNavigationObject::FixedRange
@ FixedRange
Temporal navigation relies on a fixed datetime range.
Definition: qgstemporalnavigationobject.h:55
QgsProject::readNumEntry
int readNumEntry(const QString &scope, const QString &key, int def=0, bool *ok=nullptr) const
Definition: qgsproject.cpp:2472
QgsMapLayerModel
The QgsMapLayerModel class is a model to display layers in widgets.
Definition: qgsmaplayermodel.h:36
QgsTemporalNavigationObject::framesPerSecond
double framesPerSecond() const
Returns the animation frame rate, in frames per second.
Definition: qgstemporalnavigationobject.cpp:193
QgsTemporalNavigationObject::animationState
AnimationState animationState() const
Returns the current animation state.
Definition: qgstemporalnavigationobject.cpp:279
QgsTemporalUtils::calculateTemporalRangeForProject
static QgsDateTimeRange calculateTemporalRangeForProject(QgsProject *project)
Calculates the temporal range for a project.
Definition: qgstemporalutils.cpp:31