29#include <QStandardItemModel> 
   30#include <QStandardItem> 
   35#include <QDirIterator> 
   37#include <QDragEnterEvent> 
   41QgsProcessingMultipleSelectionPanelWidget::QgsProcessingMultipleSelectionPanelWidget( 
const QVariantList &availableOptions,
 
   42    const QVariantList &selectedOptions,
 
   45  , mValueFormatter( []( const QVariant & v )->QString
 
   47  if ( v.userType() == QMetaType::type( 
"QgsProcessingModelChildParameterSource" ) )
 
   48    return v.value< QgsProcessingModelChildParameterSource >().staticValue().toString();
 
   57  mSelectionList->setSelectionBehavior( QAbstractItemView::SelectRows );
 
   58  mSelectionList->setSelectionMode( QAbstractItemView::ExtendedSelection );
 
   59  mSelectionList->setDragDropMode( QAbstractItemView::InternalMove );
 
   61  mButtonSelectAll = 
new QPushButton( tr( 
"Select All" ) );
 
   62  mButtonBox->addButton( mButtonSelectAll, QDialogButtonBox::ActionRole );
 
   64  mButtonClearSelection = 
new QPushButton( tr( 
"Clear Selection" ) );
 
   65  mButtonBox->addButton( mButtonClearSelection, QDialogButtonBox::ActionRole );
 
   67  mButtonToggleSelection = 
new QPushButton( tr( 
"Toggle Selection" ) );
 
   68  mButtonBox->addButton( mButtonToggleSelection, QDialogButtonBox::ActionRole );
 
   70  connect( mButtonSelectAll, &QPushButton::clicked, 
this, [ = ] { selectAll( 
true ); } );
 
   71  connect( mButtonClearSelection, &QPushButton::clicked, 
this, [ = ] { selectAll( 
false ); } );
 
   72  connect( mButtonToggleSelection, &QPushButton::clicked, 
this, &QgsProcessingMultipleSelectionPanelWidget::toggleSelection );
 
   74  connect( mButtonBox, &QDialogButtonBox::accepted, 
this, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked );
 
   75  populateList( availableOptions, selectedOptions );
 
   77  connect( mModel, &QStandardItemModel::itemChanged, 
this, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged );
 
   81  connect( mModel, &QStandardItemModel::rowsRemoved, 
this, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged );
 
   84void QgsProcessingMultipleSelectionPanelWidget::setValueFormatter( 
const std::function<QString( 
const QVariant & )> &
formatter )
 
   88  for ( 
int i = 0; i < mModel->rowCount(); ++i )
 
   90    mModel->item( i )->setText( mValueFormatter( mModel->item( i )->data( Qt::UserRole ) ) );
 
   94QVariantList QgsProcessingMultipleSelectionPanelWidget::selectedOptions()
 const 
   97  options.reserve( mModel->rowCount() );
 
   98  bool hasModelSources = 
false;
 
   99  for ( 
int i = 0; i < mModel->rowCount(); ++i )
 
  101    QStandardItem *item = mModel->item( i );
 
  107    if ( item->checkState() == Qt::Checked )
 
  109      const QVariant option = item->data( Qt::UserRole );
 
  111      if ( option.userType() == QMetaType::type( 
"QgsProcessingModelChildParameterSource" ) )
 
  112        hasModelSources = 
true;
 
  118  if ( hasModelSources )
 
  121    QVariantList originalOptions = options;
 
  123    for ( 
const QVariant &option : originalOptions )
 
  125      if ( option.userType() == QMetaType::type( 
"QgsProcessingModelChildParameterSource" ) )
 
  128        options << QVariant::fromValue( QgsProcessingModelChildParameterSource::fromStaticValue( option ) );
 
  136void QgsProcessingMultipleSelectionPanelWidget::selectAll( 
const bool checked )
 
  138  const QList<QStandardItem *> items = currentItems();
 
  139  for ( QStandardItem *item : items )
 
  141    item->setCheckState( checked ? Qt::Checked : Qt::Unchecked );
 
  145void QgsProcessingMultipleSelectionPanelWidget::toggleSelection()
 
  147  const QList<QStandardItem *> items = currentItems();
 
  148  for ( QStandardItem *item : items )
 
  150    item->setCheckState( item->checkState() == Qt::Unchecked ? Qt::Checked : Qt::Unchecked );
 
  154QList<QStandardItem *> QgsProcessingMultipleSelectionPanelWidget::currentItems()
 
  156  QList<QStandardItem *> items;
 
  157  const QModelIndexList selection = mSelectionList->selectionModel()->selectedIndexes();
 
  158  if ( selection.size() > 1 )
 
  160    items.reserve( selection.size() );
 
  161    for ( 
const QModelIndex &index : selection )
 
  163      items << mModel->itemFromIndex( index );
 
  168    items.reserve( mModel->rowCount() );
 
  169    for ( 
int i = 0; i < mModel->rowCount(); ++i )
 
  171      items << mModel->item( i );
 
  177void QgsProcessingMultipleSelectionPanelWidget::populateList( 
const QVariantList &availableOptions, 
const QVariantList &selectedOptions )
 
  179  mModel = 
new QStandardItemModel( 
this );
 
  181  QVariantList remainingOptions = availableOptions;
 
  184  for ( 
const QVariant &option : selectedOptions )
 
  190    addOption( option, mValueFormatter( option ), 
true );
 
  191    remainingOptions.removeAll( option );
 
  194  for ( 
const QVariant &option : std::as_const( remainingOptions ) )
 
  196    addOption( option, mValueFormatter( option ), 
false );
 
  199  mSelectionList->setModel( mModel );
 
  202QList< int> QgsProcessingMultipleSelectionPanelWidget::existingMapLayerFromMimeData( 
const QMimeData *data )
 const 
  211      for ( 
int i = 0; i < mModel->rowCount(); ++i )
 
  214        QString userRole = mModel->item( i )->data( Qt::UserRole ).toString();
 
  215        if ( userRole == layer->id() || userRole == layer->source() )
 
  225void QgsProcessingMultipleSelectionPanelWidget::dragEnterEvent( QDragEnterEvent *event )
 
  227  if ( !( event->possibleActions() & Qt::CopyAction ) )
 
  230  const QList< int> indexes = existingMapLayerFromMimeData( event->mimeData() );
 
  231  if ( !indexes.isEmpty() )
 
  234    event->setDropAction( Qt::CopyAction );
 
  239void QgsProcessingMultipleSelectionPanelWidget::dropEvent( QDropEvent *event )
 
  241  if ( !( event->possibleActions() & Qt::CopyAction ) )
 
  244  const QList< int> indexes = existingMapLayerFromMimeData( event->mimeData() );
 
  245  if ( !indexes.isEmpty() )
 
  248    setFocus( Qt::MouseFocusReason );
 
  249    event->setDropAction( Qt::CopyAction );
 
  252    for ( 
const int i : indexes )
 
  254      mModel->item( i )->setCheckState( Qt::Checked );
 
  256    emit selectionChanged();
 
  260void QgsProcessingMultipleSelectionPanelWidget::addOption( 
const QVariant &value, 
const QString &title, 
bool selected, 
bool updateExistingTitle )
 
  263  for ( 
int i = 0; i < mModel->rowCount(); ++i )
 
  265    if ( mModel->item( i )->data( Qt::UserRole ) == value ||
 
  266         ( mModel->item( i )->data( Qt::UserRole ).userType() == QMetaType::type( 
"QgsProcessingModelChildParameterSource" ) &&
 
  267           value.userType() == QMetaType::type( 
"QgsProcessingModelChildParameterSource" ) &&
 
  268           mModel->item( i )->data( Qt::UserRole ).value< QgsProcessingModelChildParameterSource >() ==
 
  269           value.value< QgsProcessingModelChildParameterSource >() )
 
  272      if ( updateExistingTitle )
 
  273        mModel->item( i )->setText( title );
 
  278  std::unique_ptr< QStandardItem > item = std::make_unique< QStandardItem >( title );
 
  279  item->setData( value, Qt::UserRole );
 
  280  item->setCheckState( selected ? Qt::Checked : Qt::Unchecked );
 
  281  item->setCheckable( 
true );
 
  282  item->setDropEnabled( 
false );
 
  283  mModel->appendRow( item.release() );
 
  292QgsProcessingMultipleSelectionDialog::QgsProcessingMultipleSelectionDialog( 
const QVariantList &availableOptions, 
const QVariantList &selectedOptions, QWidget *parent, Qt::WindowFlags flags )
 
  293  : QDialog( parent, flags )
 
  295  setWindowTitle( tr( 
"Multiple Selection" ) );
 
  296  QVBoxLayout *vLayout = 
new QVBoxLayout();
 
  297  mWidget = 
new QgsProcessingMultipleSelectionPanelWidget( availableOptions, selectedOptions );
 
  298  vLayout->addWidget( mWidget );
 
  299  mWidget->buttonBox()->addButton( QDialogButtonBox::Cancel );
 
  300  connect( mWidget->buttonBox(), &QDialogButtonBox::accepted, 
this, &QDialog::accept );
 
  301  connect( mWidget->buttonBox(), &QDialogButtonBox::rejected, 
this, &QDialog::reject );
 
  302  setLayout( vLayout );
 
  305void QgsProcessingMultipleSelectionDialog::setValueFormatter( 
const std::function<QString( 
const QVariant & )> &
formatter )
 
  310QVariantList QgsProcessingMultipleSelectionDialog::selectedOptions()
 const 
  312  return mWidget->selectedOptions();
 
  321    const QList<QgsProcessingModelChildParameterSource> &modelSources,
 
  322    QgsProcessingModelAlgorithm *model, QWidget *parent )
 
  323  : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), selectedOptions, parent )
 
  324  , mParameter( parameter )
 
  326  QPushButton *addFileButton = 
