QGIS API Documentation  3.27.0-Master (11ef3e5184)
qgsprocessingmeshdatasetwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsprocessingmeshdatasetgroupswidget.h
3  ---------------------
4  Date : October 2020
5  Copyright : (C) 2020 by Vincent Cloarec
6  Email : vcloarec at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 #include "qgsdatetimeedit.h"
19 #include "qgsprocessingoutputs.h"
20 #include "qgsmeshlayer.h"
21 #include "qgsmeshlayerutils.h"
23 #include "qgspanelwidget.h"
24 #include "qgsmapcanvas.h"
27 
28 #include <QLineEdit>
29 #include <QLabel>
30 #include <QMenu>
31 #include <QToolButton>
32 #include <QVBoxLayout>
33 
35 
36 QgsProcessingMeshDatasetGroupsWidget::QgsProcessingMeshDatasetGroupsWidget( QWidget *parent, const QgsProcessingParameterMeshDatasetGroups *param )
37  : QWidget( parent ),
38  mParam( param )
39 {
40  QHBoxLayout *hl = new QHBoxLayout();
41  hl->setContentsMargins( 0, 0, 0, 0 );
42 
43  mLineEdit = new QLineEdit();
44  mLineEdit->setEnabled( false );
45  hl->addWidget( mLineEdit, 1 );
46 
47  mToolButton = new QToolButton();
48  mToolButton->setText( QString( QChar( 0x2026 ) ) );
49  hl->addWidget( mToolButton );
50 
51  setLayout( hl );
52 
53  mLineEdit->setText( tr( "%1 dataset groups selected" ).arg( 0 ) );
54 
55  mToolButton->setPopupMode( QToolButton::InstantPopup );
56  QMenu *toolButtonMenu = new QMenu( this );
57  mActionCurrentActiveDatasetGroups = toolButtonMenu->addAction( tr( "Current Active Dataset Group" ) );
58  connect( mActionCurrentActiveDatasetGroups,
59  &QAction::triggered, this, &QgsProcessingMeshDatasetGroupsWidget::selectCurrentActiveDatasetGroup );
60 
61  mActionAvailableDatasetGroups = toolButtonMenu->addAction( tr( "Select in Available Dataset Groups" ) );
62  connect( mActionAvailableDatasetGroups, &QAction::triggered, this, &QgsProcessingMeshDatasetGroupsWidget::showDialog );
63 
64  mToolButton->setMenu( toolButtonMenu );
65 }
66 
67 void QgsProcessingMeshDatasetGroupsWidget::setMeshLayer( QgsMeshLayer *layer, bool layerFromProject )
68 {
69  mActionCurrentActiveDatasetGroups->setEnabled( layer && layerFromProject );
70  mActionAvailableDatasetGroups->setEnabled( layer );
71 
72  if ( mMeshLayer == layer )
73  return;
74 
75  mDatasetGroupsNames.clear();
76 
77  if ( layerFromProject )
78  mMeshLayer = layer;
79  else
80  {
81  mMeshLayer = nullptr;
82  if ( layer )
83  {
84  QList<int> datasetGroupsIndexes = layer->datasetGroupsIndexes();
85  for ( int i : datasetGroupsIndexes )
86  {
88  if ( mParam->isDataTypeSupported( meta.dataType() ) )
89  {
90  mDatasetGroupsNames[i] = meta.name();
91  }
92  }
93  }
94  }
95  mValue.clear();
96  updateSummaryText();
97  emit changed();
98 }
99 
100 void QgsProcessingMeshDatasetGroupsWidget::setValue( const QVariant &value )
101 {
102  if ( value.isValid() )
103  mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
104  else
105  mValue.clear();
106 
107  updateSummaryText();
108  emit changed();
109 }
110 
111 QVariant QgsProcessingMeshDatasetGroupsWidget::value() const
112 {
113  return mValue;
114 }
115 
116 void QgsProcessingMeshDatasetGroupsWidget::showDialog()
117 {
118  QList<int> datasetGroupsIndexes;
119  QStringList options;
120  QVariantList availableOptions;
121  if ( mMeshLayer )
122  {
123  datasetGroupsIndexes = mMeshLayer->datasetGroupsIndexes();
124  for ( int i : std::as_const( datasetGroupsIndexes ) )
125  {
126  QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( i );
127  if ( mParam->isDataTypeSupported( meta.dataType() ) )
128  {
129  availableOptions.append( i );
130  options.append( meta.name() );
131  }
132  }
133  }
134  else
135  {
136  for ( int i : mDatasetGroupsNames.keys() )
137  {
138  availableOptions.append( i );
139  options.append( mDatasetGroupsNames.value( i ) );
140  }
141  }
142 
144  if ( panel && panel->dockMode() )
145  {
146  QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
147  widget->setPanelTitle( tr( "Dataset Groups Available" ) );
148 
149  widget->setValueFormatter( [availableOptions, options]( const QVariant & v ) -> QString
150  {
151  const int index = v.toInt();
152  const int pos = availableOptions.indexOf( index );
153  return ( pos >= 0 && pos < options.size() ) ? options.at( pos ) : QString();
154  } );
155 
156  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
157  {
158  setValue( widget->selectedOptions() );
159  } );
160  connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
161  panel->openPanel( widget );
162  }
163  else
164  {
165  QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
166 
167  dlg.setValueFormatter( [datasetGroupsIndexes, options]( const QVariant & v ) -> QString
168  {
169  const int index = v.toInt();
170  const int pos = datasetGroupsIndexes.indexOf( index );
171  return ( pos >= 0 && pos < options.size() ) ? options.at( pos ) : QString();
172  } );
173  if ( dlg.exec() )
174  {
175  setValue( dlg.selectedOptions() );
176  }
177  }
178 }
179 
180 void QgsProcessingMeshDatasetGroupsWidget::selectCurrentActiveDatasetGroup()
181 {
182  QVariantList options;
183  if ( mMeshLayer && mParam )
184  {
185  int scalarDatasetGroup = mMeshLayer->rendererSettings().activeScalarDatasetGroup();
186  int vectorDatasetGroup = mMeshLayer->rendererSettings().activeVectorDatasetGroup();
187 
188  if ( scalarDatasetGroup >= 0 && mParam->isDataTypeSupported( mMeshLayer->datasetGroupMetadata( scalarDatasetGroup ).dataType() ) )
189  options.append( scalarDatasetGroup );
190 
191  if ( vectorDatasetGroup >= 0
192  && mParam->isDataTypeSupported( mMeshLayer->datasetGroupMetadata( vectorDatasetGroup ).dataType() )
193  && vectorDatasetGroup != scalarDatasetGroup )
194  options.append( vectorDatasetGroup );
195  }
196 
197  setValue( options );
198 }
199 
200 QgsProcessingMeshDatasetGroupsWidgetWrapper::QgsProcessingMeshDatasetGroupsWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent ):
201  QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
202 {}
203 
204 QString QgsProcessingMeshDatasetGroupsWidgetWrapper::parameterType() const
205 {
207 }
208 
209 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMeshDatasetGroupsWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
210 {
211  return new QgsProcessingMeshDatasetGroupsWidgetWrapper( parameter, type );
212 }
213 
214 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMeshDatasetGroupsWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
215 {
216  return new QgsProcessingMeshDatasetGroupsParameterDefinitionWidget( context, widgetContext, definition, algorithm );
217 }
218 
219 void QgsProcessingMeshDatasetGroupsWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
220 {
222  switch ( type() )
223  {
226  {
227  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
228  {
229  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterMeshDatasetGroups * >( parameterDefinition() )->meshLayerParameterName() )
230  {
231  setMeshLayerWrapperValue( wrapper );
233  {
234  setMeshLayerWrapperValue( wrapper );
235  } );
236  break;
237  }
238  }
239  }
240  break;
242  break;
243  }
244 }
245 
246 void QgsProcessingMeshDatasetGroupsWidgetWrapper::setMeshLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
247 {
248  if ( ! mWidget )
249  return;
250 
251  // evaluate value to layer
252  QgsProcessingContext *context = nullptr;
253  if ( mProcessingContextGenerator )
254  context = mProcessingContextGenerator->processingContext();
255 
256  bool layerFromProject;
257  QgsMeshLayer *meshLayer;
258  if ( !context )
259  {
260  QgsProcessingContext dummyContext;
261  meshLayer = QgsProcessingParameters::parameterAsMeshLayer( wrapper->parameterDefinition(), wrapper->parameterValue(), dummyContext );
262  layerFromProject = false;
263  }
264  else
265  {
266  meshLayer = QgsProcessingParameters::parameterAsMeshLayer( wrapper->parameterDefinition(), wrapper->parameterValue(), *context );
267  layerFromProject = context->project() && context->project()->layerStore()->layers<QgsMeshLayer *>().contains( meshLayer );
268  }
269 
270  if ( mWidget )
271  mWidget->setMeshLayer( meshLayer, layerFromProject );
272 }
273 
274 QStringList QgsProcessingMeshDatasetGroupsWidgetWrapper::compatibleParameterTypes() const
275 {
276  return QStringList() << QgsProcessingParameterMeshDatasetGroups::typeName()
279 }
280 
281 QStringList QgsProcessingMeshDatasetGroupsWidgetWrapper::compatibleOutputTypes() const
282 {
283  return QStringList() << QgsProcessingOutputString::typeName()
285 }
286 
287 QWidget *QgsProcessingMeshDatasetGroupsWidgetWrapper::createWidget() SIP_FACTORY
288 {
289  mWidget = new QgsProcessingMeshDatasetGroupsWidget( nullptr, static_cast<const QgsProcessingParameterMeshDatasetGroups *>( parameterDefinition() ) );
290  connect( mWidget, &QgsProcessingMeshDatasetGroupsWidget::changed, this, [ = ]
291  {
292  emit widgetValueHasChanged( this );
293  } );
294 
295  return mWidget;
296 }
297 
298 void QgsProcessingMeshDatasetGroupsWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
299 {
300  if ( !mWidget )
301  return;
302 
303  QList<int> datasetGroupIndexes;
304  if ( value.type() == QVariant::List )
305  {
306  //here we can't use QgsProcessingParameters::parameterAsInts() because this method return empry list when first value is 0...
307  datasetGroupIndexes = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
308  }
309  else
310  datasetGroupIndexes.append( QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context ) );
311 
312  QVariantList varList;
313  for ( const int index : std::as_const( datasetGroupIndexes ) )
314  varList.append( index );
315 
316  mWidget->setValue( varList );
317 }
318 
319 QVariant QgsProcessingMeshDatasetGroupsWidgetWrapper::widgetValue() const
320 {
321  if ( mWidget )
322  return mWidget->value();
323  return QVariant();
324 }
325 
326 
327 void QgsProcessingMeshDatasetGroupsWidget::updateSummaryText()
328 {
329  mLineEdit->setText( tr( "%n option(s) selected", nullptr, mValue.count() ) );
330 }
331 
332 QgsProcessingMeshDatasetTimeWidgetWrapper::QgsProcessingMeshDatasetTimeWidgetWrapper( const QgsProcessingParameterDefinition *parameter,
334  QWidget *parent )
335  : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
336 {
337 
338 }
339 
340 QString QgsProcessingMeshDatasetTimeWidgetWrapper::parameterType() const
341 {
343 }
344 
345 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMeshDatasetTimeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
346 {
347  return new QgsProcessingMeshDatasetTimeWidgetWrapper( parameter, type );
348 }
349 
350 void QgsProcessingMeshDatasetTimeWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
351 {
353  switch ( type() )
354  {
357  {
358  const QgsAbstractProcessingParameterWidgetWrapper *layerParameterWrapper = nullptr;
359  const QgsAbstractProcessingParameterWidgetWrapper *datasetGroupsParameterWrapper = nullptr;
360  for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
361  {
362  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterMeshDatasetTime * >( parameterDefinition() )->meshLayerParameterName() )
363  layerParameterWrapper = wrapper;
364 
365  if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterMeshDatasetTime * >( parameterDefinition() )->datasetGroupParameterName() )
366  datasetGroupsParameterWrapper = wrapper;
367  }
368  setMeshLayerWrapperValue( layerParameterWrapper );
369  setDatasetGroupIndexesWrapperValue( datasetGroupsParameterWrapper );
370  connect( datasetGroupsParameterWrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [ = ]
371  {
372  setMeshLayerWrapperValue( layerParameterWrapper );
373  setDatasetGroupIndexesWrapperValue( datasetGroupsParameterWrapper );
374  } );
375 
376  break;
377  }
378 
380  break;
381  }
382 }
383 
384 QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMeshDatasetTimeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
385 {
386  return new QgsProcessingMeshDatasetTimeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
387 }
388 
389 void QgsProcessingMeshDatasetTimeWidgetWrapper::setMeshLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
390 {
391  if ( !mWidget || !wrapper )
392  return;
393 
394  // evaluate value to layer
395  QgsProcessingContext *context = nullptr;
396  if ( mProcessingContextGenerator )
397  context = mProcessingContextGenerator->processingContext();
398 
399  bool layerFromProject;
400  QgsMeshLayer *meshLayer;
401  if ( !context )
402  {
403  QgsProcessingContext dummyContext;
404  meshLayer = QgsProcessingParameters::parameterAsMeshLayer( wrapper->parameterDefinition(), wrapper->parameterValue(), dummyContext );
405  layerFromProject = false;
406  }
407  else
408  {
409  meshLayer = QgsProcessingParameters::parameterAsMeshLayer( wrapper->parameterDefinition(), wrapper->parameterValue(), *context );
410  layerFromProject = context->project() && context->project()->layerStore()->layers<QgsMeshLayer *>().contains( meshLayer );
411  }
412 
413  mWidget->setMeshLayer( meshLayer, layerFromProject );
414 }
415 
416 void QgsProcessingMeshDatasetTimeWidgetWrapper::setDatasetGroupIndexesWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
417 {
418  if ( !mWidget || !wrapper )
419  return;
420 
421  QVariant datasetGroupsVariant = wrapper->parameterValue();
422 
423  if ( !datasetGroupsVariant.isValid() || datasetGroupsVariant.type() != QVariant::List )
424  mWidget->setDatasetGroupIndexes( QList<int>() );
425 
426  QVariantList datasetGroupsListVariant = datasetGroupsVariant.toList();
427 
428  QList<int> datasetGroupsIndexes;
429  for ( const QVariant &variantIndex : datasetGroupsListVariant )
430  datasetGroupsIndexes << variantIndex.toInt();
431 
432  mWidget->setDatasetGroupIndexes( datasetGroupsIndexes );
433 
434 }
435 
436 QStringList QgsProcessingMeshDatasetTimeWidgetWrapper::compatibleParameterTypes() const
437 {
438  return QStringList()
442 }
443 
444 QStringList QgsProcessingMeshDatasetTimeWidgetWrapper::compatibleOutputTypes() const
445 {
446  return QStringList()
448 }
449 
450 QWidget *QgsProcessingMeshDatasetTimeWidgetWrapper::createWidget()
451 {
452  mWidget = new QgsProcessingMeshDatasetTimeWidget( nullptr, static_cast<const QgsProcessingParameterMeshDatasetTime *>( parameterDefinition() ), widgetContext() );
453 
454  QgsMapCanvas *canvas = widgetContext().mapCanvas();
455  if ( canvas )
456  {
457  connect( canvas, &QgsMapCanvas::temporalRangeChanged, mWidget, &QgsProcessingMeshDatasetTimeWidget::updateValue );
458  }
459  connect( mWidget, &QgsProcessingMeshDatasetTimeWidget::changed, this, [ = ]
460  {
461  emit widgetValueHasChanged( this );
462  } );
463 
464  return mWidget;
465 }
466 
467 void QgsProcessingMeshDatasetTimeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
468 {
469  Q_UNUSED( context );
470  if ( mWidget )
471  mWidget->setValue( value );
472 }
473 
474 QVariant QgsProcessingMeshDatasetTimeWidgetWrapper::widgetValue() const
475 {
476  if ( mWidget )
477  return mWidget->value();
478  return QVariant();
479 }
480 
481 QgsProcessingMeshDatasetTimeWidget::QgsProcessingMeshDatasetTimeWidget( QWidget *parent,
483  const QgsProcessingParameterWidgetContext &context ):
484  QWidget( parent ),
485  mParam( param )
486 {
487  setupUi( this );
488 
489  mValue.insert( QStringLiteral( "type" ), QStringLiteral( "static" ) );
490 
491  dateTimeEdit->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
492 
493  mCanvas = context.mapCanvas();
494 
495  connect( radioButtonCurrentCanvasTime, &QRadioButton::toggled, this, [this]( bool isChecked ) {if ( isChecked ) this->updateValue();} );
496  connect( radioButtonDefinedDateTime, &QRadioButton::toggled, this, [this]( bool isChecked ) {if ( isChecked ) this->updateValue();} );
497  connect( radioButtonDatasetGroupTimeStep, &QRadioButton::toggled, this, [this]( bool isChecked ) {if ( isChecked ) this->updateValue();} );
498  connect( dateTimeEdit, &QgsDateTimeEdit::dateTimeChanged, this, &QgsProcessingMeshDatasetTimeWidget::updateValue );
499  connect( comboBoxDatasetTimeStep, qOverload<int>( &QComboBox::currentIndexChanged ),
500  this, &QgsProcessingMeshDatasetTimeWidget::updateValue );
501 
502  updateWidget();
503 }
504 
505 void QgsProcessingMeshDatasetTimeWidget::setMeshLayer( QgsMeshLayer *layer, bool layerFromProject )
506 {
507  if ( mMeshLayer == layer )
508  return;
509 
510  mReferenceTime = QDateTime();
511 
512  if ( layerFromProject )
513  {
514  mMeshLayer = layer;
515  mReferenceTime = static_cast<QgsMeshLayerTemporalProperties *>( layer->temporalProperties() )->referenceTime();
516  }
517  else
518  {
519  mMeshLayer = nullptr;
520  if ( layer )
521  mReferenceTime = layer->dataProvider()->temporalCapabilities()->referenceTime();
522  storeTimeStepsFromLayer( layer );
523  }
524 
525  if ( mReferenceTime.isValid() )
526  whileBlocking( dateTimeEdit )->setDateTime( mReferenceTime );
527 
528  updateValue();
529 }
530 
531 void QgsProcessingMeshDatasetTimeWidget::setDatasetGroupIndexes( const QList<int> datasetGroupIndexes )
532 {
533  if ( datasetGroupIndexes == mDatasetGroupIndexes )
534  return;
535  mDatasetGroupIndexes = datasetGroupIndexes;
536  populateTimeSteps();
537  updateValue();
538 }
539 
540 void QgsProcessingMeshDatasetTimeWidget::setValue( const QVariant &value )
541 {
542  if ( !value.isValid() || ( value.type() != QVariant::Map && !value.toDateTime().isValid() ) )
543  return;
544 
545  mValue.clear();
546  if ( value.toDateTime().isValid() )
547  {
548  QDateTime dateTime = value.toDateTime();
549  dateTime.setTimeSpec( Qt::UTC );
550  mValue.insert( QStringLiteral( "type" ), QStringLiteral( "defined-date-time" ) );
551  mValue.insert( QStringLiteral( "value" ), dateTime );
552  }
553  else
554  mValue = value.toMap();
555 
556  if ( !mValue.contains( QStringLiteral( "type" ) ) || !mValue.contains( QStringLiteral( "value" ) ) )
557  return;
558 
559  QString type = mValue.value( QStringLiteral( "type" ) ).toString();
560 
561  setEnabled( true );
562  if ( type == QLatin1String( "static" ) )
563  {
564  setEnabled( false );
565  }
566  else if ( type == QLatin1String( "dataset-time-step" ) )
567  {
568  QVariantList dataset = mValue.value( QStringLiteral( "value" ) ).toList();
569  whileBlocking( comboBoxDatasetTimeStep )->setCurrentIndex( comboBoxDatasetTimeStep->findData( dataset ) );
570  whileBlocking( radioButtonDatasetGroupTimeStep )->setChecked( true );
571  }
572  else if ( type == QLatin1String( "defined-date-time" ) )
573  {
574  whileBlocking( dateTimeEdit )->setDateTime( mValue.value( QStringLiteral( "value" ) ).toDateTime() );
575  whileBlocking( radioButtonDefinedDateTime )->setChecked( true );
576  }
577  else if ( type == QLatin1String( "current-context-time" ) )
578  {
579  whileBlocking( radioButtonCurrentCanvasTime )->setChecked( true );
580  }
581 
582  emit changed();
583  updateWidget();
584 }
585 
586 QVariant QgsProcessingMeshDatasetTimeWidget::value() const
587 {
588  return mValue;
589 }
590 
591 void QgsProcessingMeshDatasetTimeWidget::updateWidget()
592 {
593  bool isStatic = !hasTemporalDataset();
594  setEnabled( !isStatic );
595 
596  if ( mCanvas != nullptr && mCanvas->mapSettings().isTemporal() )
597  {
598  whileBlocking( radioButtonCurrentCanvasTime )->setEnabled( true && mReferenceTime.isValid() );
599  labelCurrentCanvasTime->setText( mCanvas->mapSettings().temporalRange().begin().toString( "yyyy-MM-dd HH:mm:ss" ) );
600  }
601  else
602  {
603  whileBlocking( radioButtonCurrentCanvasTime )->setEnabled( false );
604  if ( radioButtonCurrentCanvasTime->isChecked() )
605  whileBlocking( radioButtonDefinedDateTime )->setChecked( true );
606  }
607 
608  if ( ! mReferenceTime.isValid() )
609  whileBlocking( radioButtonDatasetGroupTimeStep )->setChecked( true );
610 
611  whileBlocking( radioButtonDefinedDateTime )->setEnabled( mReferenceTime.isValid() );
612 
613  dateTimeEdit->setVisible( radioButtonDefinedDateTime->isChecked() && !isStatic );
614  labelCurrentCanvasTime->setVisible( radioButtonCurrentCanvasTime->isChecked() && !isStatic );
615  comboBoxDatasetTimeStep->setVisible( radioButtonDatasetGroupTimeStep->isChecked() && !isStatic );
616 }
617 
618 bool QgsProcessingMeshDatasetTimeWidget::hasTemporalDataset() const
619 {
620  for ( int index : mDatasetGroupIndexes )
621  {
622  if ( mMeshLayer && mMeshLayer->datasetGroupMetadata( index ).isTemporal() )
623  return true;
624  else if ( mDatasetTimeSteps.contains( index ) )
625  return true;
626  }
627 
628  return false;
629 }
630 
631 
632 void QgsProcessingMeshDatasetTimeWidget::populateTimeSteps()
633 {
634  if ( mMeshLayer )
635  {
636  populateTimeStepsFromLayer();
637  return;
638  }
639 
640  QMap<quint64, QgsMeshDatasetIndex> timeStep;
641  for ( int groupIndex : mDatasetGroupIndexes )
642  {
643  if ( !mDatasetTimeSteps.contains( groupIndex ) )
644  continue;
645  const QList<qint64> relativeTimeSteps = mDatasetTimeSteps.value( groupIndex );
646  for ( int index = 0; index < relativeTimeSteps.count(); ++index )
647  {
648  QgsMeshDatasetIndex datasetIndex( groupIndex, index );
649  if ( timeStep.contains( relativeTimeSteps.at( index ) ) )
650  continue;
651  timeStep[relativeTimeSteps.at( index )] = datasetIndex;
652  }
653  }
654 
655  for ( qint64 key : timeStep.keys() )
656  {
657  QString stringTime = QgsMeshLayerUtils::formatTime( key / 1000 / 3600, mReferenceTime, QgsMeshTimeSettings() );
658  QVariantList data;
659  const QgsMeshDatasetIndex &index = timeStep.value( key );
660  data << index.group() << index.dataset();
661  whileBlocking( comboBoxDatasetTimeStep )->addItem( stringTime, data );
662  }
663 
664 }
665 
666 void QgsProcessingMeshDatasetTimeWidget::populateTimeStepsFromLayer()
667 {
668  whileBlocking( comboBoxDatasetTimeStep )->clear();
669 
670  if ( !mMeshLayer )
671  return;
672 
673  QMap<quint64, QgsMeshDatasetIndex> timeStep;
674  for ( int groupIndex : std::as_const( mDatasetGroupIndexes ) )
675  {
676  QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( groupIndex );
677  if ( !meta.isTemporal() )
678  continue;
679  int datasetCount = mMeshLayer->datasetCount( groupIndex );
680 
681  for ( int index = 0; index < datasetCount; ++index )
682  {
683  QgsMeshDatasetIndex datasetIndex( groupIndex, index );
684  qint64 relativeTime = mMeshLayer->datasetRelativeTimeInMilliseconds( datasetIndex );
685  if ( timeStep.contains( relativeTime ) )
686  continue;
687  timeStep[relativeTime] = datasetIndex;
688  }
689  }
690 
691  for ( qint64 key : timeStep.keys() )
692  {
693  QString stringTime = mMeshLayer->formatTime( key / 1000.0 / 3600.0 );
694  QVariantList data;
695  const QgsMeshDatasetIndex &index = timeStep.value( key );
696  data << index.group() << index.dataset();
697  whileBlocking( comboBoxDatasetTimeStep )->addItem( stringTime, data );
698  }
699 }
700 
701 void QgsProcessingMeshDatasetTimeWidget::storeTimeStepsFromLayer( QgsMeshLayer *layer )
702 {
703  mDatasetTimeSteps.clear();
704  if ( !layer )
705  return;
706  QList<int> datasetGroupsList = layer->datasetGroupsIndexes();
707  for ( int groupIndex : datasetGroupsList )
708  {
709  QgsMeshDatasetGroupMetadata meta = layer->datasetGroupMetadata( groupIndex );
710  if ( !meta.isTemporal() )
711  continue;
712  int datasetCount = layer->datasetCount( groupIndex );
713  QList<qint64> relativeTimeSteps;
714  relativeTimeSteps.reserve( datasetCount );
715  for ( int index = 0; index < datasetCount; ++index )
716  relativeTimeSteps.append( layer->datasetRelativeTimeInMilliseconds( QgsMeshDatasetIndex( groupIndex, index ) ) );
717  mDatasetTimeSteps[groupIndex] = relativeTimeSteps;
718  }
719 }
720 
721 void QgsProcessingMeshDatasetTimeWidget::buildValue()
722 {
723  mValue.clear();
724 
725  if ( !isEnabled() )
726  {
727  mValue[QStringLiteral( "type" )] = QStringLiteral( "static" );
728  }
729  else if ( radioButtonDatasetGroupTimeStep->isChecked() )
730  {
731  mValue[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" );
732  mValue[QStringLiteral( "value" )] = comboBoxDatasetTimeStep->currentData();
733  }
734  else if ( radioButtonDefinedDateTime->isChecked() )
735  {
736  mValue[QStringLiteral( "type" )] = QStringLiteral( "defined-date-time" );
737  mValue[QStringLiteral( "value" )] = dateTimeEdit->dateTime();
738  }
739  else if ( radioButtonCurrentCanvasTime->isChecked() && mCanvas )
740  {
741  mValue[QStringLiteral( "type" )] = QStringLiteral( "current-context-time" );
742  }
743 
744  emit changed();
745 }
746 
747 void QgsProcessingMeshDatasetTimeWidget::updateValue()
748 {
749  updateWidget();
750  buildValue();
751 }
752 
753 
754 QgsProcessingMeshDatasetGroupsParameterDefinitionWidget::QgsProcessingMeshDatasetGroupsParameterDefinitionWidget(
755  QgsProcessingContext &context,
756  const QgsProcessingParameterWidgetContext &widgetContext,
757  const QgsProcessingParameterDefinition *definition,
759  QWidget *parent )
760  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
761 {
762  QVBoxLayout *vlayout = new QVBoxLayout();
763  vlayout->setContentsMargins( 0, 0, 0, 0 );
764 
765  vlayout->addWidget( new QLabel( tr( "Linked input" ) ) );
766 
767  mParentLayerComboBox = new QComboBox();
768  vlayout->addWidget( mParentLayerComboBox );
769 
770  if ( QgsProcessingModelAlgorithm *model = widgetContext.model() )
771  {
772  const QMap<QString, QgsProcessingModelParameter> components = model->parameterComponents();
773  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
774  {
775  const QgsProcessingParameterDefinition *def = model->parameterDefinition( it.value().parameterName() );
776  if ( def && def->type() == QgsProcessingParameterMeshLayer::typeName() )
777  {
778  mParentLayerComboBox->addItem( def->description(), def->name() );
779  }
780  }
781  }
782 
783  const QgsProcessingParameterMeshDatasetGroups *datasetGroupDef =
784  static_cast< const QgsProcessingParameterMeshDatasetGroups *>( definition );
785  int currentIndex = mParentLayerComboBox->findData( datasetGroupDef->meshLayerParameterName() );
786  if ( currentIndex != -1 )
787  mParentLayerComboBox->setCurrentIndex( currentIndex );
788  else if ( !datasetGroupDef->meshLayerParameterName().isEmpty() )
789  {
790  // if no layer parameter candidates found, we just add the existing one as a placeholder
791  mParentLayerComboBox->addItem( datasetGroupDef->meshLayerParameterName(), datasetGroupDef->meshLayerParameterName() );
792  mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
793  }
794 
795  setLayout( vlayout );
796 }
797 
798 QgsProcessingParameterDefinition *QgsProcessingMeshDatasetGroupsParameterDefinitionWidget::createParameter(
799  const QString &name,
800  const QString &description,
801  QgsProcessingParameterDefinition::Flags flags ) const
802 {
803  QSet<int> supportedDataType;
804  supportedDataType.insert( QgsMeshDatasetGroupMetadata::DataOnEdges );
805  supportedDataType.insert( QgsMeshDatasetGroupMetadata::DataOnVertices );
806  supportedDataType.insert( QgsMeshDatasetGroupMetadata::DataOnFaces );
807  supportedDataType.insert( QgsMeshDatasetGroupMetadata::DataOnVolumes );
808  std::unique_ptr<QgsProcessingParameterMeshDatasetGroups> param =
809  std::make_unique<QgsProcessingParameterMeshDatasetGroups>( name, description, mParentLayerComboBox->currentData().toString(), supportedDataType );
810  param->setFlags( flags );
811  return param.release();
812 }
813 
814 QgsProcessingMeshDatasetTimeParameterDefinitionWidget::QgsProcessingMeshDatasetTimeParameterDefinitionWidget(
815  QgsProcessingContext &context,
816  const QgsProcessingParameterWidgetContext &widgetContext,
817  const QgsProcessingParameterDefinition *definition,
819  QWidget *parent )
820  : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
821 {
822  if ( definition )
823  {
824  const QgsProcessingParameterMeshDatasetTime *datasetTimeDef =
825  static_cast< const QgsProcessingParameterMeshDatasetTime *>( definition );
826  mMeshLayerParameterName = datasetTimeDef->meshLayerParameterName();
827  }
828 
829  QVBoxLayout *vlayout = new QVBoxLayout();
830  vlayout->setContentsMargins( 0, 0, 0, 0 );
831 
832  vlayout->addWidget( new QLabel( tr( "Linked input" ) ) );
833 
834  mParentDatasetComboBox = new QComboBox();
835  vlayout->addWidget( mParentDatasetComboBox );
836 
837  QgsProcessingModelAlgorithm *model = widgetContext.model();
838  if ( model )
839  {
840  const QMap<QString, QgsProcessingModelParameter> components = model->parameterComponents();
841  for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
842  {
843  const QgsProcessingParameterDefinition *def = model->parameterDefinition( it.value().parameterName() );
845  mParentDatasetComboBox->addItem( def->description(), def->name() );
846  }
847  }
848 
849  if ( definition )
850  {
851  const QgsProcessingParameterMeshDatasetTime *datasetTimeDef =
852  static_cast< const QgsProcessingParameterMeshDatasetTime *>( definition );
853  int currentIndex = mParentDatasetComboBox->findData( datasetTimeDef->datasetGroupParameterName() );
854  if ( currentIndex != -1 )
855  mParentDatasetComboBox->setCurrentIndex( currentIndex );
856  else if ( !datasetTimeDef->meshLayerParameterName().isEmpty() )
857  {
858  // if no layer parameter candidates found, we just add the existing one as a placeholder
859  mParentDatasetComboBox->addItem( datasetTimeDef->datasetGroupParameterName(), datasetTimeDef->datasetGroupParameterName() );
860  mParentDatasetComboBox->setCurrentIndex( mParentDatasetComboBox->count() - 1 );
861  }
862  }
863 
864  if ( model )
865  {
866  const QgsProcessingParameterDefinition *currentDef = model->parameterDefinition( mParentDatasetComboBox->currentData().toString() );
867  if ( currentDef )
868  mMeshLayerParameterName = static_cast<const QgsProcessingParameterMeshDatasetGroups *>( currentDef )->meshLayerParameterName();
869 
870  connect( mParentDatasetComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this, model]
871  {
872  const QgsProcessingParameterDefinition *currentDef = model->parameterDefinition( mParentDatasetComboBox->currentData().toString() );
873  if ( currentDef )
874  mMeshLayerParameterName = static_cast<const QgsProcessingParameterMeshDatasetGroups *>( currentDef )->meshLayerParameterName();
875  } );
876  }
877 
878  setLayout( vlayout );
879 }
880 
881 QgsProcessingParameterDefinition *QgsProcessingMeshDatasetTimeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
882 {
883  std::unique_ptr<QgsProcessingParameterMeshDatasetTime> param = std::make_unique<QgsProcessingParameterMeshDatasetTime>(
884  name, description, mMeshLayerParameterName, mParentDatasetComboBox->currentData().toString() );
885 
886  param->setFlags( flags );
887  return param.release();
888 }
889 
891 
A widget wrapper for Processing parameter value widgets.
QVariant parameterValue() const
Returns the current value of the parameter.
void widgetValueHasChanged(QgsAbstractProcessingParameterWidgetWrapper *wrapper)
Emitted whenever the parameter value (as defined by the wrapped widget) is changed.
virtual void postInitialize(const QList< QgsAbstractProcessingParameterWidgetWrapper * > &wrappers)
Called after all wrappers have been created within a particular dialog or context,...
const QgsProcessingParameterDefinition * parameterDefinition() const
Returns the parameter definition associated with this wrapper.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:90
void temporalRangeChanged()
Emitted when the map canvas temporal range changes.
QVector< T > layers() const
Returns a list of registered map layers with a specified layer type.
QDateTime referenceTime() const
Returns the reference time.
QgsMeshDataProviderTemporalCapabilities * temporalCapabilities() override
Returns the provider's temporal capabilities.
QgsMeshDatasetGroupMetadata is a collection of dataset group metadata such as whether the data is vec...
bool isTemporal() const
Returns whether the dataset group is temporal (contains time-related dataset)
QString name() const
Returns name of the dataset group.
DataType dataType() const
Returns whether dataset group data is defined on vertices or faces or volumes.
@ DataOnEdges
Data is defined on edges.
@ DataOnFaces
Data is defined on faces.
@ DataOnVertices
Data is defined on vertices.
@ DataOnVolumes
Data is defined on volumes.
QgsMeshDatasetIndex is index that identifies the dataset group (e.g.
int group() const
Returns a group index.
int dataset() const
Returns a dataset index within group()
Implementation of map layer temporal properties for mesh layers.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:99
int datasetCount(const QgsMeshDatasetIndex &index) const
Returns the dataset count in the dataset groups.
QList< int > datasetGroupsIndexes() const
Returns the list of indexes of dataset groups handled by the layer.
QgsMeshDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
qint64 datasetRelativeTimeInMilliseconds(const QgsMeshDatasetIndex &index)
Returns the relative time (in milliseconds) of the dataset from the reference time of its group.
QgsMeshDatasetGroupMetadata datasetGroupMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset groups metadata.
Represents a mesh time settings for mesh datasets.
Base class for any widget that can be shown as a inline panel.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
void acceptPanel()
Accept the panel.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
bool dockMode()
Returns the dock mode state.
Abstract base class for widgets which allow users to specify the properties of a Processing parameter...
Abstract base class for processing algorithms.
Contains information about the context in which a processing algorithm is executed.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
WidgetType
Types of dialogs which Processing widgets can be created for.
@ Modeler
Modeler dialog.
@ Standard
Standard algorithm dialog.
@ Batch
Batch processing dialog.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the parameter class.
Base class for the definition of processing parameters.
QString description() const
Returns the description for the parameter.
virtual QString type() const =0
Unique parameter type name.
QString name() const
Returns the name of the parameter.
A parameter for processing algorithms that need a list of mesh dataset groups.
static QString typeName()
Returns the type name for the parameter class.
QString meshLayerParameterName() const
Returns the name of the mesh layer parameter.
A parameter for processing algorithms that need a list of mesh dataset index from time parameter.
QString datasetGroupParameterName() const
Returns the name of the dataset groups parameter.
QString meshLayerParameterName() const
Returns the name of the mesh layer parameter.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
Contains settings which reflect the context in which a Processing parameter widget is shown,...
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
QgsProcessingModelAlgorithm * model() const
Returns the model which the parameter widget is associated with.
static QList< int > parameterAsInts(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a list of integer values.
static QgsMeshLayer * parameterAsMeshLayer(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition and value to a mesh layer.
static int parameterAsInt(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static integer value.
QgsMapLayerStore * layerStore()
Returns a pointer to the project's internal layer store.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:2453
#define SIP_FACTORY
Definition: qgis_sip.h:76