18 #include "qgssettings.h"
24 #include "processing/models/qgsprocessingmodelchildparametersource.h"
25 #include <QStandardItemModel>
26 #include <QStandardItem>
27 #include <QPushButton>
29 #include <QToolButton>
30 #include <QFileDialog>
31 #include <QDirIterator>
35 QgsProcessingMultipleSelectionPanelWidget::QgsProcessingMultipleSelectionPanelWidget(
const QVariantList &availableOptions,
36 const QVariantList &selectedOptions,
39 , mValueFormatter( []( const QVariant & v )->QString
41 if ( v.canConvert< QgsProcessingModelChildParameterSource >() )
42 return v.value< QgsProcessingModelChildParameterSource >().staticValue().toString();
51 mSelectionList->setSelectionBehavior( QAbstractItemView::SelectRows );
52 mSelectionList->setSelectionMode( QAbstractItemView::ExtendedSelection );
53 mSelectionList->setDragDropMode( QAbstractItemView::InternalMove );
55 mButtonSelectAll =
new QPushButton( tr(
"Select All" ) );
56 mButtonBox->addButton( mButtonSelectAll, QDialogButtonBox::ActionRole );
58 mButtonClearSelection =
new QPushButton( tr(
"Clear Selection" ) );
59 mButtonBox->addButton( mButtonClearSelection, QDialogButtonBox::ActionRole );
61 mButtonToggleSelection =
new QPushButton( tr(
"Toggle Selection" ) );
62 mButtonBox->addButton( mButtonToggleSelection, QDialogButtonBox::ActionRole );
64 connect( mButtonSelectAll, &QPushButton::clicked,
this, [ = ] { selectAll(
true ); } );
65 connect( mButtonClearSelection, &QPushButton::clicked,
this, [ = ] { selectAll(
false ); } );
66 connect( mButtonToggleSelection, &QPushButton::clicked,
this, &QgsProcessingMultipleSelectionPanelWidget::toggleSelection );
68 connect( mButtonBox, &QDialogButtonBox::accepted,
this, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked );
69 populateList( availableOptions, selectedOptions );
71 connect( mModel, &QStandardItemModel::itemChanged,
this, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged );
74 void QgsProcessingMultipleSelectionPanelWidget::setValueFormatter(
const std::function<QString(
const QVariant & )> &
formatter )
78 for (
int i = 0; i < mModel->rowCount(); ++i )
80 mModel->item( i )->setText( mValueFormatter( mModel->item( i )->data( Qt::UserRole ) ) );
84 QVariantList QgsProcessingMultipleSelectionPanelWidget::selectedOptions()
const
87 options.reserve( mModel->rowCount() );
88 bool hasModelSources =
false;
89 for (
int i = 0; i < mModel->rowCount(); ++i )
91 if ( mModel->item( i )->checkState() == Qt::Checked )
93 const QVariant option = mModel->item( i )->data( Qt::UserRole );
95 if ( option.canConvert< QgsProcessingModelChildParameterSource >() )
96 hasModelSources =
true;
102 if ( hasModelSources )
105 QVariantList originalOptions = options;
107 for (
const QVariant &option : originalOptions )
109 if ( option.canConvert< QgsProcessingModelChildParameterSource >() )
112 options << QVariant::fromValue( QgsProcessingModelChildParameterSource::fromStaticValue( option ) );
120 void QgsProcessingMultipleSelectionPanelWidget::selectAll(
const bool checked )
122 const QList<QStandardItem *> items = currentItems();
123 for ( QStandardItem *item : items )
125 item->setCheckState( checked ? Qt::Checked : Qt::Unchecked );
129 void QgsProcessingMultipleSelectionPanelWidget::toggleSelection()
131 const QList<QStandardItem *> items = currentItems();
132 for ( QStandardItem *item : items )
134 item->setCheckState( item->checkState() == Qt::Unchecked ? Qt::Checked : Qt::Unchecked );
138 QList<QStandardItem *> QgsProcessingMultipleSelectionPanelWidget::currentItems()
140 QList<QStandardItem *> items;
141 const QModelIndexList selection = mSelectionList->selectionModel()->selectedIndexes();
142 if ( selection.size() > 1 )
144 items.reserve( selection.size() );
145 for (
const QModelIndex &index : selection )
147 items << mModel->itemFromIndex( index );
152 items.reserve( mModel->rowCount() );
153 for (
int i = 0; i < mModel->rowCount(); ++i )
155 items << mModel->item( i );
161 void QgsProcessingMultipleSelectionPanelWidget::populateList(
const QVariantList &availableOptions,
const QVariantList &selectedOptions )
163 mModel =
new QStandardItemModel(
this );
165 QVariantList remainingOptions = availableOptions;
168 for (
const QVariant &option : selectedOptions )
174 addOption( option, mValueFormatter( option ),
true );
175 remainingOptions.removeAll( option );
178 for (
const QVariant &option : std::as_const( remainingOptions ) )
180 addOption( option, mValueFormatter( option ),
false );
183 mSelectionList->setModel( mModel );
187 void QgsProcessingMultipleSelectionPanelWidget::addOption(
const QVariant &value,
const QString &title,
bool selected,
bool updateExistingTitle )
190 for (
int i = 0; i < mModel->rowCount(); ++i )
192 if ( mModel->item( i )->data( Qt::UserRole ) == value ||
193 ( mModel->item( i )->data( Qt::UserRole ).canConvert< QgsProcessingModelChildParameterSource >() &&
194 value.canConvert< QgsProcessingModelChildParameterSource >() &&
195 mModel->item( i )->data( Qt::UserRole ).value< QgsProcessingModelChildParameterSource >() ==
196 value.value< QgsProcessingModelChildParameterSource >() )
199 if ( updateExistingTitle )
200 mModel->item( i )->setText( title );
205 std::unique_ptr< QStandardItem > item = std::make_unique< QStandardItem >( title );
206 item->setData( value, Qt::UserRole );
207 item->setCheckState( selected ? Qt::Checked : Qt::Unchecked );
208 item->setCheckable(
true );
209 item->setDropEnabled(
false );
210 mModel->appendRow( item.release() );
219 QgsProcessingMultipleSelectionDialog::QgsProcessingMultipleSelectionDialog(
const QVariantList &availableOptions,
const QVariantList &selectedOptions, QWidget *parent, Qt::WindowFlags flags )
220 : QDialog( parent, flags )
222 setWindowTitle( tr(
"Multiple Selection" ) );
223 QVBoxLayout *vLayout =
new QVBoxLayout();
224 mWidget =
new QgsProcessingMultipleSelectionPanelWidget( availableOptions, selectedOptions );
225 vLayout->addWidget( mWidget );
226 mWidget->buttonBox()->addButton( QDialogButtonBox::Cancel );
227 connect( mWidget->buttonBox(), &QDialogButtonBox::accepted,
this, &QDialog::accept );
228 connect( mWidget->buttonBox(), &QDialogButtonBox::rejected,
this, &QDialog::reject );
229 setLayout( vLayout );
232 void QgsProcessingMultipleSelectionDialog::setValueFormatter(
const std::function<QString(
const QVariant & )> &
formatter )
237 QVariantList QgsProcessingMultipleSelectionDialog::selectedOptions()
const
239 return mWidget->selectedOptions();
248 const QList<QgsProcessingModelChildParameterSource> &modelSources,
249 QgsProcessingModelAlgorithm *model, QWidget *parent )
250 : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), selectedOptions, parent )
251 , mParameter( parameter )
253 QPushButton *addFileButton =
new QPushButton( tr(
"Add File(s)…" ) );
254 connect( addFileButton, &QPushButton::clicked,
this, &QgsProcessingMultipleInputPanelWidget::addFiles );
255 buttonBox()->addButton( addFileButton, QDialogButtonBox::ActionRole );
257 QPushButton *addDirButton =
new QPushButton( tr(
"Add Directory…" ) );
258 connect( addDirButton, &QPushButton::clicked,
this, &QgsProcessingMultipleInputPanelWidget::addDirectory );
259 buttonBox()->addButton( addDirButton, QDialogButtonBox::ActionRole );
261 for (
const QgsProcessingModelChildParameterSource &source : modelSources )
263 addOption( QVariant::fromValue( source ), source.friendlyIdentifier( model ),
false,
true );
267 void QgsProcessingMultipleInputPanelWidget::setProject(
QgsProject *project )
270 populateFromProject( project );
273 void QgsProcessingMultipleInputPanelWidget::addFiles()
275 QgsSettings settings;
276 QString path = settings.value( QStringLiteral(
"/Processing/LastInputPath" ), QDir::homePath() ).toString();
280 filter = generator->createFileFilter();
282 filter = QObject::tr(
"All files (*.*)" );
284 const QStringList filenames = QFileDialog::getOpenFileNames(
this, tr(
"Select File(s)" ), path, filter );
285 if ( filenames.empty() )
288 settings.setValue( QStringLiteral(
"/Processing/LastInputPath" ), QFileInfo( filenames.at( 0 ) ).path() );
290 for (
const QString &file : filenames )
292 addOption( file, file,
true );
295 emit selectionChanged();
298 void QgsProcessingMultipleInputPanelWidget::addDirectory()
300 QgsSettings settings;
301 QString path = settings.value( QStringLiteral(
"/Processing/LastInputPath" ), QDir::homePath() ).toString();
303 const QString dir = QFileDialog::getExistingDirectory(
this, tr(
"Select Directory" ), path );
307 settings.setValue( QStringLiteral(
"/Processing/LastInputPath" ), dir );
309 QStringList nameFilters;
313 for (
const QString &extension : extensions )
315 nameFilters << QStringLiteral(
"*.%1" ).arg( extension );
316 nameFilters << QStringLiteral(
"*.%1" ).arg( extension.toUpper() );
317 nameFilters << QStringLiteral(
"*.%1" ).arg( extension.toLower() );
321 QDirIterator it( path, nameFilters, QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories );
323 while ( it.hasNext() )
325 const QString fullPath = it.next();
326 addOption( fullPath, fullPath,
true );
328 emit selectionChanged();
331 void QgsProcessingMultipleInputPanelWidget::populateFromProject(
QgsProject *project )
335 for (
int i = 0; i < mModel->rowCount(); ++i )
337 const QStandardItem *item = mModel->item( i );
338 if ( item->data( Qt::UserRole ) == layerId )
340 bool isChecked = ( item->checkState() == Qt::Checked );
341 mModel->removeRow( i );
344 emit selectionChanged();
351 QgsSettings settings;
354 const QString authid = layer->crs().authid();
356 if ( settings.value( QStringLiteral(
"Processing/Configuration/SHOW_CRS_DEF" ),
true ).toBool() && !authid.isEmpty() )
357 title = QStringLiteral(
"%1 [%2]" ).arg( layer->name(), authid );
359 title = layer->name();
362 QString
id = layer->id();
363 for (
int i = 0; i < mModel->rowCount(); ++i )
366 if ( mModel->item( i )->data( Qt::UserRole ) == layer->id() )
371 else if ( mModel->item( i )->data( Qt::UserRole ) == layer->source() )
373 id = layer->source();
378 addOption(
id, title,
false,
true );
381 switch ( mParameter->layerType() )
459 const QList< QgsProcessingModelChildParameterSource > &modelSources, QgsProcessingModelAlgorithm *model, QWidget *parent, Qt::WindowFlags flags )
460 : QDialog( parent, flags )
462 setWindowTitle( tr(
"Multiple Selection" ) );
463 QVBoxLayout *vLayout =
new QVBoxLayout();
464 mWidget =
new QgsProcessingMultipleInputPanelWidget( parameter, selectedOptions, modelSources, model );
465 vLayout->addWidget( mWidget );
466 mWidget->buttonBox()->addButton( QDialogButtonBox::Cancel );
467 connect( mWidget->buttonBox(), &QDialogButtonBox::accepted,
this, &QDialog::accept );
468 connect( mWidget->buttonBox(), &QDialogButtonBox::rejected,
this, &QDialog::reject );
469 setLayout( vLayout );
472 QVariantList QgsProcessingMultipleInputDialog::selectedOptions()
const
474 return mWidget->selectedOptions();
477 void QgsProcessingMultipleInputDialog::setProject(
QgsProject *project )
479 mWidget->setProject( project );
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...
Base class for all map layer types.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
A parameter for processing algorithms which accepts multiple map layers.
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< 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< QgsMeshLayer * > compatibleMeshLayers(QgsProject *project, bool sort=true)
Returns a list of mesh layers from a project which are compatible with the processing framework.
@ TypeVectorLine
Vector line layers.
@ TypeMapLayer
Any map layer type (raster or vector or mesh)
@ TypeVectorPolygon
Vector polygon layers.
@ TypeFile
Files (i.e. non map layer sources, such as text files)
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
@ TypeRaster
Raster layers.
@ TypeVectorPoint
Vector point layers.
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
void layerRemoved(const QString &layerId)
Emitted after a layer was removed from the registry.
Represents a raster layer.
Represents a vector layer which manages a vector based data sets.