QGIS API Documentation 3.41.0-Master (af5edcb665c)
Loading...
Searching...
No Matches
qgsprocessingmultipleselectiondialog.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingmultipleselectiondialog.cpp
3 ------------------------------------
4 Date : February 2019
5 Copyright : (C) 2019 Nyall Dawson
6 Email : nyall dot dawson 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 "moc_qgsprocessingmultipleselectiondialog.cpp"
18#include "qgsgui.h"
19#include "qgssettings.h"
20#include "qgsfileutils.h"
21#include "qgsvectorlayer.h"
22#include "qgsmeshlayer.h"
23#include "qgsrasterlayer.h"
24#include "qgspluginlayer.h"
25#include "qgspointcloudlayer.h"
26#include "qgsannotationlayer.h"
27#include "qgsvectortilelayer.h"
28#include "qgsproject.h"
30#include <QStandardItemModel>
31#include <QStandardItem>
32#include <QPushButton>
33#include <QLineEdit>
34#include <QToolButton>
35#include <QFileDialog>
36#include <QDirIterator>
37#include "qgsmimedatautils.h"
38#include <QDragEnterEvent>
39
41
42QgsProcessingMultipleSelectionPanelWidget::QgsProcessingMultipleSelectionPanelWidget( const QVariantList &availableOptions, const QVariantList &selectedOptions, QWidget *parent )
43 : QgsPanelWidget( parent )
44 , mValueFormatter( []( const QVariant &v ) -> QString {
45 if ( v.userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>() )
46 return v.value<QgsProcessingModelChildParameterSource>().staticValue().toString();
47 else
48 return v.toString();
49 } )
50{
51 setupUi( this );
52
54
55 mSelectionList->setSelectionBehavior( QAbstractItemView::SelectRows );
56 mSelectionList->setSelectionMode( QAbstractItemView::ExtendedSelection );
57 mSelectionList->setDragDropMode( QAbstractItemView::InternalMove );
58
59 mButtonSelectAll = new QPushButton( tr( "Select All" ) );
60 mButtonBox->addButton( mButtonSelectAll, QDialogButtonBox::ActionRole );
61
62 mButtonClearSelection = new QPushButton( tr( "Clear Selection" ) );
63 mButtonBox->addButton( mButtonClearSelection, QDialogButtonBox::ActionRole );
64
65 mButtonToggleSelection = new QPushButton( tr( "Toggle Selection" ) );
66 mButtonBox->addButton( mButtonToggleSelection, QDialogButtonBox::ActionRole );
67
68 connect( mButtonSelectAll, &QPushButton::clicked, this, [=] { selectAll( true ); } );
69 connect( mButtonClearSelection, &QPushButton::clicked, this, [=] { selectAll( false ); } );
70 connect( mButtonToggleSelection, &QPushButton::clicked, this, &QgsProcessingMultipleSelectionPanelWidget::toggleSelection );
71
72 connect( mButtonBox, &QDialogButtonBox::accepted, this, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked );
73 populateList( availableOptions, selectedOptions );
74
75 connect( mModel, &QStandardItemModel::itemChanged, this, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged );
76
77 // When user moves an item, a new item is created and another one is removed, so we need to fire selectionChanged
78 // see https://github.com/qgis/QGIS/issues/44270
79 connect( mModel, &QStandardItemModel::rowsRemoved, this, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged );
80}
81
82void QgsProcessingMultipleSelectionPanelWidget::setValueFormatter( const std::function<QString( const QVariant & )> &formatter )
83{
84 mValueFormatter = formatter;
85 // update item text using new formatter
86 for ( int i = 0; i < mModel->rowCount(); ++i )
87 {
88 mModel->item( i )->setText( mValueFormatter( mModel->item( i )->data( Qt::UserRole ) ) );
89 }
90}
91
92QVariantList QgsProcessingMultipleSelectionPanelWidget::selectedOptions() const
93{
94 QVariantList options;
95 options.reserve( mModel->rowCount() );
96 bool hasModelSources = false;
97 for ( int i = 0; i < mModel->rowCount(); ++i )
98 {
99 QStandardItem *item = mModel->item( i );
100 if ( !item )
101 {
102 continue;
103 }
104
105 if ( item->checkState() == Qt::Checked )
106 {
107 const QVariant option = item->data( Qt::UserRole );
108
109 if ( option.userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>() )
110 hasModelSources = true;
111
112 options << option;
113 }
114 }
115
116 if ( hasModelSources )
117 {
118 // if any selected value is a QgsProcessingModelChildParameterSource, then we need to upgrade them all
119 QVariantList originalOptions = options;
120 options.clear();
121 for ( const QVariant &option : originalOptions )
122 {
123 if ( option.userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>() )
124 options << option;
125 else
126 options << QVariant::fromValue( QgsProcessingModelChildParameterSource::fromStaticValue( option ) );
127 }
128 }
129
130 return options;
131}
132
133
134void QgsProcessingMultipleSelectionPanelWidget::selectAll( const bool checked )
135{
136 const QList<QStandardItem *> items = currentItems();
137 for ( QStandardItem *item : items )
138 {
139 item->setCheckState( checked ? Qt::Checked : Qt::Unchecked );
140 }
141}
142
143void QgsProcessingMultipleSelectionPanelWidget::toggleSelection()
144{
145 const QList<QStandardItem *> items = currentItems();
146 for ( QStandardItem *item : items )
147 {
148 item->setCheckState( item->checkState() == Qt::Unchecked ? Qt::Checked : Qt::Unchecked );
149 }
150}
151
152QList<QStandardItem *> QgsProcessingMultipleSelectionPanelWidget::currentItems()
153{
154 QList<QStandardItem *> items;
155 const QModelIndexList selection = mSelectionList->selectionModel()->selectedIndexes();
156 if ( selection.size() > 1 )
157 {
158 items.reserve( selection.size() );
159 for ( const QModelIndex &index : selection )
160 {
161 items << mModel->itemFromIndex( index );
162 }
163 }
164 else
165 {
166 items.reserve( mModel->rowCount() );
167 for ( int i = 0; i < mModel->rowCount(); ++i )
168 {
169 items << mModel->item( i );
170 }
171 }
172 return items;
173}
174
175void QgsProcessingMultipleSelectionPanelWidget::populateList( const QVariantList &availableOptions, const QVariantList &selectedOptions )
176{
177 mModel = new QStandardItemModel( this );
178
179 QVariantList remainingOptions = availableOptions;
180
181 // we add selected options first, keeping the existing order of options
182 for ( const QVariant &option : selectedOptions )
183 {
184 // if isinstance(t, QgsProcessingModelChildParameterSource):
185 // item = QStandardItem(t.staticValue())
186 // else:
187
188 addOption( option, mValueFormatter( option ), true );
189 remainingOptions.removeAll( option );
190 }
191
192 for ( const QVariant &option : std::as_const( remainingOptions ) )
193 {
194 addOption( option, mValueFormatter( option ), false );
195 }
196
197 mSelectionList->setModel( mModel );
198}
199
200QList<int> QgsProcessingMultipleSelectionPanelWidget::existingMapLayerFromMimeData( const QMimeData *data ) const
201{
203 QList<int> indexes;
204 for ( const QgsMimeDataUtils::Uri &u : uriList )
205 {
206 // is this uri from the current project?
207 if ( QgsMapLayer *layer = u.mapLayer() )
208 {
209 for ( int i = 0; i < mModel->rowCount(); ++i )
210 {
211 // try to match project layers to current layers
212 QString userRole = mModel->item( i )->data( Qt::UserRole ).toString();
213 if ( userRole == layer->id() || userRole == layer->source() )
214 {
215 indexes.append( i );
216 }
217 }
218 }
219 }
220 return indexes;
221}
222
223void QgsProcessingMultipleSelectionPanelWidget::dragEnterEvent( QDragEnterEvent *event )
224{
225 if ( !( event->possibleActions() & Qt::CopyAction ) )
226 return;
227
228 const QList<int> indexes = existingMapLayerFromMimeData( event->mimeData() );
229 if ( !indexes.isEmpty() )
230 {
231 // dragged an acceptable layer, phew
232 event->setDropAction( Qt::CopyAction );
233 event->accept();
234 }
235}
236
237void QgsProcessingMultipleSelectionPanelWidget::dropEvent( QDropEvent *event )
238{
239 if ( !( event->possibleActions() & Qt::CopyAction ) )
240 return;
241
242 const QList<int> indexes = existingMapLayerFromMimeData( event->mimeData() );
243 if ( !indexes.isEmpty() )
244 {
245 // dropped an acceptable layer, phew
246 setFocus( Qt::MouseFocusReason );
247 event->setDropAction( Qt::CopyAction );
248 event->accept();
249
250 for ( const int i : indexes )
251 {
252 mModel->item( i )->setCheckState( Qt::Checked );
253 }
254 emit selectionChanged();
255 }
256}
257
258void QgsProcessingMultipleSelectionPanelWidget::addOption( const QVariant &value, const QString &title, bool selected, bool updateExistingTitle )
259{
260 // don't add duplicate options
261 for ( int i = 0; i < mModel->rowCount(); ++i )
262 {
263 if ( mModel->item( i )->data( Qt::UserRole ) == value || ( mModel->item( i )->data( Qt::UserRole ).userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>() && value.userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>() && mModel->item( i )->data( Qt::UserRole ).value<QgsProcessingModelChildParameterSource>() == value.value<QgsProcessingModelChildParameterSource>() ) )
264 {
265 if ( updateExistingTitle )
266 mModel->item( i )->setText( title );
267 return;
268 }
269 }
270
271 std::unique_ptr<QStandardItem> item = std::make_unique<QStandardItem>( title );
272 item->setData( value, Qt::UserRole );
273 item->setCheckState( selected ? Qt::Checked : Qt::Unchecked );
274 item->setCheckable( true );
275 item->setDropEnabled( false );
276 mModel->appendRow( item.release() );
277}
278
279//
280// QgsProcessingMultipleSelectionDialog
281//
282
283
284QgsProcessingMultipleSelectionDialog::QgsProcessingMultipleSelectionDialog( const QVariantList &availableOptions, const QVariantList &selectedOptions, QWidget *parent, Qt::WindowFlags flags )
285 : QDialog( parent, flags )
286{
287 setWindowTitle( tr( "Multiple Selection" ) );
288 QVBoxLayout *vLayout = new QVBoxLayout();
289 mWidget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, selectedOptions );
290 vLayout->addWidget( mWidget );
291 mWidget->buttonBox()->addButton( QDialogButtonBox::Cancel );
292 connect( mWidget->buttonBox(), &QDialogButtonBox::accepted, this, &QDialog::accept );
293 connect( mWidget->buttonBox(), &QDialogButtonBox::rejected, this, &QDialog::reject );
294 setLayout( vLayout );
295}
296
297void QgsProcessingMultipleSelectionDialog::setValueFormatter( const std::function<QString( const QVariant & )> &formatter )
298{
299 mWidget->setValueFormatter( formatter );
300}
301
302QVariantList QgsProcessingMultipleSelectionDialog::selectedOptions() const
303{
304 return mWidget->selectedOptions();
305}
306
307
308//
309// QgsProcessingMultipleInputPanelWidget
310//
311
312QgsProcessingMultipleInputPanelWidget::QgsProcessingMultipleInputPanelWidget( const QgsProcessingParameterMultipleLayers *parameter, const QVariantList &selectedOptions, const QList<QgsProcessingModelChildParameterSource> &modelSources, QgsProcessingModelAlgorithm *model, QWidget *parent )
313 : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), selectedOptions, parent )
314 , mParameter( parameter )
315{
316 QPushButton *addFileButton = new QPushButton( tr( "Add File(s)…" ) );
317 connect( addFileButton, &QPushButton::clicked, this, &QgsProcessingMultipleInputPanelWidget::addFiles );
318 buttonBox()->addButton( addFileButton, QDialogButtonBox::ActionRole );
319
320 QPushButton *addDirButton = new QPushButton( tr( "Add Directory…" ) );
321 connect( addDirButton, &QPushButton::clicked, this, &QgsProcessingMultipleInputPanelWidget::addDirectory );
322 buttonBox()->addButton( addDirButton, QDialogButtonBox::ActionRole );
323 setAcceptDrops( true );
324 for ( const QgsProcessingModelChildParameterSource &source : modelSources )
325 {
326 addOption( QVariant::fromValue( source ), source.friendlyIdentifier( model ), false, true );
327 }
328}
329
330void QgsProcessingMultipleInputPanelWidget::setProject( QgsProject *project )
331{
332 if ( mParameter->layerType() != Qgis::ProcessingSourceType::File )
333 populateFromProject( project );
334}
335
336void QgsProcessingMultipleInputPanelWidget::addFiles()
337{
338 QgsSettings settings;
339 QString path = settings.value( QStringLiteral( "/Processing/LastInputPath" ), QDir::homePath() ).toString();
340
341 QString filter;
342 if ( const QgsFileFilterGenerator *generator = dynamic_cast<const QgsFileFilterGenerator *>( mParameter ) )
343 filter = generator->createFileFilter();
344 else
345 filter = QObject::tr( "All files (*.*)" );
346
347 const QStringList filenames = QFileDialog::getOpenFileNames( this, tr( "Select File(s)" ), path, filter );
348 if ( filenames.empty() )
349 return;
350
351 settings.setValue( QStringLiteral( "/Processing/LastInputPath" ), QFileInfo( filenames.at( 0 ) ).path() );
352
353 for ( const QString &file : filenames )
354 {
355 addOption( file, file, true );
356 }
357
358 emit selectionChanged();
359}
360
361void QgsProcessingMultipleInputPanelWidget::addDirectory()
362{
363 QgsSettings settings;
364 const QString path = settings.value( QStringLiteral( "/Processing/LastInputPath" ), QDir::homePath() ).toString();
365
366 const QString dir = QFileDialog::getExistingDirectory( this, tr( "Select Directory" ), path );
367 if ( dir.isEmpty() )
368 return;
369
370 settings.setValue( QStringLiteral( "/Processing/LastInputPath" ), dir );
371
372 QStringList nameFilters;
373 if ( const QgsFileFilterGenerator *generator = dynamic_cast<const QgsFileFilterGenerator *>( mParameter ) )
374 {
375 const QStringList extensions = QgsFileUtils::extensionsFromFilter( generator->createFileFilter() );
376 for ( const QString &extension : extensions )
377 {
378 nameFilters << QStringLiteral( "*.%1" ).arg( extension );
379 nameFilters << QStringLiteral( "*.%1" ).arg( extension.toUpper() );
380 nameFilters << QStringLiteral( "*.%1" ).arg( extension.toLower() );
381 }
382 }
383
384 QDirIterator it( dir, nameFilters, QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories );
385 while ( it.hasNext() )
386 {
387 const QString fullPath = it.next();
388 if ( fullPath.endsWith( QLatin1String( ".dbf" ), Qt::CaseInsensitive ) )
389 {
390 if ( QFileInfo::exists( QStringLiteral( "%1.shp" ).arg( fullPath.chopped( 4 ) ) ) || QFileInfo::exists( QStringLiteral( "%1.SHP" ).arg( fullPath.chopped( 4 ) ) ) )
391 {
392 // Skip DBFs that are sidecar files to a Shapefile
393 continue;
394 }
395 }
396 else if ( fullPath.endsWith( QLatin1String( ".aux.xml" ), Qt::CaseInsensitive ) || fullPath.endsWith( QLatin1String( ".shp.xml" ), Qt::CaseInsensitive ) )
397 {
398 // Skip XMLs that are sidecar files to datasets
399 continue;
400 }
401 addOption( fullPath, fullPath, true );
402 }
403 emit selectionChanged();
404}
405
406QList<int> QgsProcessingMultipleInputPanelWidget::existingMapLayerFromMimeData( const QMimeData *data, QgsMimeDataUtils::UriList &handledUrls ) const
407{
408 handledUrls.clear();
410 QList<int> indexes;
411 for ( const QgsMimeDataUtils::Uri &u : uriList )
412 {
413 // is this uri from the current project?
414 bool matched = false;
415 if ( QgsMapLayer *layer = u.mapLayer() )
416 {
417 for ( int i = 0; i < mModel->rowCount(); ++i )
418 {
419 // try to match project layers to current layers
420 const QString userRole = mModel->item( i )->data( Qt::UserRole ).toString();
421 if ( userRole == layer->id() || userRole == layer->source() )
422 {
423 indexes.append( i );
424 matched = true;
425 }
426 }
427 }
428
429 if ( matched )
430 {
431 handledUrls.append( u );
432 }
433 }
434 return indexes;
435}
436
437
438QStringList QgsProcessingMultipleInputPanelWidget::compatibleUrisFromMimeData( const QgsProcessingParameterMultipleLayers *parameter, const QMimeData *data, const QgsMimeDataUtils::UriList &skipUrls )
439{
440 QStringList skipUrlData;
441 skipUrlData.reserve( skipUrls.size() );
442 for ( const QgsMimeDataUtils::Uri &u : skipUrls )
443 {
444 skipUrlData.append( u.data() );
445 }
446
447 QStringList res;
448
450 for ( const QgsMimeDataUtils::Uri &u : uriList )
451 {
452 if ( skipUrlData.contains( u.data() ) )
453 continue;
454
455 // clang analyzer is not happy because of the multiple duplicate return branches, but it makes the code more readable
456 // NOLINTBEGIN(bugprone-branch-clone)
463 && u.layerType == QLatin1String( "vector" ) )
464 {
465 bool acceptable = false;
466 switch ( QgsWkbTypes::geometryType( u.wkbType ) )
467 {
469 acceptable = true;
470 break;
471
474 acceptable = true;
475 break;
476
479 acceptable = true;
480 break;
481
484 acceptable = true;
485 break;
486
489 acceptable = true;
490 break;
491 }
492 if ( acceptable )
493 res.append( u.providerKey != QLatin1String( "ogr" ) ? QgsProcessingUtils::encodeProviderKeyAndUri( u.providerKey, u.uri ) : u.uri );
494 }
496 && u.layerType == QLatin1String( "raster" ) && u.providerKey == QLatin1String( "gdal" ) )
497 res.append( u.uri );
499 && u.layerType == QLatin1String( "mesh" ) && u.providerKey == QLatin1String( "mdal" ) )
500 res.append( u.uri );
502 && u.layerType == QLatin1String( "pointcloud" ) )
503 res.append( u.uri );
505 && u.layerType == QLatin1String( "vector-tile" ) )
506 res.append( u.uri );
507 // NOLINTEND(bugprone-branch-clone)
508 }
509 if ( !uriList.isEmpty() )
510 return res;
511
512 // second chance -- files dragged from file explorer, outside of QGIS
513 QStringList rawPaths;
514 if ( data->hasUrls() )
515 {
516 const QList<QUrl> urls = data->urls();
517 rawPaths.reserve( urls.count() );
518 for ( const QUrl &url : urls )
519 {
520 const QString local = url.toLocalFile();
521 if ( !rawPaths.contains( local ) )
522 rawPaths.append( local );
523 }
524 }
525 if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
526 rawPaths.append( data->text() );
527
528 for ( const QString &path : std::as_const( rawPaths ) )
529 {
530 QFileInfo file( path );
531 if ( file.isFile() )
532 {
533 // TODO - we should check to see if it's a valid extension for the parameter, but that's non-trivial
534 res.append( path );
535 }
536 }
537
538 return res;
539}
540
541void QgsProcessingMultipleInputPanelWidget::dragEnterEvent( QDragEnterEvent *event )
542{
543 if ( !( event->possibleActions() & Qt::CopyAction ) )
544 return;
545
546 // maybe dragging layers from the project
547 QgsMimeDataUtils::UriList handledUris;
548 const QList<int> indexes = existingMapLayerFromMimeData( event->mimeData(), handledUris );
549 if ( !indexes.isEmpty() )
550 {
551 // dragged an acceptable layer, phew
552 event->setDropAction( Qt::CopyAction );
553 event->accept();
554 return;
555 }
556
557 // maybe dragging layers from browser or file explorer
558 const QStringList uris = compatibleUrisFromMimeData( mParameter, event->mimeData(), handledUris );
559 if ( !uris.isEmpty() )
560 {
561 // dragged an acceptable layer, phew
562 event->setDropAction( Qt::CopyAction );
563 event->accept();
564 }
565}
566
567void QgsProcessingMultipleInputPanelWidget::dropEvent( QDropEvent *event )
568{
569 if ( !( event->possibleActions() & Qt::CopyAction ) )
570 return;
571
572 QgsMimeDataUtils::UriList handledUris;
573 const QList<int> indexes = existingMapLayerFromMimeData( event->mimeData(), handledUris );
574 if ( !indexes.isEmpty() )
575 {
576 // dropped an acceptable layer, phew
577 setFocus( Qt::MouseFocusReason );
578 event->setDropAction( Qt::CopyAction );
579 event->accept();
580
581 for ( const int i : indexes )
582 {
583 mModel->item( i )->setCheckState( Qt::Checked );
584 }
585 emit selectionChanged();
586 }
587
588 // maybe dragging layers from browser or file explorer
589 const QStringList uris = compatibleUrisFromMimeData( mParameter, event->mimeData(), handledUris );
590 if ( !uris.isEmpty() )
591 {
592 for ( const QString &uri : uris )
593 {
594 addOption( uri, uri, true );
595 }
596 emit selectionChanged();
597 }
598}
599
600void QgsProcessingMultipleInputPanelWidget::populateFromProject( QgsProject *project )
601{
602 connect( project, &QgsProject::layerRemoved, this, [&]( const QString &layerId ) {
603 for ( int i = 0; i < mModel->rowCount(); ++i )
604 {
605 const QStandardItem *item = mModel->item( i );
606 if ( item->data( Qt::UserRole ) == layerId )
607 {
608 bool isChecked = ( item->checkState() == Qt::Checked );
609 mModel->removeRow( i );
610
611 if ( isChecked )
612 emit selectionChanged();
613
614 break;
615 }
616 }
617 } );
618
619 QgsSettings settings;
620 auto addLayer = [&]( const QgsMapLayer *layer ) {
621 const QString authid = layer->crs().authid();
622 QString title;
623 if ( settings.value( QStringLiteral( "Processing/Configuration/SHOW_CRS_DEF" ), true ).toBool() && !authid.isEmpty() )
624 title = QStringLiteral( "%1 [%2]" ).arg( layer->name(), authid );
625 else
626 title = layer->name();
627
628
629 QString id = layer->id();
630 if ( layer == project->mainAnnotationLayer() )
631 id = QStringLiteral( "main" );
632
633 for ( int i = 0; i < mModel->rowCount(); ++i )
634 {
635 // try to match project layers to current layers
636 if ( mModel->item( i )->data( Qt::UserRole ) == layer->id() )
637 {
638 id = layer->id();
639 break;
640 }
641 else if ( mModel->item( i )->data( Qt::UserRole ) == layer->source() )
642 {
643 id = layer->source();
644 break;
645 }
646 }
647
648 addOption( id, title, false, true );
649 };
650
651 switch ( mParameter->layerType() )
652 {
654 break;
655
657 {
658 const QList<QgsRasterLayer *> options = QgsProcessingUtils::compatibleRasterLayers( project, false );
659 for ( const QgsRasterLayer *layer : options )
660 {
661 addLayer( layer );
662 }
663 break;
664 }
665
667 {
668 const QList<QgsMeshLayer *> options = QgsProcessingUtils::compatibleMeshLayers( project, false );
669 for ( const QgsMeshLayer *layer : options )
670 {
671 addLayer( layer );
672 }
673
674 break;
675 }
676
678 {
679 const QList<QgsPluginLayer *> options = QgsProcessingUtils::compatiblePluginLayers( project, false );
680 for ( const QgsPluginLayer *layer : options )
681 {
682 addLayer( layer );
683 }
684
685 break;
686 }
687
689 {
690 const QList<QgsAnnotationLayer *> options = QgsProcessingUtils::compatibleAnnotationLayers( project, false );
691 for ( const QgsAnnotationLayer *layer : options )
692 {
693 addLayer( layer );
694 }
695
696 break;
697 }
698
700 {
701 const QList<QgsPointCloudLayer *> options = QgsProcessingUtils::compatiblePointCloudLayers( project, false );
702 for ( const QgsPointCloudLayer *layer : options )
703 {
704 addLayer( layer );
705 }
706
707 break;
708 }
709
711 {
712 const QList<QgsVectorTileLayer *> options = QgsProcessingUtils::compatibleVectorTileLayers( project, false );
713 for ( const QgsVectorTileLayer *layer : options )
714 {
715 addLayer( layer );
716 }
717
718 break;
719 }
720
723 {
724 const QList<QgsVectorLayer *> options = QgsProcessingUtils::compatibleVectorLayers( project, QList<int>() << static_cast<int>( mParameter->layerType() ) );
725 for ( const QgsVectorLayer *layer : options )
726 {
727 addLayer( layer );
728 }
729
730 break;
731 }
732
734 {
735 const QList<QgsVectorLayer *> vectors = QgsProcessingUtils::compatibleVectorLayers( project, QList<int>() );
736 for ( const QgsVectorLayer *layer : vectors )
737 {
738 addLayer( layer );
739 }
740 const QList<QgsRasterLayer *> rasters = QgsProcessingUtils::compatibleRasterLayers( project );
741 for ( const QgsRasterLayer *layer : rasters )
742 {
743 addLayer( layer );
744 }
745 const QList<QgsMeshLayer *> meshes = QgsProcessingUtils::compatibleMeshLayers( project );
746 for ( const QgsMeshLayer *layer : meshes )
747 {
748 addLayer( layer );
749 }
750 const QList<QgsPluginLayer *> plugins = QgsProcessingUtils::compatiblePluginLayers( project );
751 for ( const QgsPluginLayer *layer : plugins )
752 {
753 addLayer( layer );
754 }
755 const QList<QgsPointCloudLayer *> pointClouds = QgsProcessingUtils::compatiblePointCloudLayers( project );
756 for ( const QgsPointCloudLayer *layer : pointClouds )
757 {
758 addLayer( layer );
759 }
760 const QList<QgsAnnotationLayer *> annotations = QgsProcessingUtils::compatibleAnnotationLayers( project );
761 for ( const QgsAnnotationLayer *layer : annotations )
762 {
763 addLayer( layer );
764 }
765
766 break;
767 }
768
772 {
773 const QList<QgsVectorLayer *> vectors = QgsProcessingUtils::compatibleVectorLayers( project, QList<int>() << static_cast<int>( mParameter->layerType() ) );
774 for ( const QgsVectorLayer *layer : vectors )
775 {
776 addLayer( layer );
777 }
778 break;
779 }
780 }
781}
782
783//
784// QgsProcessingMultipleInputDialog
785//
786
787QgsProcessingMultipleInputDialog::QgsProcessingMultipleInputDialog( const QgsProcessingParameterMultipleLayers *parameter, const QVariantList &selectedOptions, const QList<QgsProcessingModelChildParameterSource> &modelSources, QgsProcessingModelAlgorithm *model, QWidget *parent, Qt::WindowFlags flags )
788 : QDialog( parent, flags )
789{
790 setWindowTitle( tr( "Multiple Selection" ) );
791 QVBoxLayout *vLayout = new QVBoxLayout();
792 mWidget = new QgsProcessingMultipleInputPanelWidget( parameter, selectedOptions, modelSources, model );
793 vLayout->addWidget( mWidget );
794 mWidget->buttonBox()->addButton( QDialogButtonBox::Cancel );
795 connect( mWidget->buttonBox(), &QDialogButtonBox::accepted, this, &QDialog::accept );
796 connect( mWidget->buttonBox(), &QDialogButtonBox::rejected, this, &QDialog::reject );
797 setLayout( vLayout );
798 setAcceptDrops( true );
799}
800
801QVariantList QgsProcessingMultipleInputDialog::selectedOptions() const
802{
803 return mWidget->selectedOptions();
804}
805
806void QgsProcessingMultipleInputDialog::setProject( QgsProject *project )
807{
808 mWidget->setProject( project );
809}
810
811
@ File
Files (i.e. non map layer sources, such as text files)
@ Annotation
Annotation layers.
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
@ VectorTile
Vector tile layers.
@ MapLayer
Any map layer type (raster, vector, mesh, point cloud, annotation or plugin layer)
@ VectorAnyGeometry
Any vector layer with geometry.
@ VectorPoint
Vector point layers.
@ VectorPolygon
Vector polygon layers.
@ VectorLine
Vector line layers.
@ PointCloud
Point cloud layers.
@ Polygon
Polygons.
@ Unknown
Unknown types.
@ Null
No geometry.
Represents a map layer containing a set of georeferenced annotations, e.g.
Abstract interface for classes which generate a file filter string.
static QStringList extensionsFromFilter(const QString &filter)
Returns a list of the extensions contained within a file filter string.
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition qgsgui.cpp:210
Base class for all map layer types.
Definition qgsmaplayer.h:76
Represents a mesh layer supporting display of data on structured or unstructured meshes.
QList< QgsMimeDataUtils::Uri > UriList
static UriList decodeUriList(const QMimeData *data)
Base class for any widget that can be shown as a inline panel.
Base class for plugin layers.
Represents a map layer supporting display of point clouds.
A parameter for processing algorithms which accepts multiple map layers.
Qgis::ProcessingSourceType layerType() const
Returns the layer type for layers acceptable by the parameter.
static QList< QgsAnnotationLayer * > compatibleAnnotationLayers(QgsProject *project, bool sort=true)
Returns a list of annotation layers from a project which are compatible with the processing framework...
static QString encodeProviderKeyAndUri(const QString &providerKey, const QString &uri)
Encodes a provider key and layer uri to a single string, for use with decodeProviderKeyAndUri()
static QList< QgsRasterLayer * > compatibleRasterLayers(QgsProject *project, bool sort=true)
Returns a list of raster layers from a project which are compatible with the processing framework.
static QList< QgsPluginLayer * > compatiblePluginLayers(QgsProject *project, bool sort=true)
Returns a list of plugin layers from a project which are compatible with the processing framework.
static QList< QgsVectorLayer * > compatibleVectorLayers(QgsProject *project, const QList< int > &sourceTypes=QList< int >(), bool sort=true)
Returns a list of vector layers from a project which are compatible with the processing framework.
static QList< QgsVectorTileLayer * > compatibleVectorTileLayers(QgsProject *project, bool sort=true)
Returns a list of vector tile layers from a project which are compatible with the processing framewor...
static QList< QgsPointCloudLayer * > compatiblePointCloudLayers(QgsProject *project, bool sort=true)
Returns a list of point cloud layers from a project which are compatible with the processing framewor...
static QList< QgsMeshLayer * > compatibleMeshLayers(QgsProject *project, bool sort=true)
Returns a list of mesh layers from a project which are compatible with the processing framework.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:107
QgsAnnotationLayer * mainAnnotationLayer()
Returns the main annotation layer associated with the project.
void layerRemoved(const QString &layerId)
Emitted after a layer was removed from the registry.
Represents a raster layer.
This class is a composition of two QSettings instances:
Definition qgssettings.h:64
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Represents a vector layer which manages a vector based data sets.
Implements a map layer that is dedicated to rendering of vector tiles.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...