new QPushButton( tr( 
"Add File(s)…" ) );
 
  327  connect( addFileButton, &QPushButton::clicked, 
this, &QgsProcessingMultipleInputPanelWidget::addFiles );
 
  328  buttonBox()->addButton( addFileButton, QDialogButtonBox::ActionRole );
 
  330  QPushButton *addDirButton = 
new QPushButton( tr( 
"Add Directory…" ) );
 
  331  connect( addDirButton, &QPushButton::clicked, 
this, &QgsProcessingMultipleInputPanelWidget::addDirectory );
 
  332  buttonBox()->addButton( addDirButton, QDialogButtonBox::ActionRole );
 
  333  setAcceptDrops( 
true );
 
  334  for ( 
const QgsProcessingModelChildParameterSource &source : modelSources )
 
  336    addOption( QVariant::fromValue( source ), source.friendlyIdentifier( model ), 
false, 
true );
 
  340void QgsProcessingMultipleInputPanelWidget::setProject( 
QgsProject *project )
 
  343    populateFromProject( project );
 
  346void QgsProcessingMultipleInputPanelWidget::addFiles()
 
  349  QString path = settings.
value( QStringLiteral( 
"/Processing/LastInputPath" ), QDir::homePath() ).toString();
 
  353    filter = generator->createFileFilter();
 
  355    filter = QObject::tr( 
"All files (*.*)" );
 
  357  const QStringList filenames = QFileDialog::getOpenFileNames( 
this, tr( 
"Select File(s)" ), path, filter );
 
  358  if ( filenames.empty() )
 
  361  settings.
