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.