28 #include <QStandardItemModel>
29 #include <QStandardItem>
30 #include <QPushButton>
32 #include <QToolButton>
33 #include <QFileDialog>
34 #include <QDirIterator>
38 QgsProcessingMultipleSelectionPanelWidget::QgsProcessingMultipleSelectionPanelWidget(
const QVariantList &availableOptions,
39 const QVariantList &selectedOptions,
42 , mValueFormatter( []( const QVariant & v )->QString
44 if ( v.canConvert< QgsProcessingModelChildParameterSource >() )
45 return v.value< QgsProcessingModelChildParameterSource >().staticValue().toString();
54 mSelectionList->setSelectionBehavior( QAbstractItemView::SelectRows );
55 mSelectionList->setSelectionMode( QAbstractItemView::ExtendedSelection );
56 mSelectionList->setDragDropMode( QAbstractItemView::InternalMove );
58 mButtonSelectAll =
new QPushButton( tr(
"Select All" ) );
59 mButtonBox->addButton( mButtonSelectAll, QDialogButtonBox::ActionRole );
61 mButtonClearSelection =
new QPushButton( tr(
"Clear Selection" ) );
62 mButtonBox->addButton( mButtonClearSelection, QDialogButtonBox::ActionRole );
64 mButtonToggleSelection =
new QPushButton( tr(
"Toggle Selection" ) );
65 mButtonBox->addButton( mButtonToggleSelection, QDialogButtonBox::ActionRole );
67 connect( mButtonSelectAll, &QPushButton::clicked,
this, [ = ] { selectAll(
true ); } );
68 connect( mButtonClearSelection, &QPushButton::clicked,
this, [ = ] { selectAll(
false ); } );
69 connect( mButtonToggleSelection, &QPushButton::clicked,
this, &QgsProcessingMultipleSelectionPanelWidget::toggleSelection );
71 connect( mButtonBox, &QDialogButtonBox::accepted,
this, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked );
72 populateList( availableOptions, selectedOptions );
74 connect( mModel, &QStandardItemModel::itemChanged,
this, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged );
78 connect( mModel, &QStandardItemModel::rowsRemoved,
this, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged );
81 void QgsProcessingMultipleSelectionPanelWidget::setValueFormatter(
const std::function<QString(
const QVariant & )> &
formatter )
85 for (
int i = 0; i < mModel->rowCount(); ++i )
87 mModel->item( i )->setText( mValueFormatter( mModel->item( i )->data( Qt::UserRole ) ) );
91 QVariantList QgsProcessingMultipleSelectionPanelWidget::selectedOptions()
const
94 options.reserve( mModel->rowCount() );
95 bool hasModelSources =
false;
96 for (
int i = 0; i < mModel->rowCount(); ++i )
98 QStandardItem *item = mModel->item( i );
104 if ( item->checkState() == Qt::Checked )
106 const QVariant option = item->data( Qt::UserRole );
108 if ( option.canConvert< QgsProcessingModelChildParameterSource >() )
109 hasModelSources =
true;
115 if ( hasModelSources )
118 QVariantList originalOptions = options;
120 for (
const QVariant &option : originalOptions )
122 if ( option.canConvert< QgsProcessingModelChildParameterSource >() )
125 options << QVariant::fromValue( QgsProcessingModelChildParameterSource::fromStaticValue( option ) );
133 void QgsProcessingMultipleSelectionPanelWidget::selectAll(
const bool checked )
135 const QList<QStandardItem *> items = currentItems();
136 for ( QStandardItem *item : items )
138 item->setCheckState( checked ? Qt::Checked : Qt::Unchecked );
142 void QgsProcessingMultipleSelectionPanelWidget::toggleSelection()
144 const QList<QStandardItem *> items = currentItems();
145 for ( QStandardItem *item : items )
147 item->setCheckState( item->checkState() == Qt::Unchecked ? Qt::Checked : Qt::Unchecked );
151 QList<QStandardItem *> QgsProcessingMultipleSelectionPanelWidget::currentItems()
153 QList<QStandardItem *> items;
154 const QModelIndexList selection = mSelectionList->selectionModel()->selectedIndexes();
155 if ( selection.size() > 1 )
157 items.reserve( selection.size() );
158 for (
const QModelIndex &index : selection )
160 items << mModel->itemFromIndex( index );
165 items.reserve( mModel->rowCount() );
166 for (
int i = 0; i < mModel->rowCount(); ++i )
168 items << mModel->item( i );
174 void QgsProcessingMultipleSelectionPanelWidget::populateList(
const QVariantList &availableOptions,
const QVariantList &selectedOptions )
176 mModel =
new QStandardItemModel(
this );
178 QVariantList remainingOptions = availableOptions;
181 for (
const QVariant &option : selectedOptions )
187 addOption( option, mValueFormatter( option ),
true );
188 remainingOptions.removeAll( option );
191 for (
const QVariant &option : std::as_const( remainingOptions ) )
193 addOption( option, mValueFormatter( option ),
false );
196 mSelectionList->setModel( mModel );
200 void QgsProcessingMultipleSelectionPanelWidget::addOption(
const QVariant &value,
const QString &title,
bool selected,
bool updateExistingTitle )
203 for (
int i = 0; i < mModel->rowCount(); ++i )
205 if ( mModel->item( i )->data( Qt::UserRole ) == value ||
206 ( mModel->item( i )->data( Qt::UserRole ).canConvert< QgsProcessingModelChildParameterSource >() &&
207 value.canConvert< QgsProcessingModelChildParameterSource >() &&
208 mModel->item( i )->data( Qt::UserRole ).value< QgsProcessingModelChildParameterSource >() ==
209 value.value< QgsProcessingModelChildParameterSource >() )
212 if ( updateExistingTitle )
213 mModel->item( i )->setText( title );
218 std::unique_ptr< QStandardItem > item = std::make_unique< QStandardItem >( title );
219 item->setData( value, Qt::UserRole );
220 item->setCheckState( selected ? Qt::Checked : Qt::Unchecked );
221 item->setCheckable(
true );
222 item->setDropEnabled(
false );
223 mModel->appendRow( item.release() );
232 QgsProcessingMultipleSelectionDialog::QgsProcessingMultipleSelectionDialog(
const QVariantList &availableOptions,
const QVariantList &selectedOptions, QWidget *parent, Qt::WindowFlags flags )
233 : QDialog( parent, flags )
235 setWindowTitle( tr(
"Multiple Selection" ) );
236 QVBoxLayout *vLayout =
new QVBoxLayout();
237 mWidget =
new QgsProcessingMultipleSelectionPanelWidget( availableOptions, selectedOptions );
238 vLayout->addWidget( mWidget );
239 mWidget->buttonBox()->addButton( QDialogButtonBox::Cancel );
240 connect( mWidget->buttonBox(), &QDialogButtonBox::accepted,
this, &QDialog::accept );
241 connect( mWidget->buttonBox(), &QDialogButtonBox::rejected,
this, &QDialog::reject );
242 setLayout( vLayout );
245 void QgsProcessingMultipleSelectionDialog::setValueFormatter(
const std::function<QString(
const QVariant & )> &
formatter )
250 QVariantList QgsProcessingMultipleSelectionDialog::selectedOptions()
const
252 return mWidget->selectedOptions();
261 const QList<QgsProcessingModelChildParameterSource> &modelSources,
262 QgsProcessingModelAlgorithm *model, QWidget *parent )
263 : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), selectedOptions, parent )
264 , mParameter( parameter )
266 QPushButton *addFileButton =
new QPushButton( tr(
"Add File(s)…" ) );
267 connect( addFileButton, &QPushButton::clicked,
this, &QgsProcessingMultipleInputPanelWidget::addFiles );
268 buttonBox()->addButton( addFileButton, QDialogButtonBox::ActionRole );
270 QPushButton *addDirButton =
new QPushButton( tr(
"Add Directory…" ) );
271 connect( addDirButton, &QPushButton::clicked,
this, &QgsProcessingMultipleInputPanelWidget::addDirectory );
272 buttonBox()->addButton( addDirButton, QDialogButtonBox::ActionRole );
274 for (
const QgsProcessingModelChildParameterSource &source : modelSources )
276 addOption( QVariant::fromValue( source ), source.friendlyIdentifier( model ),
false,
true );
280 void QgsProcessingMultipleInputPanelWidget::setProject(
QgsProject *project )
283 populateFromProject( project );
286 void QgsProcessingMultipleInputPanelWidget::addFiles()
289 QString path = settings.
value( QStringLiteral(
"/Processing/LastInputPath" ), QDir::homePath() ).toString();
293 filter = generator->createFileFilter();
295 filter = QObject::tr(
"All files (*.*)" );
297 const QStringList filenames = QFileDialog::getOpenFileNames(
this, tr(
"Select File(s)" ), path, filter );
298 if ( filenames.empty() )
301 settings.
setValue( QStringLiteral(
"/Processing/LastInputPath" ), QFileInfo( filenames.at( 0 ) ).path() );
303 for (
const QString &file : filenames )
305 addOption( file, file,
true );
308 emit selectionChanged();
311 void QgsProcessingMultipleInputPanelWidget::addDirectory()
314 QString path = settings.
value( QStringLiteral(
"/Processing/LastInputPath" ), QDir::homePath() ).toString();
316 const QString dir = QFileDialog::getExistingDirectory(
this, tr(
"Select Directory" ), path );
320 settings.
setValue( QStringLiteral(
"/Processing/LastInputPath" ), dir );
322 QStringList nameFilters;
326 for (
const QString &extension : extensions )
328 nameFilters << QStringLiteral(
"*.%1" ).arg( extension );
329 nameFilters << QStringLiteral(
"*.%1" ).arg( extension.toUpper() );
330 nameFilters << QStringLiteral(
"*.%1" ).arg( extension.toLower() );
334 QDirIterator it( path, nameFilters, QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories );
336 while ( it.hasNext() )
338 const QString fullPath = it.next();
339 addOption( fullPath, fullPath,
true );
341 emit selectionChanged();
344 void QgsProcessingMultipleInputPanelWidget::populateFromProject(
QgsProject *project )
348 for (
int i = 0; i < mModel->rowCount(); ++i )
350 const QStandardItem *item = mModel->item( i );
351 if ( item->data( Qt::UserRole ) == layerId )
353 bool isChecked = ( item->checkState() == Qt::Checked );
354 mModel->removeRow( i );
357 emit selectionChanged();
367 const QString authid = layer->crs().authid();
369 if ( settings.value( QStringLiteral(
"Processing/Configuration/SHOW_CRS_DEF" ),
true ).toBool() && !authid.isEmpty() )
370 title = QStringLiteral(
"%1 [%2]" ).arg( layer->name(), authid );
372 title = layer->name();
375 QString
id = layer->id();
377 id = QStringLiteral(
"main" );
379 for (
int i = 0; i < mModel->rowCount(); ++i )
382 if ( mModel->item( i )->data( Qt::UserRole ) == layer->id() )
387 else if ( mModel->item( i )->data( Qt::UserRole ) == layer->source() )
389 id = layer->source();
394 addOption(
id, title,
false,
true );
397 switch ( mParameter->layerType() )
523 const QList< QgsProcessingModelChildParameterSource > &modelSources, QgsProcessingModelAlgorithm *model, QWidget *parent, Qt::WindowFlags flags )
524 : QDialog( parent, flags )
526 setWindowTitle( tr(
"Multiple Selection" ) );
527 QVBoxLayout *vLayout =
new QVBoxLayout();
528 mWidget =
new QgsProcessingMultipleInputPanelWidget( parameter, selectedOptions, modelSources, model );
529 vLayout->addWidget( mWidget );
530 mWidget->buttonBox()->addButton( QDialogButtonBox::Cancel );
531 connect( mWidget->buttonBox(), &QDialogButtonBox::accepted,
this, &QDialog::accept );
532 connect( mWidget->buttonBox(), &QDialogButtonBox::rejected,
this, &QDialog::reject );
533 setLayout( vLayout );
536 QVariantList QgsProcessingMultipleInputDialog::selectedOptions()
const
538 return mWidget->selectedOptions();
541 void QgsProcessingMultipleInputDialog::setProject(
QgsProject *project )
543 mWidget->setProject( project );