QGIS API Documentation 3.99.0-Master (09f76ad7019)
Loading...
Searching...
No Matches
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
18#include "qgsdatetimeedit.h"
19#include "qgsmapcanvas.h"
20#include "qgsmeshlayer.h"
22#include "qgsmeshlayerutils.h"
23#include "qgspanelwidget.h"
28
29#include <QLabel>
30#include <QLineEdit>
31#include <QMenu>
32#include <QString>
33#include <QToolButton>
34#include <QVBoxLayout>
35
36#include "moc_qgsprocessingmeshdatasetwidget.cpp"
37
38using namespace Qt::StringLiterals;
39
41
42QgsProcessingMeshDatasetGroupsWidget::QgsProcessingMeshDatasetGroupsWidget( QWidget *parent, const QgsProcessingParameterMeshDatasetGroups *param )
43 : QWidget( parent ), mParam( param )
44{
45 QHBoxLayout *hl = new QHBoxLayout();
46 hl->setContentsMargins( 0, 0, 0, 0 );
47
48 mLineEdit = new QLineEdit();
49 mLineEdit->setEnabled( false );
50 hl->addWidget( mLineEdit, 1 );
51
52 mToolButton = new QToolButton();
53 mToolButton->setText( QString( QChar( 0x2026 ) ) );
54 hl->addWidget( mToolButton );
55
56 setLayout( hl );
57
58 mLineEdit->setText( tr( "%1 dataset groups selected" ).arg( 0 ) );
59
60 mToolButton->setPopupMode( QToolButton::InstantPopup );
61 QMenu *toolButtonMenu = new QMenu( this );
62 mActionCurrentActiveDatasetGroups = toolButtonMenu->addAction( tr( "Current Active Dataset Group" ) );
63 connect( mActionCurrentActiveDatasetGroups, &QAction::triggered, this, &QgsProcessingMeshDatasetGroupsWidget::selectCurrentActiveDatasetGroup );
64
65 mActionAvailableDatasetGroups = toolButtonMenu->addAction( tr( "Select in Available Dataset Groups" ) );
66 connect( mActionAvailableDatasetGroups, &QAction::triggered, this, &QgsProcessingMeshDatasetGroupsWidget::showDialog );
67
68 mToolButton->setMenu( toolButtonMenu );
69}
70
71void QgsProcessingMeshDatasetGroupsWidget::setMeshLayer( QgsMeshLayer *layer, bool layerFromProject )
72{
73 mActionCurrentActiveDatasetGroups->setEnabled( layer && layerFromProject );
74 mActionAvailableDatasetGroups->setEnabled( layer );
75
76 if ( mMeshLayer == layer )
77 return;
78
79 mDatasetGroupsNames.clear();
80
81 if ( layerFromProject )
82 mMeshLayer = layer;
83 else
84 {
85 mMeshLayer = nullptr;
86 if ( layer )
87 {
88 QList<int> datasetGroupsIndexes = layer->datasetGroupsIndexes();
89 for ( int i : datasetGroupsIndexes )
90 {
92 if ( mParam->isDataTypeSupported( meta.dataType() ) )
93 {
94 mDatasetGroupsNames[i] = meta.name();
95 }
96 }
97 }
98 }
99 mValue.clear();
100 updateSummaryText();
101 emit changed();
102}
103
104void QgsProcessingMeshDatasetGroupsWidget::setValue( const QVariant &value )
105{
106 if ( value.isValid() )
107 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
108 else
109 mValue.clear();
110
111 updateSummaryText();
112 emit changed();
113}
114
115QVariant QgsProcessingMeshDatasetGroupsWidget::value() const
116{
117 return mValue;
118}
119
120void QgsProcessingMeshDatasetGroupsWidget::showDialog()
121{
122 QList<int> datasetGroupsIndexes;
123 QStringList options;
124 QVariantList availableOptions;
125 if ( mMeshLayer )
126 {
127 datasetGroupsIndexes = mMeshLayer->datasetGroupsIndexes();
128 for ( int i : std::as_const( datasetGroupsIndexes ) )
129 {
130 QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( i );
131 if ( mParam->isDataTypeSupported( meta.dataType() ) )
132 {
133 availableOptions.append( i );
134 options.append( meta.name() );
135 }
136 }
137 }
138 else
139 {
140 for ( auto it = mDatasetGroupsNames.constBegin(); it != mDatasetGroupsNames.constEnd(); it++ )
141 {
142 availableOptions.append( it.key() );
143 options.append( it.value() );
144 }
145 }
146
148 if ( panel && panel->dockMode() )
149 {
150 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
151 widget->setPanelTitle( tr( "Dataset Groups Available" ) );
152
153 widget->setValueFormatter( [availableOptions, options]( const QVariant &v ) -> QString {
154 const int index = v.toInt();
155 const int pos = availableOptions.indexOf( index );
156 return ( pos >= 0 && pos < options.size() ) ? options.at( pos ) : QString();
157 } );
158
159 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [this, widget]() {
160 setValue( widget->selectedOptions() );
161 } );
162 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
163 panel->openPanel( widget );
164 }
165 else
166 {
167 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
168
169 dlg.setValueFormatter( [datasetGroupsIndexes, options]( const QVariant &v ) -> QString {
170 const int index = v.toInt();
171 const int pos = datasetGroupsIndexes.indexOf( index );
172 return ( pos >= 0 && pos < options.size() ) ? options.at( pos ) : QString();
173 } );
174 if ( dlg.exec() )
175 {
176 setValue( dlg.selectedOptions() );
177 }
178 }
179}
180
181void QgsProcessingMeshDatasetGroupsWidget::selectCurrentActiveDatasetGroup()
182{
183 QVariantList options;
184 if ( mMeshLayer && mParam )
185 {
186 int scalarDatasetGroup = mMeshLayer->rendererSettings().activeScalarDatasetGroup();
187 int vectorDatasetGroup = mMeshLayer->rendererSettings().activeVectorDatasetGroup();
188
189 if ( scalarDatasetGroup >= 0 && mParam->isDataTypeSupported( mMeshLayer->datasetGroupMetadata( scalarDatasetGroup ).dataType() ) )
190 options.append( scalarDatasetGroup );
191
192 if ( vectorDatasetGroup >= 0
193 && mParam->isDataTypeSupported( mMeshLayer->datasetGroupMetadata( vectorDatasetGroup ).dataType() )
194 && vectorDatasetGroup != scalarDatasetGroup )
195 options.append( vectorDatasetGroup );
196 }
197
198 setValue( options );
199}
200
201QgsProcessingMeshDatasetGroupsWidgetWrapper::QgsProcessingMeshDatasetGroupsWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
202 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
203{}
204
205QString QgsProcessingMeshDatasetGroupsWidgetWrapper::parameterType() const
206{
208}
209
210QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMeshDatasetGroupsWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
211{
212 return new QgsProcessingMeshDatasetGroupsWidgetWrapper( parameter, type );
213}
214
215QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMeshDatasetGroupsWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
216{
217 return new QgsProcessingMeshDatasetGroupsParameterDefinitionWidget( context, widgetContext, definition, algorithm );
218}
219
220void QgsProcessingMeshDatasetGroupsWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
221{
223 switch ( type() )
224 {
227 {
228 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
229 {
230 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterMeshDatasetGroups *>( parameterDefinition() )->meshLayerParameterName() )
231 {
232 setMeshLayerWrapperValue( wrapper );
233 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
234 setMeshLayerWrapperValue( wrapper );
235 } );
236 break;
237 }
238 }
239 }
240 break;
242 break;
243 }
244}
245
246void 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
274QWidget *QgsProcessingMeshDatasetGroupsWidgetWrapper::createWidget() SIP_FACTORY
275{
276 mWidget = new QgsProcessingMeshDatasetGroupsWidget( nullptr, static_cast<const QgsProcessingParameterMeshDatasetGroups *>( parameterDefinition() ) );
277 connect( mWidget, &QgsProcessingMeshDatasetGroupsWidget::changed, this, [this] {
278 emit widgetValueHasChanged( this );
279 } );
280
281 return mWidget;
282}
283
284void QgsProcessingMeshDatasetGroupsWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
285{
286 if ( !mWidget )
287 return;
288
289 QList<int> datasetGroupIndexes;
290 if ( value.userType() == QMetaType::Type::QVariantList )
291 {
292 //here we can't use QgsProcessingParameters::parameterAsInts() because this method return empry list when first value is 0...
293 datasetGroupIndexes = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
294 }
295 else
296 datasetGroupIndexes.append( QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context ) );
297
298 QVariantList varList;
299 for ( const int index : std::as_const( datasetGroupIndexes ) )
300 varList.append( index );
301
302 mWidget->setValue( varList );
303}
304
305QVariant QgsProcessingMeshDatasetGroupsWidgetWrapper::widgetValue() const
306{
307 if ( mWidget )
308 return mWidget->value();
309 return QVariant();
310}
311
312
313void QgsProcessingMeshDatasetGroupsWidget::updateSummaryText()
314{
315 mLineEdit->setText( tr( "%n option(s) selected", nullptr, mValue.count() ) );
316}
317
318QgsProcessingMeshDatasetTimeWidgetWrapper::QgsProcessingMeshDatasetTimeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
319 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
320{
321}
322
323QString QgsProcessingMeshDatasetTimeWidgetWrapper::parameterType() const
324{
326}
327
328QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMeshDatasetTimeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
329{
330 return new QgsProcessingMeshDatasetTimeWidgetWrapper( parameter, type );
331}
332
333void QgsProcessingMeshDatasetTimeWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
334{
336 switch ( type() )
337 {
340 {
341 const QgsAbstractProcessingParameterWidgetWrapper *layerParameterWrapper = nullptr;
342 const QgsAbstractProcessingParameterWidgetWrapper *datasetGroupsParameterWrapper = nullptr;
343 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
344 {
345 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterMeshDatasetTime *>( parameterDefinition() )->meshLayerParameterName() )
346 layerParameterWrapper = wrapper;
347
348 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterMeshDatasetTime *>( parameterDefinition() )->datasetGroupParameterName() )
349 datasetGroupsParameterWrapper = wrapper;
350 }
351 setMeshLayerWrapperValue( layerParameterWrapper );
352 setDatasetGroupIndexesWrapperValue( datasetGroupsParameterWrapper );
353 connect( datasetGroupsParameterWrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, layerParameterWrapper, datasetGroupsParameterWrapper] {
354 setMeshLayerWrapperValue( layerParameterWrapper );
355 setDatasetGroupIndexesWrapperValue( datasetGroupsParameterWrapper );
356 } );
357
358 break;
359 }
360
362 break;
363 }
364}
365
366QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMeshDatasetTimeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
367{
368 return new QgsProcessingMeshDatasetTimeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
369}
370
371void QgsProcessingMeshDatasetTimeWidgetWrapper::setMeshLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
372{
373 if ( !mWidget || !wrapper )
374 return;
375
376 // evaluate value to layer
377 QgsProcessingContext *context = nullptr;
378 if ( mProcessingContextGenerator )
379 context = mProcessingContextGenerator->processingContext();
380
381 bool layerFromProject;
382 QgsMeshLayer *meshLayer;
383 if ( !context )
384 {
385 QgsProcessingContext dummyContext;
386 meshLayer = QgsProcessingParameters::parameterAsMeshLayer( wrapper->parameterDefinition(), wrapper->parameterValue(), dummyContext );
387 layerFromProject = false;
388 }
389 else
390 {
391 meshLayer = QgsProcessingParameters::parameterAsMeshLayer( wrapper->parameterDefinition(), wrapper->parameterValue(), *context );
392 layerFromProject = context->project() && context->project()->layerStore()->layers<QgsMeshLayer *>().contains( meshLayer );
393 }
394
395 mWidget->setMeshLayer( meshLayer, layerFromProject );
396}
397
398void QgsProcessingMeshDatasetTimeWidgetWrapper::setDatasetGroupIndexesWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
399{
400 if ( !mWidget || !wrapper )
401 return;
402
403 QVariant datasetGroupsVariant = wrapper->parameterValue();
404
405 if ( !datasetGroupsVariant.isValid() || datasetGroupsVariant.userType() != QMetaType::Type::QVariantList )
406 mWidget->setDatasetGroupIndexes( QList<int>() );
407
408 QVariantList datasetGroupsListVariant = datasetGroupsVariant.toList();
409
410 QList<int> datasetGroupsIndexes;
411 for ( const QVariant &variantIndex : datasetGroupsListVariant )
412 datasetGroupsIndexes << variantIndex.toInt();
413
414 mWidget->setDatasetGroupIndexes( datasetGroupsIndexes );
415}
416
417QWidget *QgsProcessingMeshDatasetTimeWidgetWrapper::createWidget()
418{
419 mWidget = new QgsProcessingMeshDatasetTimeWidget( nullptr, static_cast<const QgsProcessingParameterMeshDatasetTime *>( parameterDefinition() ), widgetContext() );
420
421 QgsMapCanvas *canvas = widgetContext().mapCanvas();
422 if ( canvas )
423 {
424 connect( canvas, &QgsMapCanvas::temporalRangeChanged, mWidget, &QgsProcessingMeshDatasetTimeWidget::updateValue );
425 }
426 connect( mWidget, &QgsProcessingMeshDatasetTimeWidget::changed, this, [this] {
427 emit widgetValueHasChanged( this );
428 } );
429
430 return mWidget;
431}
432
433void QgsProcessingMeshDatasetTimeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
434{
435 Q_UNUSED( context );
436 if ( mWidget )
437 mWidget->setValue( value );
438}
439
440QVariant QgsProcessingMeshDatasetTimeWidgetWrapper::widgetValue() const
441{
442 if ( mWidget )
443 return mWidget->value();
444 return QVariant();
445}
446
447QgsProcessingMeshDatasetTimeWidget::QgsProcessingMeshDatasetTimeWidget( QWidget *parent, const QgsProcessingParameterMeshDatasetTime *param, const QgsProcessingParameterWidgetContext &context )
448 : QWidget( parent ), mParam( param )
449{
450 setupUi( this );
451
452 mValue.insert( u"type"_s, u"static"_s );
453
454 dateTimeEdit->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
455
456 mCanvas = context.mapCanvas();
457
458 connect( radioButtonCurrentCanvasTime, &QRadioButton::toggled, this, [this]( bool isChecked ) {if ( isChecked ) this->updateValue(); } );
459 connect( radioButtonDefinedDateTime, &QRadioButton::toggled, this, [this]( bool isChecked ) {if ( isChecked ) this->updateValue(); } );
460 connect( radioButtonDatasetGroupTimeStep, &QRadioButton::toggled, this, [this]( bool isChecked ) {if ( isChecked ) this->updateValue(); } );
461 connect( dateTimeEdit, &QgsDateTimeEdit::dateTimeChanged, this, &QgsProcessingMeshDatasetTimeWidget::updateValue );
462 connect( comboBoxDatasetTimeStep, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsProcessingMeshDatasetTimeWidget::updateValue );
463
464 updateWidget();
465}
466
467void QgsProcessingMeshDatasetTimeWidget::setMeshLayer( QgsMeshLayer *layer, bool layerFromProject )
468{
469 if ( mMeshLayer == layer )
470 return;
471
472 mReferenceTime = QDateTime();
473
474 if ( layerFromProject )
475 {
476 mMeshLayer = layer;
477 mReferenceTime = static_cast<QgsMeshLayerTemporalProperties *>( layer->temporalProperties() )->referenceTime();
478 }
479 else
480 {
481 mMeshLayer = nullptr;
482 if ( layer )
483 mReferenceTime = layer->dataProvider()->temporalCapabilities()->referenceTime();
484 storeTimeStepsFromLayer( layer );
485 }
486
487 if ( mReferenceTime.isValid() )
488 whileBlocking( dateTimeEdit )->setDateTime( mReferenceTime );
489
490 updateValue();
491}
492
493void QgsProcessingMeshDatasetTimeWidget::setDatasetGroupIndexes( const QList<int> datasetGroupIndexes )
494{
495 if ( datasetGroupIndexes == mDatasetGroupIndexes )
496 return;
497 mDatasetGroupIndexes = datasetGroupIndexes;
498 populateTimeSteps();
499 updateValue();
500}
501
502void QgsProcessingMeshDatasetTimeWidget::setValue( const QVariant &value )
503{
504 if ( !value.isValid() || ( value.userType() != QMetaType::Type::QVariantMap && !value.toDateTime().isValid() ) )
505 return;
506
507 mValue.clear();
508 if ( value.toDateTime().isValid() )
509 {
510 QDateTime dateTime = value.toDateTime();
511 dateTime.setTimeSpec( Qt::UTC );
512 mValue.insert( u"type"_s, u"defined-date-time"_s );
513 mValue.insert( u"value"_s, dateTime );
514 }
515 else
516 mValue = value.toMap();
517
518 if ( !mValue.contains( u"type"_s ) || !mValue.contains( u"value"_s ) )
519 return;
520
521 QString type = mValue.value( u"type"_s ).toString();
522
523 setEnabled( true );
524 if ( type == "static"_L1 )
525 {
526 setEnabled( false );
527 }
528 else if ( type == "dataset-time-step"_L1 )
529 {
530 QVariantList dataset = mValue.value( u"value"_s ).toList();
531 whileBlocking( comboBoxDatasetTimeStep )->setCurrentIndex( comboBoxDatasetTimeStep->findData( dataset ) );
532 whileBlocking( radioButtonDatasetGroupTimeStep )->setChecked( true );
533 }
534 else if ( type == "defined-date-time"_L1 )
535 {
536 whileBlocking( dateTimeEdit )->setDateTime( mValue.value( u"value"_s ).toDateTime() );
537 whileBlocking( radioButtonDefinedDateTime )->setChecked( true );
538 }
539 else if ( type == "current-context-time"_L1 )
540 {
541 whileBlocking( radioButtonCurrentCanvasTime )->setChecked( true );
542 }
543
544 emit changed();
545 updateWidget();
546}
547
548QVariant QgsProcessingMeshDatasetTimeWidget::value() const
549{
550 return mValue;
551}
552
553void QgsProcessingMeshDatasetTimeWidget::updateWidget()
554{
555 bool isStatic = !hasTemporalDataset();
556 setEnabled( !isStatic );
557
558 if ( mCanvas && mCanvas->mapSettings().isTemporal() )
559 {
560 whileBlocking( radioButtonCurrentCanvasTime )->setEnabled( true && mReferenceTime.isValid() );
561 labelCurrentCanvasTime->setText( mCanvas->mapSettings().temporalRange().begin().toString( "yyyy-MM-dd HH:mm:ss" ) );
562 }
563 else
564 {
565 whileBlocking( radioButtonCurrentCanvasTime )->setEnabled( false );
566 if ( radioButtonCurrentCanvasTime->isChecked() )
567 whileBlocking( radioButtonDefinedDateTime )->setChecked( true );
568 }
569
570 if ( !mReferenceTime.isValid() )
571 whileBlocking( radioButtonDatasetGroupTimeStep )->setChecked( true );
572
573 whileBlocking( radioButtonDefinedDateTime )->setEnabled( mReferenceTime.isValid() );
574
575 dateTimeEdit->setVisible( radioButtonDefinedDateTime->isChecked() && !isStatic );
576 labelCurrentCanvasTime->setVisible( radioButtonCurrentCanvasTime->isChecked() && !isStatic );
577 comboBoxDatasetTimeStep->setVisible( radioButtonDatasetGroupTimeStep->isChecked() && !isStatic );
578}
579
580bool QgsProcessingMeshDatasetTimeWidget::hasTemporalDataset() const
581{
582 for ( int index : mDatasetGroupIndexes )
583 {
584 if ( mMeshLayer && mMeshLayer->datasetGroupMetadata( index ).isTemporal() )
585 return true;
586 else if ( mDatasetTimeSteps.contains( index ) )
587 return true;
588 }
589
590 return false;
591}
592
593
594void QgsProcessingMeshDatasetTimeWidget::populateTimeSteps()
595{
596 if ( mMeshLayer )
597 {
598 populateTimeStepsFromLayer();
599 return;
600 }
601
602 QMap<quint64, QgsMeshDatasetIndex> timeStep;
603 for ( int groupIndex : mDatasetGroupIndexes )
604 {
605 if ( !mDatasetTimeSteps.contains( groupIndex ) )
606 continue;
607 const QList<qint64> relativeTimeSteps = mDatasetTimeSteps.value( groupIndex );
608 for ( int index = 0; index < relativeTimeSteps.count(); ++index )
609 {
610 QgsMeshDatasetIndex datasetIndex( groupIndex, index );
611 if ( timeStep.contains( relativeTimeSteps.at( index ) ) )
612 continue;
613 timeStep[relativeTimeSteps.at( index )] = datasetIndex;
614 }
615 }
616
617 for ( auto it = timeStep.constBegin(); it != timeStep.constEnd(); it++ )
618 {
619 QString stringTime = QgsMeshLayerUtils::formatTime( static_cast<double>( it.key() ) / 1000. / 3600., mReferenceTime, QgsMeshTimeSettings() );
620 QVariantList data;
621 const QgsMeshDatasetIndex &index = it.value();
622 data << index.group() << index.dataset();
623 whileBlocking( comboBoxDatasetTimeStep )->addItem( stringTime, data );
624 }
625}
626
627void QgsProcessingMeshDatasetTimeWidget::populateTimeStepsFromLayer()
628{
629 whileBlocking( comboBoxDatasetTimeStep )->clear();
630
631 if ( !mMeshLayer )
632 return;
633
634 QMap<quint64, QgsMeshDatasetIndex> timeStep;
635 for ( int groupIndex : std::as_const( mDatasetGroupIndexes ) )
636 {
637 QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( groupIndex );
638 if ( !meta.isTemporal() )
639 continue;
640 int datasetCount = mMeshLayer->datasetCount( groupIndex );
641
642 for ( int index = 0; index < datasetCount; ++index )
643 {
644 QgsMeshDatasetIndex datasetIndex( groupIndex, index );
645 qint64 relativeTime = mMeshLayer->datasetRelativeTimeInMilliseconds( datasetIndex );
646 if ( timeStep.contains( relativeTime ) )
647 continue;
648 timeStep[relativeTime] = datasetIndex;
649 }
650 }
651
652 for ( auto it = timeStep.constBegin(); it != timeStep.constEnd(); it++ )
653 {
654 QString stringTime = mMeshLayer->formatTime( static_cast<double>( it.key() ) / 1000.0 / 3600.0 );
655 QVariantList data;
656 const QgsMeshDatasetIndex &index = it.value();
657 data << index.group() << index.dataset();
658 whileBlocking( comboBoxDatasetTimeStep )->addItem( stringTime, data );
659 }
660}
661
662void QgsProcessingMeshDatasetTimeWidget::storeTimeStepsFromLayer( QgsMeshLayer *layer )
663{
664 mDatasetTimeSteps.clear();
665 if ( !layer )
666 return;
667 QList<int> datasetGroupsList = layer->datasetGroupsIndexes();
668 for ( int groupIndex : datasetGroupsList )
669 {
670 QgsMeshDatasetGroupMetadata meta = layer->datasetGroupMetadata( groupIndex );
671 if ( !meta.isTemporal() )
672 continue;
673 int datasetCount = layer->datasetCount( groupIndex );
674 QList<qint64> relativeTimeSteps;
675 relativeTimeSteps.reserve( datasetCount );
676 for ( int index = 0; index < datasetCount; ++index )
677 relativeTimeSteps.append( layer->datasetRelativeTimeInMilliseconds( QgsMeshDatasetIndex( groupIndex, index ) ) );
678 mDatasetTimeSteps[groupIndex] = relativeTimeSteps;
679 }
680}
681
682void QgsProcessingMeshDatasetTimeWidget::buildValue()
683{
684 mValue.clear();
685
686 if ( !isEnabled() )
687 {
688 mValue[u"type"_s] = u"static"_s;
689 }
690 else if ( radioButtonDatasetGroupTimeStep->isChecked() )
691 {
692 mValue[u"type"_s] = u"dataset-time-step"_s;
693 mValue[u"value"_s] = comboBoxDatasetTimeStep->currentData();
694 }
695 else if ( radioButtonDefinedDateTime->isChecked() )
696 {
697 mValue[u"type"_s] = u"defined-date-time"_s;
698 mValue[u"value"_s] = dateTimeEdit->dateTime();
699 }
700 else if ( radioButtonCurrentCanvasTime->isChecked() && mCanvas )
701 {
702 mValue[u"type"_s] = u"current-context-time"_s;
703 }
704
705 emit changed();
706}
707
708void QgsProcessingMeshDatasetTimeWidget::updateValue()
709{
710 updateWidget();
711 buildValue();
712}
713
714
715QgsProcessingMeshDatasetGroupsParameterDefinitionWidget::QgsProcessingMeshDatasetGroupsParameterDefinitionWidget(
716 QgsProcessingContext &context,
717 const QgsProcessingParameterWidgetContext &widgetContext,
718 const QgsProcessingParameterDefinition *definition,
720 QWidget *parent
721)
722 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
723{
724 QVBoxLayout *vlayout = new QVBoxLayout();
725 vlayout->setContentsMargins( 0, 0, 0, 0 );
726
727 vlayout->addWidget( new QLabel( tr( "Linked input" ) ) );
728
729 mParentLayerComboBox = new QComboBox();
730 vlayout->addWidget( mParentLayerComboBox );
731
732 if ( QgsProcessingModelAlgorithm *model = widgetContext.model() )
733 {
734 const QMap<QString, QgsProcessingModelParameter> components = model->parameterComponents();
735 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
736 {
737 const QgsProcessingParameterDefinition *def = model->parameterDefinition( it.value().parameterName() );
738 if ( def && def->type() == QgsProcessingParameterMeshLayer::typeName() )
739 {
740 mParentLayerComboBox->addItem( def->description(), def->name() );
741 }
742 }
743 }
744
745 const QgsProcessingParameterMeshDatasetGroups *datasetGroupDef = static_cast<const QgsProcessingParameterMeshDatasetGroups *>( definition );
746 if ( datasetGroupDef )
747 {
748 int currentIndex = mParentLayerComboBox->findData( datasetGroupDef->meshLayerParameterName() );
749 if ( currentIndex != -1 )
750 mParentLayerComboBox->setCurrentIndex( currentIndex );
751 else if ( !datasetGroupDef->meshLayerParameterName().isEmpty() )
752 {
753 // if no layer parameter candidates found, we just add the existing one as a placeholder
754 mParentLayerComboBox->addItem( datasetGroupDef->meshLayerParameterName(), datasetGroupDef->meshLayerParameterName() );
755 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
756 }
757 }
758
759 setLayout( vlayout );
760}
761
762QgsProcessingParameterDefinition *QgsProcessingMeshDatasetGroupsParameterDefinitionWidget::createParameter(
763 const QString &name,
764 const QString &description,
766) const
767{
768 QSet<int> supportedDataType;
769 supportedDataType.insert( QgsMeshDatasetGroupMetadata::DataOnEdges );
770 supportedDataType.insert( QgsMeshDatasetGroupMetadata::DataOnVertices );
771 supportedDataType.insert( QgsMeshDatasetGroupMetadata::DataOnFaces );
772 supportedDataType.insert( QgsMeshDatasetGroupMetadata::DataOnVolumes );
773 auto param = std::make_unique<QgsProcessingParameterMeshDatasetGroups>( name, description, mParentLayerComboBox->currentData().toString(), supportedDataType );
774 param->setFlags( flags );
775 return param.release();
776}
777
778QgsProcessingMeshDatasetTimeParameterDefinitionWidget::QgsProcessingMeshDatasetTimeParameterDefinitionWidget(
779 QgsProcessingContext &context,
780 const QgsProcessingParameterWidgetContext &widgetContext,
781 const QgsProcessingParameterDefinition *definition,
783 QWidget *parent
784)
785 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
786{
787 if ( definition )
788 {
789 const QgsProcessingParameterMeshDatasetTime *datasetTimeDef = static_cast<const QgsProcessingParameterMeshDatasetTime *>( definition );
790 mMeshLayerParameterName = datasetTimeDef->meshLayerParameterName();
791 }
792
793 QVBoxLayout *vlayout = new QVBoxLayout();
794 vlayout->setContentsMargins( 0, 0, 0, 0 );
795
796 vlayout->addWidget( new QLabel( tr( "Linked input" ) ) );
797
798 mParentDatasetComboBox = new QComboBox();
799 vlayout->addWidget( mParentDatasetComboBox );
800
801 QgsProcessingModelAlgorithm *model = widgetContext.model();
802 if ( model )
803 {
804 const QMap<QString, QgsProcessingModelParameter> components = model->parameterComponents();
805 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
806 {
807 const QgsProcessingParameterDefinition *def = model->parameterDefinition( it.value().parameterName() );
809 mParentDatasetComboBox->addItem( def->description(), def->name() );
810 }
811 }
812
813 if ( definition )
814 {
815 const QgsProcessingParameterMeshDatasetTime *datasetTimeDef = static_cast<const QgsProcessingParameterMeshDatasetTime *>( definition );
816 int currentIndex = mParentDatasetComboBox->findData( datasetTimeDef->datasetGroupParameterName() );
817 if ( currentIndex != -1 )
818 mParentDatasetComboBox->setCurrentIndex( currentIndex );
819 else if ( !datasetTimeDef->meshLayerParameterName().isEmpty() )
820 {
821 // if no layer parameter candidates found, we just add the existing one as a placeholder
822 mParentDatasetComboBox->addItem( datasetTimeDef->datasetGroupParameterName(), datasetTimeDef->datasetGroupParameterName() );
823 mParentDatasetComboBox->setCurrentIndex( mParentDatasetComboBox->count() - 1 );
824 }
825 }
826
827 if ( model )
828 {
829 const QgsProcessingParameterDefinition *currentDef = model->parameterDefinition( mParentDatasetComboBox->currentData().toString() );
830 if ( currentDef )
831 mMeshLayerParameterName = static_cast<const QgsProcessingParameterMeshDatasetGroups *>( currentDef )->meshLayerParameterName();
832
833 connect( mParentDatasetComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this, model] {
834 const QgsProcessingParameterDefinition *currentDef = model->parameterDefinition( mParentDatasetComboBox->currentData().toString() );
835 if ( currentDef )
836 mMeshLayerParameterName = static_cast<const QgsProcessingParameterMeshDatasetGroups *>( currentDef )->meshLayerParameterName();
837 } );
838 }
839
840 setLayout( vlayout );
841}
842
843QgsProcessingParameterDefinition *QgsProcessingMeshDatasetTimeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
844{
845 auto param = std::make_unique<QgsProcessingParameterMeshDatasetTime>(
846 name, description, mMeshLayerParameterName, mParentDatasetComboBox->currentData().toString()
847 );
848
849 param->setFlags( flags );
850 return param.release();
851}
852
ProcessingMode
Types of modes which Processing widgets can be created for.
Definition qgis.h:3742
@ Batch
Batch processing mode.
Definition qgis.h:3744
@ Modeler
Modeler mode.
Definition qgis.h:3745
@ Standard
Standard (single-run) algorithm mode.
Definition qgis.h:3743
QFlags< ProcessingParameterFlag > ProcessingParameterFlags
Flags which dictate the behavior of Processing parameters.
Definition qgis.h:3848
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.
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.
A collection of dataset group metadata such as whether the data is vector or scalar,...
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.
An 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.
QDateTime referenceTime() const
Returns the reference time.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
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 an 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 ...
bool dockMode() const
Returns the dock mode state.
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.
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.
Base class for the definition of processing parameters.
void setFlags(Qgis::ProcessingParameterFlags flags)
Sets the flags associated with the parameter.
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.
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:6839
#define SIP_FACTORY
Definition qgis_sip.h:84