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