23 #include "processing/models/qgsprocessingmodelchildparametersource.h"
24 #include <QStandardItemModel>
25 #include <QStandardItem>
26 #include <QPushButton>
28 #include <QToolButton>
29 #include <QFileDialog>
33 QgsProcessingMultipleSelectionPanelWidget::QgsProcessingMultipleSelectionPanelWidget(
const QVariantList &availableOptions,
34 const QVariantList &selectedOptions,
37 , mValueFormatter( []( const QVariant & v )->QString
39 if ( v.canConvert< QgsProcessingModelChildParameterSource >() )
40 return v.value< QgsProcessingModelChildParameterSource >().staticValue().toString();
49 mSelectionList->setSelectionBehavior( QAbstractItemView::SelectRows );
50 mSelectionList->setSelectionMode( QAbstractItemView::ExtendedSelection );
51 mSelectionList->setDragDropMode( QAbstractItemView::InternalMove );
53 mButtonSelectAll =
new QPushButton( tr(
"Select All" ) );
54 mButtonBox->addButton( mButtonSelectAll, QDialogButtonBox::ActionRole );
56 mButtonClearSelection =
new QPushButton( tr(
"Clear Selection" ) );
57 mButtonBox->addButton( mButtonClearSelection, QDialogButtonBox::ActionRole );
59 mButtonToggleSelection =
new QPushButton( tr(
"Toggle Selection" ) );
60 mButtonBox->addButton( mButtonToggleSelection, QDialogButtonBox::ActionRole );
62 connect( mButtonSelectAll, &QPushButton::clicked,
this, [ = ] { selectAll(
true ); } );
63 connect( mButtonClearSelection, &QPushButton::clicked,
this, [ = ] { selectAll(
false ); } );
64 connect( mButtonToggleSelection, &QPushButton::clicked,
this, &QgsProcessingMultipleSelectionPanelWidget::toggleSelection );
66 connect( mButtonBox, &QDialogButtonBox::accepted,
this, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked );
67 populateList( availableOptions, selectedOptions );
69 connect( mModel, &QStandardItemModel::itemChanged,
this, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged );
72 void QgsProcessingMultipleSelectionPanelWidget::setValueFormatter(
const std::function<QString(
const QVariant & )> &
formatter )
76 for (
int i = 0; i < mModel->rowCount(); ++i )
78 mModel->item( i )->setText( mValueFormatter( mModel->item( i )->data( Qt::UserRole ) ) );
82 QVariantList QgsProcessingMultipleSelectionPanelWidget::selectedOptions()
const
85 options.reserve( mModel->rowCount() );
86 bool hasModelSources =
false;
87 for (
int i = 0; i < mModel->rowCount(); ++i )
89 if ( mModel->item( i )->checkState() == Qt::Checked )
91 const QVariant option = mModel->item( i )->data( Qt::UserRole );
93 if ( option.canConvert< QgsProcessingModelChildParameterSource >() )
94 hasModelSources =
true;
100 if ( hasModelSources )
103 QVariantList originalOptions = options;
105 for (
const QVariant &option : originalOptions )
107 if ( option.canConvert< QgsProcessingModelChildParameterSource >() )
110 options << QVariant::fromValue( QgsProcessingModelChildParameterSource::fromStaticValue( option ) );
118 void QgsProcessingMultipleSelectionPanelWidget::selectAll(
const bool checked )
120 const QList<QStandardItem *> items = currentItems();
121 for ( QStandardItem *item : items )
123 item->setCheckState( checked ? Qt::Checked : Qt::Unchecked );
127 void QgsProcessingMultipleSelectionPanelWidget::toggleSelection()
129 const QList<QStandardItem *> items = currentItems();
130 for ( QStandardItem *item : items )
132 item->setCheckState( item->checkState() == Qt::Unchecked ? Qt::Checked : Qt::Unchecked );
136 QList<QStandardItem *> QgsProcessingMultipleSelectionPanelWidget::currentItems()
138 QList<QStandardItem *> items;
139 const QModelIndexList selection = mSelectionList->selectionModel()->selectedIndexes();
140 if ( selection.size() > 1 )
142 items.reserve( selection.size() );
143 for (
const QModelIndex &index : selection )
145 items << mModel->itemFromIndex( index );
150 items.reserve( mModel->rowCount() );
151 for (
int i = 0; i < mModel->rowCount(); ++i )
153 items << mModel->item( i );
159 void QgsProcessingMultipleSelectionPanelWidget::populateList(
const QVariantList &availableOptions,
const QVariantList &selectedOptions )
161 mModel =
new QStandardItemModel(
this );
163 QVariantList remainingOptions = availableOptions;
166 for (
const QVariant &option : selectedOptions )
172 addOption( option, mValueFormatter( option ),
true );
173 remainingOptions.removeAll( option );
176 for (
const QVariant &option : qgis::as_const( remainingOptions ) )
178 addOption( option, mValueFormatter( option ),
false );
181 mSelectionList->setModel( mModel );
185 void QgsProcessingMultipleSelectionPanelWidget::addOption(
const QVariant &value,
const QString &title,
bool selected,
bool updateExistingTitle )
188 for (
int i = 0; i < mModel->rowCount(); ++i )
190 if ( mModel->item( i )->data( Qt::UserRole ) == value ||
191 ( mModel->item( i )->data( Qt::UserRole ).canConvert< QgsProcessingModelChildParameterSource >() &&
192 value.canConvert< QgsProcessingModelChildParameterSource >() &&
193 mModel->item( i )->data( Qt::UserRole ).value< QgsProcessingModelChildParameterSource >() ==
194 value.value< QgsProcessingModelChildParameterSource >() )
197 if ( updateExistingTitle )
198 mModel->item( i )->setText( title );
203 std::unique_ptr< QStandardItem > item = qgis::make_unique< QStandardItem >( title );
204 item->setData( value, Qt::UserRole );
205 item->setCheckState( selected ? Qt::Checked : Qt::Unchecked );
206 item->setCheckable(
true );
207 item->setDropEnabled(
false );
208 mModel->appendRow( item.release() );
217 QgsProcessingMultipleSelectionDialog::QgsProcessingMultipleSelectionDialog(
const QVariantList &availableOptions,
const QVariantList &selectedOptions, QWidget *parent, Qt::WindowFlags flags )
218 : QDialog( parent, flags )
220 setWindowTitle( tr(
"Multiple Selection" ) );
221 QVBoxLayout *vLayout =
new QVBoxLayout();
222 mWidget =
new QgsProcessingMultipleSelectionPanelWidget( availableOptions, selectedOptions );
223 vLayout->addWidget( mWidget );
224 mWidget->buttonBox()->addButton( QDialogButtonBox::Cancel );
225 connect( mWidget->buttonBox(), &QDialogButtonBox::accepted,
this, &QDialog::accept );
226 connect( mWidget->buttonBox(), &QDialogButtonBox::rejected,
this, &QDialog::reject );
227 setLayout( vLayout );
230 void QgsProcessingMultipleSelectionDialog::setValueFormatter(
const std::function<QString(
const QVariant & )> &
formatter )
235 QVariantList QgsProcessingMultipleSelectionDialog::selectedOptions()
const
237 return mWidget->selectedOptions();
246 const QList<QgsProcessingModelChildParameterSource> &modelSources,
247 QgsProcessingModelAlgorithm *model, QWidget *parent )
248 : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), selectedOptions, parent )
249 , mParameter( parameter )
251 QPushButton *addFileButton =
new QPushButton( tr(
"Add File(s)…" ) );
252 connect( addFileButton, &QPushButton::clicked,
this, &QgsProcessingMultipleInputPanelWidget::addFiles );
253 buttonBox()->addButton( addFileButton, QDialogButtonBox::ActionRole );
255 QPushButton *addDirButton =
new QPushButton( tr(
"Add Directory…" ) );
256 connect( addDirButton, &QPushButton::clicked,
this, &QgsProcessingMultipleInputPanelWidget::addDirectory );
257 buttonBox()->addButton( addDirButton, QDialogButtonBox::ActionRole );
259 for (
const QgsProcessingModelChildParameterSource &source : modelSources )
261 addOption( QVariant::fromValue( source ), source.friendlyIdentifier( model ),
false,
true );
265 void QgsProcessingMultipleInputPanelWidget::setProject(
QgsProject *project )
268 populateFromProject( project );
271 void QgsProcessingMultipleInputPanelWidget::addFiles()
274 QString path = settings.
value( QStringLiteral(
"/Processing/LastInputPath" ), QDir::homePath() ).toString();
278 filter = generator->createFileFilter();
280 filter = QObject::tr(
"All files (*.*)" );
282 const QStringList filenames = QFileDialog::getOpenFileNames(
this, tr(
"Select File(s)" ), path, filter );
283 if ( filenames.empty() )
286 settings.
setValue( QStringLiteral(
"/Processing/LastInputPath" ), QFileInfo( filenames.at( 0 ) ).path() );
288 for (
const QString &file : filenames )
290 addOption( file, file,
true );
293 emit selectionChanged();
296 void QgsProcessingMultipleInputPanelWidget::addDirectory()
299 QString path = settings.
value( QStringLiteral(
"/Processing/LastInputPath" ), QDir::homePath() ).toString();
301 const QString dir = QFileDialog::getExistingDirectory(
this, tr(
"Select Directory" ), path );
305 settings.
setValue( QStringLiteral(
"/Processing/LastInputPath" ), dir );
307 QStringList nameFilters;
311 for (
const QString &extension : extensions )
313 nameFilters << QStringLiteral(
"*.%1" ).arg( extension );
314 nameFilters << QStringLiteral(
"*.%1" ).arg( extension.toUpper() );
315 nameFilters << QStringLiteral(
"*.%1" ).arg( extension.toLower() );
319 QDirIterator it( path, nameFilters, QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories );
321 while ( it.hasNext() )
323 const QString fullPath = it.next();
324 addOption( fullPath, fullPath,
true );
326 emit selectionChanged();
329 void QgsProcessingMultipleInputPanelWidget::populateFromProject(
QgsProject *project )
334 const QString authid = layer->crs().authid();
336 if ( settings.
value( QStringLiteral(
"Processing/Configuration/SHOW_CRS_DEF" ),
true ).toBool() && !authid.isEmpty() )
337 title = QStringLiteral(
"%1 [%2]" ).arg( layer->name(), authid );
339 title = layer->name();
342 QString
id = layer->id();
343 for (
int i = 0; i < mModel->rowCount(); ++i )
346 if ( mModel->item( i )->data( Qt::UserRole ) == layer->id() )
351 else if ( mModel->item( i )->data( Qt::UserRole ) == layer->source() )
353 id = layer->source();
358 addOption(
id, title,
false,
true );
361 switch ( mParameter->layerType() )
439 const QList< QgsProcessingModelChildParameterSource > &modelSources, QgsProcessingModelAlgorithm *model, QWidget *parent, Qt::WindowFlags flags )
440 : QDialog( parent, flags )
442 setWindowTitle( tr(
"Multiple Selection" ) );
443 QVBoxLayout *vLayout =
new QVBoxLayout();
444 mWidget =
new QgsProcessingMultipleInputPanelWidget( parameter, selectedOptions, modelSources, model );
445 vLayout->addWidget( mWidget );
446 mWidget->buttonBox()->addButton( QDialogButtonBox::Cancel );
447 connect( mWidget->buttonBox(), &QDialogButtonBox::accepted,
this, &QDialog::accept );
448 connect( mWidget->buttonBox(), &QDialogButtonBox::rejected,
this, &QDialog::reject );
449 setLayout( vLayout );
452 QVariantList QgsProcessingMultipleInputDialog::selectedOptions()
const
454 return mWidget->selectedOptions();
457 void QgsProcessingMultipleInputDialog::setProject(
QgsProject *project )
459 mWidget->setProject( project );