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