setValue( QStringLiteral( 
"/Processing/LastInputPath" ), QFileInfo( filenames.at( 0 ) ).path() );
 
  363  for ( 
const QString &file : filenames )
 
  365    addOption( file, file, 
true );
 
  368  emit selectionChanged();
 
  371void QgsProcessingMultipleInputPanelWidget::addDirectory()
 
  374  const QString path = settings.
value( QStringLiteral( 
"/Processing/LastInputPath" ), QDir::homePath() ).toString();
 
  376  const QString dir = QFileDialog::getExistingDirectory( 
this, tr( 
"Select Directory" ), path );
 
  380  settings.
setValue( QStringLiteral( 
"/Processing/LastInputPath" ), dir );
 
  382  QStringList nameFilters;
 
  386    for ( 
const QString &extension : extensions )
 
  388      nameFilters << QStringLiteral( 
"*.%1" ).arg( extension );
 
  389      nameFilters << QStringLiteral( 
"*.%1" ).arg( extension.toUpper() );
 
  390      nameFilters << QStringLiteral( 
"*.%1" ).arg( extension.toLower() );
 
  394  QDirIterator it( dir, nameFilters, QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories );
 
  395  while ( it.hasNext() )
 
  397    const QString fullPath = it.next();
 
  398    if ( fullPath.endsWith( QLatin1String( 
".dbf" ), Qt::CaseInsensitive ) )
 
  400      if ( QFileInfo::exists( QStringLiteral( 
"%1.shp" ).arg( fullPath.chopped( 4 ) ) ) ||
 
  401           QFileInfo::exists( QStringLiteral( 
"%1.SHP" ).arg( fullPath.chopped( 4 ) ) ) )
 
  407    else if ( fullPath.endsWith( QLatin1String( 
".aux.xml" ), Qt::CaseInsensitive ) ||
 
  408              fullPath.endsWith( QLatin1String( 
".shp.xml" ), Qt::CaseInsensitive ) )
 
  413    addOption( fullPath, fullPath, 
true );
 
  415  emit selectionChanged();
 
  418QList< int> QgsProcessingMultipleInputPanelWidget::existingMapLayerFromMimeData( 
const QMimeData *data )
 const 
  427      for ( 
int i = 0; i < mModel->rowCount(); ++i )
 
  430        const QString userRole = mModel->item( i )->data( Qt::UserRole ).toString();
 
  431        if ( userRole == layer->id() || userRole == layer->source() )
 
  441void QgsProcessingMultipleInputPanelWidget::dragEnterEvent( QDragEnterEvent *event )
 
  443  if ( !( event->possibleActions() & Qt::CopyAction ) )
 
  446  const QList< int> indexes = existingMapLayerFromMimeData( event->mimeData() );
 
  447  if ( !indexes.isEmpty() )
 
  450    event->setDropAction( Qt::CopyAction );
 
  455void QgsProcessingMultipleInputPanelWidget::dropEvent( QDropEvent *event )
 
  457  if ( !( event->possibleActions() & Qt::CopyAction ) )
 
  460  const QList< int> indexes = existingMapLayerFromMimeData( event->mimeData() );
 
  461  if ( !indexes.isEmpty() )
 
  464    setFocus( Qt::MouseFocusReason );
 
  465    event->setDropAction( Qt::CopyAction );
 
  468    for ( 
const int i : indexes )
 
  470      mModel->item( i )->setCheckState( Qt::Checked );
 
  472    emit selectionChanged();
 
  476void QgsProcessingMultipleInputPanelWidget::populateFromProject( 
QgsProject *project )
 
  480    for ( 
int i = 0; i < mModel->rowCount(); ++i )
 
  482      const QStandardItem *item = mModel->item( i );
 
  483      if ( item->data( Qt::UserRole ) == layerId )
 
  485        bool isChecked = ( item->checkState() == Qt::Checked );
 
  486        mModel->removeRow( i );
 
  489          emit selectionChanged();
 
  499    const QString authid = layer->crs().authid();
 
  501    if ( settings.value( QStringLiteral( 
"Processing/Configuration/SHOW_CRS_DEF" ), 
true ).toBool() && !authid.isEmpty() )
 
  502      title = QStringLiteral( 
"%1 [%2]" ).arg( layer->name(), authid );
 
  504      title = layer->name();
 
  507    QString 
id = layer->id();
 
  509      id = QStringLiteral( 
"main" );
 
  511    for ( 
int i = 0; i < mModel->rowCount(); ++i )
 
  514      if ( mModel->item( i )->data( Qt::UserRole ) == layer->id() )
 
  519      else if ( mModel->item( i )->data( Qt::UserRole ) == layer->source() )
 
  521        id = layer->source();
 
  526    addOption( 
id, title, 
false, 
true );
 
  529  switch ( mParameter->layerType() )
 
  666    const QList< QgsProcessingModelChildParameterSource > &modelSources, QgsProcessingModelAlgorithm *model, QWidget *parent, Qt::WindowFlags flags )
 
  667  : QDialog( parent, flags )
 
  669  setWindowTitle( tr( 
"Multiple Selection" ) );
 
  670  QVBoxLayout *vLayout = 
new QVBoxLayout();
 
  671  mWidget = 
new QgsProcessingMultipleInputPanelWidget( parameter, selectedOptions, modelSources, model );
 
  672  vLayout->addWidget( mWidget );
 
  673  mWidget->buttonBox()->addButton( QDialogButtonBox::Cancel );
 
  674  connect( mWidget->buttonBox(), &QDialogButtonBox::accepted, 
this, &QDialog::accept );
 
  675  connect( mWidget->buttonBox(), &QDialogButtonBox::rejected, 
this, &QDialog::reject );
 
  676  setLayout( vLayout );
 
  677  setAcceptDrops( 
true );
 
  680QVariantList QgsProcessingMultipleInputDialog::selectedOptions()
 const 
  682  return mWidget->selectedOptions();
 
  685void QgsProcessingMultipleInputDialog::setProject( 
QgsProject *project )
 
  687  mWidget->setProject( project );
 
@ 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.
 
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...
 
Base class for all map layer types.
 
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 plugin layers.
 
Represents a map layer supporting display of point clouds.
 
A parameter for processing algorithms which accepts multiple map layers.
 
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 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,...
 
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:
 
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.